On Tue, 2008-06-03 at 18:29 +1000, Nick Piggin wrote:
Yes, what is needed is a check that tells us if the page content is
still needed after the last mapper has gone. For anonymous pages the
check "!PageAnon(page) || PageSwapCache(page)" should do. The idea is
that on each path that replaces a valid pte with a swap pte the
PageSwapCache bit is set first, then page_remove_rmap is called. As far
as I can see this is true for the current code.
Yeah, but we don't really want to do that.
The current users of __SetPageUptodate are:
* do_wp_page
* do_anonymous_page
* do_fault for (flags & FAULT_FLAG_WRITE)
For these three cases the pte is created with pte_mkdirty. Clearing the
physical page dirty bit is pointless.
* hugetlb_cow
* hugetlb_no_page
The dirty bits are of no interest to hugetlbfs, no?
I think it is safe to remove the page_clear_dirty from __SetPageUptodate
New patch below.
--
blue skies,
Martin.
"Reality continues to ruin my life." - Calvin.
---
Subject: [PATCH] Optimize storage key operations for anon pages
From: Martin Schwidefsky <schwidefsky@de.ibm.com>
For anonymous pages without a swap cache backing the check for the physical
dirty bit in page_remove_rmap is unnecessary. The instruction that are used
to check and reset the dirty bit are expensive. Removing the check noticably
speeds up process exit. In addition the clearing of the dirty bit in
__SetPageUptodate is pointless as well. With these two changes there is
no storage key operation for an anonymous page anymore if it does not hit
the swap space.
The micro benchmark which repeatedly executes an empty shell script gets
about 5% faster.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---
diff -urpN linux-2.6/include/linux/page-flags.h linux-2.6-patched/include/linux/page-flags.h
--- linux-2.6/include/linux/page-flags.h 2008-06-03 09:46:50.000000000 +0200
+++ linux-2.6-patched/include/linux/page-flags.h 2008-06-03 11:37:27.000000000 +0200
@@ -217,9 +217,6 @@ static inline void __SetPageUptodate(str
{
smp_wmb();
__set_bit(PG_uptodate, &(page)->flags);
-#ifdef CONFIG_S390
- page_clear_dirty(page);
-#endif
}
static inline void SetPageUptodate(struct page *page)
diff -urpN linux-2.6/mm/rmap.c linux-2.6-patched/mm/rmap.c
--- linux-2.6/mm/rmap.c 2008-06-03 11:34:55.000000000 +0200
+++ linux-2.6-patched/mm/rmap.c 2008-06-03 11:36:27.000000000 +0200
@@ -678,7 +678,8 @@ void page_remove_rmap(struct page *page,
* Leaving it set also helps swapoff to reinstate ptes
* faster for those pages still in swapcache.
*/
- if (page_test_dirty(page)) {
+ if ((!PageAnon(page) || PageSwapCache(page)) &&
+ page_test_dirty(page)) {
page_clear_dirty(page);
set_page_dirty(page);
}
--