mm: free swp_entry in madvise_free
Subsystems (14)
PATCH 1/4 mm: free swp_entry in madvise_free
When I test below piece of code with 12 processes(ie, 512M * 12 = 6G consume) on my (3G ram + 12 cpu + 8G swap, the madvise_free is siginficat slower (ie, 2x times) than madvise_dontneed.
loop = 5;
mmap(512M);
while (loop--) {
memset(512M);
madvise(MADV_FREE or MADV_DONTNEED);
}The reason is lots of swapin.
1) dontneed: 1,612 swapin
2) madvfree: 879,585 swapin
If we find hinted pages were already swapped out when syscall is called, it's pointless to keep the swapped-out pages in pte. Instead, let's free the cold page because swapin is more expensive than (alloc page + zeroing).
With this patch, it reduced swapin from 879,585 to 1,878 so elapsed time
1) dontneed: 6.10user 233.50system 0:50.44elapsed
2) madvfree: 6.03user 401.17system 1:30.67elapsed
2) madvfree + below patch: 6.70user 339.14system 1:04.45elapsed
--- mm/madvise.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)
mm/madvise.c +25 -1
@@ -274,7 +274,9 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,spinlock_t *ptl;pte_t *pte, ptent;struct page *page; +swp_entry_t entry;unsigned long next; +int nr_swap =0 ; next =pmd_addr_end (addr, end);if (pmd_trans_huge (*pmd)) {
@@ -293,8 +295,22 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,for (; addr != end; pte++, addr +=PAGE_SIZE ) { ptent = *pte; -if (!pte_present (ptent)) +if (pte_none (ptent))continue ; +/* +* If the pte has swp_entry, just clear page table to +* prevent swap-in which is more expensive rather than +* (page allocation + zeroing). +*/ +if (!pte_present (ptent)) { + entry =pte_to_swp_entry (ptent); +if (non_swap_entry (entry)) +continue ; + nr_swap--; +free_swap_and_cache (entry); +pte_clear_not_present_full (mm, addr, pte, tlb->fullmm); +continue ; + } page =vm_normal_page (vma, addr, ptent);if (!page)
@@ -326,6 +342,14 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,set_pte_at (mm, addr, pte, ptent);tlb_remove_tlb_entry (tlb, pte, addr); } + +if (nr_swap) { +if (current->mm == mm) +sync_mm_rss (mm); + +add_mm_counter (mm,MM_SWAPENTS , nr_swap); + } +arch_leave_lazy_mmu_mode ();pte_unmap_unlock (pte -1 , ptl); next:
Signature · 1 line
1.9.3
PATCH 2/4 mm: change deactivate_page with deactivate_file_page
Deactivate_page was born for file invalidation so it has too specific logic for file-backed pages. So, let's change the name of function to file-specific and yield the generic name.
--- include/linux/swap.h | 2 +- mm/swap.c | 20 ++++++++++---------- mm/truncate.c | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-)
include/linux/swap.h +1 -1
@@ -307,7 +307,7 @@ extern void lru_add_drain(void);extern void lru_add_drain_cpu (int cpu);extern void lru_add_drain_all (void );extern void rotate_reclaimable_page (struct page *page); -extern void deactivate_page (struct page *page); +extern void deactivate_file_page (struct page *page);extern void swap_setup (void );extern void add_page_to_unevictable_list (struct page *page);
mm/swap.c +10 -10
@@ -42,7 +42,7 @@ int page_cluster; static DEFINE_PER_CPU(struct pagevec, lru_add_pvec); static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs); -static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs); +static DEFINE_PER_CPU(struct pagevec, lru_deactivate_file_pvecs);/* * This path almost never happens for VM activity - pages are normally
@@ -743,7 +743,7 @@ void lru_cache_add_active_or_unevictable(struct page *page,* be write it out by flusher threads as this is much more effective * than the single-page writeout from reclaim. */ -static void lru_deactivate_fn (struct page *page,struct lruvec *lruvec, +static void lru_deactivate_file_fn (struct page *page,struct lruvec *lruvec,void *arg) {int lru, file;
@@ -811,22 +811,22 @@ void lru_add_drain_cpu(int cpu)local_irq_restore (flags); } - pvec = &per_cpu (lru_deactivate_pvecs, cpu); + pvec = &per_cpu (lru_deactivate_file_pvecs, cpu);if (pagevec_count (pvec)) -pagevec_lru_move_fn (pvec, lru_deactivate_fn,NULL ); +pagevec_lru_move_fn (pvec, lru_deactivate_file_fn,NULL );activate_page_drain (cpu); }/** -* deactivate_page - forcefully deactivate a page +* deactivate_file_page - forcefully deactivate a file page * @page: page to deactivate * * This function hints the VM that @page is a good reclaim candidate, * for example if its invalidation fails due to the page being dirty * or under writeback. */ -void deactivate_page (struct page *page) +void deactivate_file_page (struct page *page) {/* * In a workload with many unevictable page such as mprotect, unevictable
@@ -836,11 +836,11 @@ void deactivate_page(struct page *page)return ;if (likely (get_page_unless_zero (page))) { -struct pagevec *pvec = &get_cpu_var (lru_deactivate_pvecs); +struct pagevec *pvec = &get_cpu_var (lru_deactivate_file_pvecs);if (!pagevec_add (pvec, page)) -pagevec_lru_move_fn (pvec, lru_deactivate_fn,NULL ); -put_cpu_var (lru_deactivate_pvecs); +pagevec_lru_move_fn (pvec, lru_deactivate_file_fn,NULL ); +put_cpu_var (lru_deactivate_file_pvecs); } }
@@ -872,7 +872,7 @@ void lru_add_drain_all(void)if (pagevec_count (&per_cpu (lru_add_pvec, cpu)) ||pagevec_count (&per_cpu (lru_rotate_pvecs, cpu)) || -pagevec_count (&per_cpu (lru_deactivate_pvecs, cpu)) || +pagevec_count (&per_cpu (lru_deactivate_file_pvecs, cpu)) ||need_activate_page_drain (cpu)) {INIT_WORK (work, lru_add_drain_per_cpu);schedule_work_on (cpu, work);
mm/truncate.c +1 -1
@@ -490,7 +490,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,* of interest and try to speed up its reclaim. */ if (!ret) -deactivate_page (page); +deactivate_file_page (page); count += ret; }pagevec_remove_exceptionals (&pvec);
Signature · 7 lines
1.9.3 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/4 mm: move lazy free pages to inactive list
In reply to Minchan KimMADV_FREE is hint that it's okay to discard pages if there is memory pressure and we uses reclaimers(ie, kswapd and direct reclaim) to free them so there is no worth to remain them in active anonymous LRU so this patch moves them to inactive LRU list's head.
This means that MADV_FREE-ed pages which were living on the inactive list are reclaimed first because they are more likely to be cold rather than recently active pages.
A arguable issue for the approach would be whether we should put it to head or tail in inactive list. I selected *head* because kernel cannot make sure it's really cold or warm for every MADV_FREE usecase but at least we know it's not *hot* so landing of inactive head would be comprimise for various usecases.
This is fixing a suboptimal behavior of MADV_FREE when pages living on the active list will sit there for a long time even under memory pressure while the inactive list is reclaimed heavily. This basically breaks the whole purpose of using MADV_FREE to help the system to free memory which is might not be used.
--- include/linux/swap.h | 1 + mm/madvise.c | 2 ++ mm/swap.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+)
include/linux/swap.h +1 -0
@@ -308,6 +308,7 @@ extern void lru_add_drain_cpu(int cpu);extern void lru_add_drain_all (void );extern void rotate_reclaimable_page (struct page *page);extern void deactivate_file_page (struct page *page); +extern void deactivate_page (struct page *page);extern void swap_setup (void );extern void add_page_to_unevictable_list (struct page *page);
mm/madvise.c +2 -0
@@ -340,6 +340,8 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, ptent =pte_mkold (ptent); ptent =pte_mkclean (ptent);set_pte_at (mm, addr, pte, ptent); +if (PageActive (page)) +deactivate_page (page);tlb_remove_tlb_entry (tlb, pte, addr); }
mm/swap.c +35 -0
@@ -43,6 +43,7 @@ int page_cluster; static DEFINE_PER_CPU(struct pagevec, lru_add_pvec); static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs); static DEFINE_PER_CPU(struct pagevec, lru_deactivate_file_pvecs); +static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs);/* * This path almost never happens for VM activity - pages are normally
@@ -789,6 +790,23 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec,update_page_reclaim_stat (lruvec, file,0 ); } + +static void lru_deactivate_fn (struct page *page,struct lruvec *lruvec, +void *arg) +{ +if (PageLRU (page) &&PageActive (page) && !PageUnevictable (page)) { +int file =page_is_file_cache (page); +int lru =page_lru_base_type (page); + +del_page_from_lru_list (page, lruvec, lru +LRU_ACTIVE ); +ClearPageActive (page); +add_page_to_lru_list (page, lruvec, lru); + +__count_vm_event (PGDEACTIVATE ); +update_page_reclaim_stat (lruvec, file,0 ); + } +} +/* * Drain pages out of the cpu's pagevecs. * Either "cpu" is the current CPU, and preemption has already been
@@ -815,6 +833,10 @@ void lru_add_drain_cpu(int cpu)if (pagevec_count (pvec))pagevec_lru_move_fn (pvec, lru_deactivate_file_fn,NULL ); + pvec = &per_cpu (lru_deactivate_pvecs, cpu); +if (pagevec_count (pvec)) +pagevec_lru_move_fn (pvec, lru_deactivate_fn,NULL ); +activate_page_drain (cpu); }
@@ -844,6 +866,18 @@ void deactivate_file_page(struct page *page) } } +void deactivate_page (struct page *page) +{ +if (PageLRU (page) &&PageActive (page) && !PageUnevictable (page)) { +struct pagevec *pvec = &get_cpu_var (lru_deactivate_pvecs); + +page_cache_get (page); +if (!pagevec_add (pvec, page)) +pagevec_lru_move_fn (pvec, lru_deactivate_fn,NULL ); +put_cpu_var (lru_deactivate_pvecs); + } +} +void lru_add_drain (void ) {lru_add_drain_cpu (get_cpu ());
@@ -873,6 +907,7 @@ void lru_add_drain_all(void)if (pagevec_count (&per_cpu (lru_add_pvec, cpu)) ||pagevec_count (&per_cpu (lru_rotate_pvecs, cpu)) ||pagevec_count (&per_cpu (lru_deactivate_file_pvecs, cpu)) || +pagevec_count (&per_cpu (lru_deactivate_pvecs, cpu)) ||need_activate_page_drain (cpu)) {INIT_WORK (work, lru_add_drain_per_cpu);schedule_work_on (cpu, work);
Signature · 7 lines
1.9.3 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RE: [PATCH 3/4] mm: move lazy free pages to inactive list
Quoted 55 lines
-----Original Message-----
From: Minchan Kim [mailto:[email protected]]
Sent: Wednesday, March 11, 2015 9:21 AM
To: Andrew Morton
Cc: [email protected]; [email protected]; Michal Hocko; Johannes Weiner; Mel Gorman; Rik van Riel; Shaohua Li; Wang, Yalin; Minchan Kim
Subject: [PATCH 3/4] mm: move lazy free pages to inactive list
MADV_FREEis hint that it's okay to discard pages if there is memory pressure and we usesreclaimers(ie, kswapd and direct reclaim)to free them so there is no worth to remain them in active anonymous LRU so this patch moves them to inactive LRU list's head.This means that MADV_FREE-ed pages which were living on the inactive list are reclaimed first because they are more likely to be cold rather than recently active pages.
A arguable issue for the approach would be whether we should put it to head or tail in inactive list. I selected *head* because kernel cannot make sure it's really cold or warm for every
MADV_FREEusecase but at least we know it's not *hot* so landing of inactive head would be comprimise for various usecases.This is fixing a suboptimal behavior of
MADV_FREEwhen pages living on the active list will sit there for a long time even under memory pressure while the inactive list is reclaimed heavily. This basically breaks the whole purpose of usingMADV_FREEto help the system to free memory which is might not be used.Acked-by Michal Hocko <[email protected]>Signed-off-by Minchan Kim <[email protected]>--- include/linux/swap.h | 1 + mm/madvise.c | 2 ++ mm/swap.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+)include/linux/swap.h +1
-0@@ -308,6 +308,7 @@ extern void lru_add_drain_cpu(int cpu);extern void lru_add_drain_all (void );extern void rotate_reclaimable_page (struct page *page);extern void deactivate_file_page (struct page *page); +extern void deactivate_page (struct page *page);extern void swap_setup (void );extern void add_page_to_unevictable_list (struct page *page);mm/madvise.c +0
-0
mm/madvise.c static int madvise_free_pte_range(pmd_t *pmd, unsigned · line 347
Quoted 8 lines
mm/madvise.c +2
-0@@ -340,6 +340,8 @@ static int madvise_free_pte_range(pmd_t *pmd, unsignedlong addr, ptent =pte_mkold (ptent); ptent =pte_mkclean (ptent);set_pte_at (mm, addr, pte, ptent); +if (PageActive (page)) +deactivate_page (page);tlb_remove_tlb_entry (tlb, pte, addr); }
I think this place should be changed like this:
+ if (!page_referenced(page, false, NULL, NULL, NULL) && PageActive(page))
+ deactivate_page(page);
Because we don't know if other processes are reference this page, If it is true, don't need deactivate this page.
Thanks
Re: [PATCH 3/4] mm: move lazy free pages to inactive list
Quoted 61 lines · Yalin
Quoted 61 lines
-----Original Message-----
From: Minchan Kim [mailto:[email protected]]
Sent: Wednesday, March 11, 2015 9:21 AM
To: Andrew Morton
Cc: [email protected]; [email protected]; Michal Hocko; Johannes Weiner; Mel Gorman; Rik van Riel; Shaohua Li; Wang, Yalin; Minchan Kim
Subject: [PATCH 3/4] mm: move lazy free pages to inactive list
MADV_FREEis hint that it's okay to discard pages if there is memory pressure and we usesreclaimers(ie, kswapd and direct reclaim)to free them so there is no worth to remain them in active anonymous LRU so this patch moves them to inactive LRU list's head.This means that MADV_FREE-ed pages which were living on the inactive list are reclaimed first because they are more likely to be cold rather than recently active pages.
A arguable issue for the approach would be whether we should put it to head or tail in inactive list. I selected *head* because kernel cannot make sure it's really cold or warm for every
MADV_FREEusecase but at least we know it's not *hot* so landing of inactive head would be comprimise for various usecases.This is fixing a suboptimal behavior of
MADV_FREEwhen pages living on the active list will sit there for a long time even under memory pressure while the inactive list is reclaimed heavily. This basically breaks the whole purpose of usingMADV_FREEto help the system to free memory which is might not be used.Acked-by Michal Hocko <[email protected]>Signed-off-by Minchan Kim <[email protected]>--- include/linux/swap.h | 1 + mm/madvise.c | 2 ++ mm/swap.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+)include/linux/swap.h +1
-0@@ -308,6 +308,7 @@ extern void lru_add_drain_cpu(int cpu);extern void lru_add_drain_all (void );extern void rotate_reclaimable_page (struct page *page);extern void deactivate_file_page (struct page *page); +extern void deactivate_page (struct page *page);extern void swap_setup (void );extern void add_page_to_unevictable_list (struct page *page);mm/madvise.c +2
-0@@ -340,6 +340,8 @@ static int madvise_free_pte_range(pmd_t *pmd, unsignedlong addr, ptent =pte_mkold (ptent); ptent =pte_mkclean (ptent);set_pte_at (mm, addr, pte, ptent); +if (PageActive (page)) +deactivate_page (page);
Quoted 8 lines
mm/madvise.c static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, · line 346
Quoted 2 lines
mm/madvise.c +0
-0tlb_remove_tlb_entry (tlb, pte, addr); }I think this place should be changed like this:
+ if (!page_referenced(page, false, NULL, NULL, NULL) && PageActive(page))
+deactivate_page(page);
Because we don't know if other processes are reference this page, If it is true, don't need deactivate this page.
The page_referenced is too much heavy operation to do it in madvise_free fast path.
If other processes(parent or child) referenced the page, shrink_page_list in slow path could filter it out and activates the page.
In addition, shared case for anon pages happens by fork mostly so we could expect child will do exec soonish in many cases.
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 3/4] mm: move lazy free pages to inactive list
In reply to Wang, YalinQuoted 61 lines · Yalin
Quoted 61 lines
-----Original Message-----
From: Minchan Kim [mailto:[email protected]]
Sent: Wednesday, March 11, 2015 9:21 AM
To: Andrew Morton
Cc: [email protected]; [email protected]; Michal Hocko; Johannes Weiner; Mel Gorman; Rik van Riel; Shaohua Li; Wang, Yalin; Minchan Kim
Subject: [PATCH 3/4] mm: move lazy free pages to inactive list
MADV_FREEis hint that it's okay to discard pages if there is memory pressure and we usesreclaimers(ie, kswapd and direct reclaim)to free them so there is no worth to remain them in active anonymous LRU so this patch moves them to inactive LRU list's head.This means that MADV_FREE-ed pages which were living on the inactive list are reclaimed first because they are more likely to be cold rather than recently active pages.
A arguable issue for the approach would be whether we should put it to head or tail in inactive list. I selected *head* because kernel cannot make sure it's really cold or warm for every
MADV_FREEusecase but at least we know it's not *hot* so landing of inactive head would be comprimise for various usecases.This is fixing a suboptimal behavior of
MADV_FREEwhen pages living on the active list will sit there for a long time even under memory pressure while the inactive list is reclaimed heavily. This basically breaks the whole purpose of usingMADV_FREEto help the system to free memory which is might not be used.Acked-by Michal Hocko <[email protected]>Signed-off-by Minchan Kim <[email protected]>--- include/linux/swap.h | 1 + mm/madvise.c | 2 ++ mm/swap.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+)include/linux/swap.h +1
-0@@ -308,6 +308,7 @@ extern void lru_add_drain_cpu(int cpu);extern void lru_add_drain_all (void );extern void rotate_reclaimable_page (struct page *page);extern void deactivate_file_page (struct page *page); +extern void deactivate_page (struct page *page);extern void swap_setup (void );extern void add_page_to_unevictable_list (struct page *page);mm/madvise.c +2
-0@@ -340,6 +340,8 @@ static int madvise_free_pte_range(pmd_t *pmd, unsignedlong addr, ptent =pte_mkold (ptent); ptent =pte_mkclean (ptent);set_pte_at (mm, addr, pte, ptent); +if (PageActive (page)) +deactivate_page (page);
Quoted 8 lines
mm/madvise.c static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, · line 346
Quoted 2 lines
mm/madvise.c +0
-0tlb_remove_tlb_entry (tlb, pte, addr); }I think this place should be changed like this:
+ if (!page_referenced(page, false, NULL, NULL, NULL) && PageActive(page))
+deactivate_page(page);
Because we don't know if other processes are reference this page, If it is true, don't need deactivate this page.
We never clear the page and pte referenced bits on an active page, that is only done when the page is moved to the inactive list through LRU movement.
In other words, the page_referenced() check will return true most of the time, even if the page was last referenced half an hour ago (but there was no memory pressure).
Minchan's code looks correct.
The code may even want a ClearPageReferenced(page) in there...
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC 1/1 mm: don't ignore file map pages for madvise_free( )
In reply to Minchan KimHi
I just want to explain my ideas about file map pages for madvise_free() syscall. As the following patch,
For file map vma, there is 2 types:
1. private file map
In this type, the pages of this vma are file map pages or anon page (when COW happened),
2. shared file map
In this type, the pages of this vma are all file map pages.
No matter which type file map,
We can handle file map vma as the following:
If the page is file map pages,
We just clear its pte young bit(pte_mkold()), This will have some advantages, it will make page Reclaim path move this file map page into inactive lru list aggressively.
If the page is anon map page, we just handle it in the Same way as for the pages in anon vma.
---
mm/madvise.c +2 -5
@@ -322,7 +322,8 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, ptent =ptep_get_and_clear_full (mm, addr, pte, tlb->fullmm); ptent =pte_mkold (ptent); - ptent =pte_mkclean (ptent); +if (PageAnon (page)) + ptent =pte_mkclean (ptent);set_pte_at (mm, addr, pte, ptent);tlb_remove_tlb_entry (tlb, pte, addr); }
@@ -364,10 +365,6 @@ static int madvise_free_single_vma(struct vm_area_struct *vma,if (vma->vm_flags & (VM_LOCKED |VM_HUGETLB |VM_PFNMAP ))return -EINVAL ; -/* MADV_FREE works for only anon vma at the moment */ -if (vma->vm_file) -return -EINVAL ; - start =max (vma->vm_start, start_addr);if (start >= vma->vm_end)return -EINVAL ;
RFC 1/1 mm:do recheck for freeable page in reclaim path
In reply to Minchan KimIn reclaim path, if encounter a freeable page,
the try_to_unmap may fail, because the page's pte is dirty, we can recheck this page as normal non-freeable page, this means we can swap out this page into swap partition.
--- mm/vmscan.c | 5 +++++ 1 file changed, 5 insertions(+)
mm/vmscan.c +5 -0
@@ -1000,6 +1000,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, } } +recheck:if (!force_reclaim) references =page_check_references (page, sc, &freeable);
@@ -1045,6 +1046,10 @@ unmap:switch (try_to_unmap (page, freeable ?TTU_FREE : ttu_flags)) {case SWAP_FAIL : +if (freeable) { + freeable = false; + goto recheck; + } goto activate_locked;case SWAP_AGAIN : goto keep_locked;
Signature · 1 line
2.2.2
Andrew Morton
maintainerRe: [PATCH 3/4] mm: move lazy free pages to inactive list
In reply to Minchan KimQuoted 32 lines · On Wed, 11 Mar 2015 10:20:37 +0900 Minchan Kim <[email protected]> wrote:
MADV_FREEis hint that it's okay to discard pages if there is memory pressure and we usesreclaimers(ie, kswapd and direct reclaim)to free them so there is no worth to remain them in active anonymous LRU so this patch moves them to inactive LRU list's head.This means that MADV_FREE-ed pages which were living on the inactive list are reclaimed first because they are more likely to be cold rather than recently active pages.
A arguable issue for the approach would be whether we should put it to head or tail in inactive list. I selected *head* because kernel cannot make sure it's really cold or warm for every
MADV_FREEusecase but at least we know it's not *hot* so landing of inactive head would be comprimise for various usecases.This is fixing a suboptimal behavior of
MADV_FREEwhen pages living on the active list will sit there for a long time even under memory pressure while the inactive list is reclaimed heavily. This basically breaks the whole purpose of usingMADV_FREEto help the system to free memory which is might not be used.mm/swap.c +3
-0@@ -789,6 +790,23 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec,update_page_reclaim_stat (lruvec, file,0 ); } + +static void lru_deactivate_fn (struct page *page,struct lruvec *lruvec, +void *arg)
mm/swap.c void deactivate_file_page(struct page *page) · line 870
Quoted 5 lines
mm/swap.c +2
-0@@ -844,6 +866,18 @@ void deactivate_file_page(struct page *page) } } +void deactivate_page (struct page *page) +{
lru_deactivate_file_fn() and deactivate_file_page() are carefully documented and lru_deactivate_fn() and deactivate_page() should be as well. In fact it becomes more important now that we have two similar-looking things.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 3/4] mm: move lazy free pages to inactive list
Hello Andrew,
Quoted 37 lines · Andrew Morton
Quoted 35 lines · On Wed, 11 Mar 2015 10:20:37 +0900 Minchan Kim <[email protected]> wrote:
MADV_FREEis hint that it's okay to discard pages if there is memory pressure and we usesreclaimers(ie, kswapd and direct reclaim)to free them so there is no worth to remain them in active anonymous LRU so this patch moves them to inactive LRU list's head.This means that MADV_FREE-ed pages which were living on the inactive list are reclaimed first because they are more likely to be cold rather than recently active pages.
A arguable issue for the approach would be whether we should put it to head or tail in inactive list. I selected *head* because kernel cannot make sure it's really cold or warm for every
MADV_FREEusecase but at least we know it's not *hot* so landing of inactive head would be comprimise for various usecases.This is fixing a suboptimal behavior of
MADV_FREEwhen pages living on the active list will sit there for a long time even under memory pressure while the inactive list is reclaimed heavily. This basically breaks the whole purpose of usingMADV_FREEto help the system to free memory which is might not be used.(quoted diff) +3
-0@@ -789,6 +790,23 @@ static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, update_page_reclaim_stat(lruvec, file, 0); } + +static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec, + void *arg)@@ -844,6 +866,18 @@ void deactivate_file_page(struct page *page) } }
Quoted 7 lines
Review void deactivate_file_page(struct page *page) · line 870
Quoted 2 lines
(quoted diff) +2
-0+void deactivate_page(struct page *page) +{
lru_deactivate_file_fn()anddeactivate_file_page()are carefully documented andlru_deactivate_fn()anddeactivate_page()should be as well. In fact it becomes more important now that we have two similar-looking things.
Sorry, I have missed this comment.
Acutally, deactive_file_page was too specific on file-backed page invalidation when I implemented first time. That's why it had a lot description but deactivate_page is too general so I think short comment is enough. :)
Here it goes.
Thanks.
Andrew Morton
maintainerRe: [PATCH 3/4] mm: move lazy free pages to inactive list
Quoted 6 lines · On Mon, 30 Mar 2015 14:35:02 +0900 Minchan Kim <[email protected]> wrote:
mm/swap.c +0
-0@@ -866,6 +866,13 @@ void deactivate_file_page(struct page *page) } }
mm/swap.c void deactivate_file_page(struct page *page) · line 878
Quoted 10 lines
mm/swap.c +7
-0+/** +* deactivate_page - deactivate a page +* @page: page to deactivate +* +* This function moves @page to inactive list if @page was on active list and +* was not unevictable page to accelerate to reclaim @page. +*/ void deactivate_page (struct page *page) {if (PageLRU (page) &&PageActive (page) && !PageUnevictable (page)) {
Thanks.
deactivate_page() doesn't look at or alter PageReferenced(). Should it?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 3/4] mm: move lazy free pages to inactive list
Hello Andrew,
Quoted 21 lines · Andrew Morton
Quoted 6 lines · On Mon, 30 Mar 2015 14:35:02 +0900 Minchan Kim <[email protected]> wrote:
mm/swap.c +0
-0@@ -866,6 +866,13 @@ void deactivate_file_page(struct page *page) } }mm/swap.c void deactivate_file_page(struct page *page) · line 878
Quoted 10 lines
mm/swap.c +7
-0+/** +* deactivate_page - deactivate a page +* @page: page to deactivate +* +* This function moves @page to inactive list if @page was on active list and +* was not unevictable page to accelerate to reclaim @page. +*/ void deactivate_page (struct page *page) {if (PageLRU (page) &&PageActive (page) && !PageUnevictable (page)) {Thanks.
Quoted 1 line
deactivate_page()doesn't look at or alterPageReferenced(). Should it?
Absolutely true. Thanks.
Here it goes.
Andrew Morton
maintainerRe: [PATCH 3/4] mm: move lazy free pages to inactive list
Quoted 20 lines · On Tue, 31 Mar 2015 13:45:25 +0900 Minchan Kim <[email protected]> wrote:
Quoted 2 lines
deactivate_page()doesn't look at or alterPageReferenced(). Should it?Absolutely true. Thanks.
Here it goes.Quoted 1 line
From
2b2c92eb73a1cceac615b9abd4c0f5f0c3395ff5Mon Sep 17 00:00:00 2001From: Minchan Kim <[email protected]>
Date: Tue, 31 Mar 2015 13:38:46 +0900
Subject: [PATCH] mm:lru_deactivate_fnshould clearPG_referenced
deactivate_pageaims for accelerate for reclaiming through moving pages from active list to inactive list so we should clearPG_referencedfor the goal....
mm/swap.c static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec, · line 806
Quoted 7 lines
mm/swap.c +1
-0@@ -800,6 +800,7 @@ static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec,del_page_from_lru_list (page, lruvec, lru +LRU_ACTIVE );ClearPageActive (page); +ClearPageReferenced (page);add_page_to_lru_list (page, lruvec, lru);__count_vm_event (PGDEACTIVATE );
What if we have
PageLRU(page) && !PageActive(page) && PageReferenced(page)
if we really want to "accelerate the reclaim of @page" then we should clear PG_referenced there too.
(And what about page_referenced(page) :))
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 3/4] mm: move lazy free pages to inactive list
Quoted 27 lines · Andrew Morton
Quoted 26 lines · On Tue, 31 Mar 2015 13:45:25 +0900 Minchan Kim <[email protected]> wrote:
Quoted 2 lines
deactivate_page()doesn't look at or alterPageReferenced(). Should it?Absolutely true. Thanks.
Here it goes.Quoted 1 line
From
2b2c92eb73a1cceac615b9abd4c0f5f0c3395ff5Mon Sep 17 00:00:00 2001From: Minchan Kim <[email protected]>
Date: Tue, 31 Mar 2015 13:38:46 +0900
Subject: [PATCH] mm:lru_deactivate_fnshould clearPG_referenced
deactivate_pageaims for accelerate for reclaiming through moving pages from active list to inactive list so we should clearPG_referencedfor the goal....
mm/swap.c +1
-0@@ -800,6 +800,7 @@ static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec,del_page_from_lru_list (page, lruvec, lru +LRU_ACTIVE );ClearPageActive (page); +ClearPageReferenced (page);add_page_to_lru_list (page, lruvec, lru);
Quoted 8 lines
mm/swap.c static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec, · line 806
Quoted 1 line
mm/swap.c +0
-0__count_vm_event (PGDEACTIVATE );What if we have
PageLRU(page) && !PageActive(page) && PageReferenced(page)if we really want to "accelerate the reclaim of @page" then we should clear
PG_referencedthere too.
The function's name is *deactivate*_page. IOW, I think it should work for only pages in active list, IMHO.
Quoted 2 lines
(And what about
page_referenced(page):))
Yes, I considered it when you mentioned PG_referenced. Now, madvise_free clear out access bit of page table when the syscall is called so shrink_page_list could reclaim pages easily.
Of course, we could clear access bit by page_referenced for general purpose, not only madvise_free but it would hurt performance for madvise_free so I'd like to leave it unless there is a need for the function.
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/4 mm: make every pte dirty on do_swap_page
In reply to Minchan KimBascially, MADV_FREE relys on the pte dirty to decide whether it allows VM to discard the page. However, if there is swap-in, pte pointed out the page has no pte_dirty. So, MADV_FREE checks PageDirty and PageSwapCache for those pages to not discard it because swapped-in page could live on swap cache or PageDirty when it is removed from swapcache.
The problem in here is that anonymous pages can have PageDirty if it is removed from swapcache so that VM cannot parse those pages as freeable even if we did madvise_free. Look at below example.
ptr = malloc();
memset(ptr);
..
heavy memory pressure -> swap-out all of pages
..
out of memory pressure so there are lots of free pages
..
var = *ptr; -> swap-in page/remove the page from swapcache. so pte_clean
but SetPageDirty
madvise_free(ptr);
..
..
heavy memory pressure -> VM cannot discard the page by PageDirty.
PageDirty for anonymous page aims for avoiding duplicating swapping out. In other words, if a page have swapped-in but live swapcache(ie, !PageDirty), we could save swapout if the page is selected as victim by VM in future because swap device have kept previous swapped-out contents of the page.
So, rather than relying on the PG_dirty for working madvise_free, pte_dirty is more straightforward. Inherently, swapped-out page was pte_dirty so this patch restores the dirtiness when swap-in fault happens so madvise_free doesn't rely on the PageDirty any more.
--- mm/madvise.c | 1 - mm/memory.c | 9 +++++++-- mm/rmap.c | 2 +- mm/vmscan.c | 3 +-- 4 files changed, 9 insertions(+), 6 deletions(-)
mm/madvise.c +0 -1
@@ -325,7 +325,6 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,continue ; } -ClearPageDirty (page);unlock_page (page); }
mm/memory.c +7 -2
@@ -2521,9 +2521,14 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,inc_mm_counter_fast (mm,MM_ANONPAGES );dec_mm_counter_fast (mm,MM_SWAPENTS ); - pte =mk_pte (page, vma->vm_page_prot); + +/* +* Every page swapped-out was pte_dirty so we make pte dirty again. +* MADV_FREE relies on it. +*/ + pte =pte_mkdirty (mk_pte (page, vma->vm_page_prot));if ((flags &FAULT_FLAG_WRITE ) &&reuse_swap_page (page)) { - pte =maybe_mkwrite (pte_mkdirty (pte), vma); + pte =maybe_mkwrite (pte, vma); flags &= ~FAULT_FLAG_WRITE ; ret |=VM_FAULT_WRITE ; exclusive =1 ;
mm/rmap.c +1 -1
@@ -1268,7 +1268,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,if (flags &TTU_FREE ) {VM_BUG_ON_PAGE (PageSwapCache (page), page); -if (!dirty && !PageDirty (page)) { +if (!dirty) {/* It's a freeable page by MADV_FREE */ dec_mm_counter (mm,MM_ANONPAGES ); goto discard;
mm/vmscan.c +1 -2
@@ -805,8 +805,7 @@ static enum page_references page_check_references(struct page *page,return PAGEREF_KEEP ; } -if (PageAnon (page) && !pte_dirty && !PageSwapCache (page) && - !PageDirty (page)) +if (PageAnon (page) && !pte_dirty && !PageSwapCache (page)) *freeable = true;/* Reclaim if clean, defer dirty pages to writeback */
Signature · 7 lines
1.9.3 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
2nd description trial.
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Quoted 1 line · Minchan Kim
2nd description trial.
...
Hi Minchan, could you please point for which repo this patch, linux-next?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Hi Cyrill,
Quoted 5 lines · Cyrill Gorcunov
Quoted 1 line · Minchan Kim
2nd description trial.
...
Hi Minchan, could you please point for which repo this patch, linux-next?
It was based on v4.0-rc5-mmotm-2015-03-24-17-02. As well, I confirmed it was applied on local-next-20150327.
Thanks.
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Quoted 5 lines · Minchan Kim
Hi Cyrill,
Quoted 2 lines · Cyrill Gorcunov
Quoted 1 line · Minchan Kim
2nd description trial.
Quoted 8 lines
Quoted 3 lines
...
Hi Minchan, could you please point for which repo this patch, linux-next?It was based on v4.0-rc5-mmotm-2015-03-24-17-02. As well, I confirmed it was applied on local-next-20150327.
Thanks.
Hi Minchan! I managed to fetch mmotm and the change looks reasonable to me. Still better to wait for review from Mel or Hugh, maybe I miss something obvious.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Quoted 10 lines · Cyrill Gorcunov
Quoted 9 lines · Minchan Kim
Hi Cyrill,
Quoted 5 lines · Cyrill Gorcunov
Quoted 1 line · Minchan Kim
2nd description trial.
...
Hi Minchan, could you please point for which repo this patch, linux-next?
Quoted 8 lines
Quoted 4 lines
It was based on v4.0-rc5-mmotm-2015-03-24-17-02. As well, I confirmed it was applied on local-next-20150327.
Thanks.
Hi Minchan! I managed to fetch mmotm and the change looks reasonable to me. Still better to wait for review from Mel or Hugh, maybe I miss something obvious.
Thanks for the review!
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
In reply to Minchan KimBump.
Quoted 112 lines · Minchan Kim
Bascially,
MADV_FREErelys on the pte dirty to decide whether it allows VM to discard the page. However, if there is swap-in, pte pointed out the page has nopte_dirty. So,MADV_FREEchecks PageDirty and PageSwapCache for those pages to not discard it because swapped-in page could live on swap cache or PageDirty when it is removed from swapcache.The problem in here is that anonymous pages can have PageDirty if it is removed from swapcache so that VM cannot parse those pages as freeable even if we did
madvise_free. Look at below example.ptr =
malloc();
memset(ptr);
..
heavy memory pressure -> swap-out all of pages
..
out of memory pressure so there are lots of free pages
..
var = *ptr; -> swap-in page/remove the page from swapcache. sopte_clean
but SetPageDirty
madvise_free(ptr);
..
..
heavy memory pressure -> VM cannot discard the page by PageDirty.PageDirty for anonymous page aims for avoiding duplicating swapping out. In other words, if a page have swapped-in but live
swapcache(ie, !PageDirty), we could save swapout if the page is selected as victim by VM in future because swap device have kept previous swapped-out contents of the page.So, rather than relying on the
PG_dirtyfor workingmadvise_free,pte_dirtyis more straightforward. Inherently, swapped-out page waspte_dirtyso this patch restores the dirtiness when swap-in fault happens somadvise_freedoesn't rely on the PageDirty any more.Cc Hugh Dickins <[email protected]>Cc Cyrill Gorcunov <[email protected]>Cc Pavel Emelyanov <[email protected]>Reported-by Yalin Wang <[email protected]>Signed-off-by Minchan Kim <[email protected]>--- mm/madvise.c | 1 - mm/memory.c | 9 +++++++-- mm/rmap.c | 2 +- mm/vmscan.c | 3 +-- 4 files changed, 9 insertions(+), 6 deletions(-)mm/madvise.c +0
-1@@ -325,7 +325,6 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,continue ; } -ClearPageDirty (page);unlock_page (page); }mm/memory.c +7
-2@@ -2521,9 +2521,14 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,inc_mm_counter_fast (mm,MM_ANONPAGES );dec_mm_counter_fast (mm,MM_SWAPENTS ); - pte =mk_pte (page, vma->vm_page_prot); + +/* +* Every page swapped-out was pte_dirty so we make pte dirty again. +* MADV_FREE relies on it. +*/ + pte =pte_mkdirty (mk_pte (page, vma->vm_page_prot));if ((flags &FAULT_FLAG_WRITE ) &&reuse_swap_page (page)) { - pte =maybe_mkwrite (pte_mkdirty (pte), vma); + pte =maybe_mkwrite (pte, vma); flags &= ~FAULT_FLAG_WRITE ; ret |=VM_FAULT_WRITE ; exclusive =1 ;mm/rmap.c +1
-1@@ -1268,7 +1268,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,if (flags &TTU_FREE ) {VM_BUG_ON_PAGE (PageSwapCache (page), page); -if (!dirty && !PageDirty (page)) { +if (!dirty) {/* It's a freeable page by MADV_FREE */ dec_mm_counter (mm,MM_ANONPAGES ); goto discard;mm/vmscan.c +1
-2@@ -805,8 +805,7 @@ static enum page_references page_check_references(struct page *page,return PAGEREF_KEEP ; } -if (PageAnon (page) && !pte_dirty && !PageSwapCache (page) && - !PageDirty (page)) +if (PageAnon (page) && !pte_dirty && !PageSwapCache (page)) *freeable = true;/* Reclaim if clean, defer dirty pages to writeback */ Signature · 1 line
1.9.3
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Quoted 1 line · On Thu, 9 Apr 2015 08:50:25 +0900 Minchan Kim <[email protected]> wrote:
Bump.
I'm getting the feeling that MADV_FREE is out of control.
Below is the overall rollup of
mm-support-madvisemadv_free.patch mm-support-madvisemadv_free-fix.patch mm-support-madvisemadv_free-fix-2.patch mm-dont-split-thp-page-when-syscall-is-called.patch mm-dont-split-thp-page-when-syscall-is-called-fix.patch mm-dont-split-thp-page-when-syscall-is-called-fix-2.patch mm-free-swp_entry-in-madvise_free.patch mm-move-lazy-free-pages-to-inactive-list.patch mm-move-lazy-free-pages-to-inactive-list-fix.patch mm-move-lazy-free-pages-to-inactive-list-fix-fix.patch mm-move-lazy-free-pages-to-inactive-list-fix-fix-fix.patch mm-make-every-pte-dirty-on-do_swap_page.patch
It's pretty large and has its sticky little paws in all sorts of places.
The feature would need to be pretty darn useful to justify a mainline merge. Has any such usefulness been demonstrated?
arch/alpha/include/uapi/asm/mman.h | 1 arch/mips/include/uapi/asm/mman.h | 1 arch/parisc/include/uapi/asm/mman.h | 1 arch/xtensa/include/uapi/asm/mman.h | 1 include/linux/huge_mm.h | 4 include/linux/rmap.h | 9 - include/linux/swap.h | 1 include/linux/vm_event_item.h | 1 include/uapi/asm-generic/mman-common.h | 1 mm/huge_memory.c | 35 ++++ mm/madvise.c | 175 +++++++++++++++++++++++ mm/memory.c | 10 + mm/rmap.c | 46 +++++- mm/swap.c | 44 +++++ mm/vmscan.c | 63 ++++++-- mm/vmstat.c | 1 16 files changed, 372 insertions(+), 22 deletions(-)
include/linux/rmap.h renamed from include/linux/rmap.h~mm-support-madvisemadv_free +7 -2
@@ -85,6 +85,7 @@ enum ttu_flags {TTU_UNMAP =1 ,/* unmap mode */ TTU_MIGRATION =2 ,/* migration mode */ TTU_MUNLOCK =4 ,/* munlock mode */ +TTU_FREE =8 ,/* free mode */ TTU_IGNORE_MLOCK = (1 <<8 ),/* ignore mlock */ TTU_IGNORE_ACCESS = (1 << 9), /* don't age */
@@ -183,7 +184,8 @@ static inline void page_dup_rmap(struct* Called from mm/vmscan.c to handle paging out */ int page_referenced (struct page *,int is_locked, -struct mem_cgroup *memcg,unsigned long *vm_flags); +struct mem_cgroup *memcg,unsigned long *vm_flags, +int *is_pte_dirty);#define TTU_ACTION (x) ((x) & TTU_ACTION_MASK)
@@ -260,9 +262,12 @@ int rmap_walk(struct page *page, structstatic inline int page_referenced (struct page *page,int is_locked,struct mem_cgroup *memcg, -unsigned long *vm_flags) +unsigned long *vm_flags, +int *is_pte_dirty) { *vm_flags =0 ; +if (is_pte_dirty) + *is_pte_dirty =0 ;return 0 ; }
include/linux/vm_event_item.h renamed from include/linux/vm_event_item.h~mm-support-madvisemadv_free +1 -0
@@ -25,6 +25,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSFOR_ALL_ZONES (PGALLOC ),PGFREE ,PGACTIVATE ,PGDEACTIVATE ,PGFAULT ,PGMAJFAULT , +PGLAZYFREED ,FOR_ALL_ZONES (PGREFILL ),FOR_ALL_ZONES (PGSTEAL_KSWAPD ), FOR_ALL_ZONES(PGSTEAL_DIRECT),
include/uapi/asm-generic/mman-common.h renamed from include/uapi/asm-generic/mman-common.h~mm-support-madvisemadv_free +1 -0
@@ -34,6 +34,7 @@#define MADV_SEQUENTIAL 2/* expect sequential page references */ #define MADV_WILLNEED 3/* will need these pages */ #define MADV_DONTNEED 4/* don't need these pages */ +#define MADV_FREE 5/* free pages only if memory pressure */ /* common parameters: try to keep these consistent across architectures */ #define MADV_REMOVE 9/* remove these pages & resources */
mm/madvise.c renamed from mm/madvise.c~mm-support-madvisemadv_free +175 -0
205 lines not on this page · raw message
mm/rmap.c renamed from mm/rmap.c~mm-support-madvisemadv_free +44 -2
124 lines not on this page · raw message
mm/vmscan.c renamed from mm/vmscan.c~mm-support-madvisemadv_free +47 -16
115 lines not on this page · raw message
mm/vmstat.c renamed from mm/vmstat.c~mm-support-madvisemadv_free +1 -0
@@ -759,6 +759,7 @@ const char * const vmstat_text[] = {"pgfault" ,"pgmajfault" , +"pglazyfreed" , TEXTS_FOR_ZONES("pgrefill")TEXTS_FOR_ZONES ("pgsteal_kswapd" )
arch/alpha/include/uapi/asm/mman.h renamed from arch/alpha/include/uapi/asm/mman.h~mm-support-madvisemadv_free +1 -0
@@ -44,6 +44,7 @@#define MADV_WILLNEED 3/* will need these pages */ #define MADV_SPACEAVAIL 5/* ensure resources are available */ #define MADV_DONTNEED 6/* don't need these pages */ +#define MADV_FREE 7/* free pages only if memory pressure */ /* common/generic parameters */ #define MADV_REMOVE 9/* remove these pages & resources */
arch/mips/include/uapi/asm/mman.h renamed from arch/mips/include/uapi/asm/mman.h~mm-support-madvisemadv_free +1 -0
@@ -67,6 +67,7 @@#define MADV_SEQUENTIAL 2/* expect sequential page references */ #define MADV_WILLNEED 3/* will need these pages */ #define MADV_DONTNEED 4/* don't need these pages */ +#define MADV_FREE 5/* free pages only if memory pressure */ /* common parameters: try to keep these consistent across architectures */ #define MADV_REMOVE 9/* remove these pages & resources */
arch/parisc/include/uapi/asm/mman.h renamed from arch/parisc/include/uapi/asm/mman.h~mm-support-madvisemadv_free +1 -0
@@ -40,6 +40,7 @@#define MADV_SPACEAVAIL 5/* insure that resources are reserved */ #define MADV_VPS_PURGE 6/* Purge pages from VM page cache */ #define MADV_VPS_INHERIT 7/* Inherit parents page size */ +#define MADV_FREE 8/* free pages only if memory pressure */ /* common/generic parameters */ #define MADV_REMOVE 9/* remove these pages & resources */
arch/xtensa/include/uapi/asm/mman.h renamed from arch/xtensa/include/uapi/asm/mman.h~mm-support-madvisemadv_free +1 -0
@@ -80,6 +80,7 @@#define MADV_SEQUENTIAL 2/* expect sequential page references */ #define MADV_WILLNEED 3/* will need these pages */ #define MADV_DONTNEED 4/* don't need these pages */ +#define MADV_FREE 5/* free pages only if memory pressure */ /* common parameters: try to keep these consistent across architectures */ #define MADV_REMOVE 9/* remove these pages & resources */
include/linux/huge_mm.h renamed from include/linux/huge_mm.h~mm-support-madvisemadv_free +4 -0
@@ -19,6 +19,9 @@ extern struct page *follow_trans_huge_pmunsigned long addr, pmd_t *pmd, unsigned int flags); +extern int madvise_free_huge_pmd (struct mmu_gather *tlb, +struct vm_area_struct *vma, +pmd_t *pmd,unsigned long addr);extern int zap_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr);
@@ -56,6 +59,7 @@ extern pmd_t *page_check_address_pmd(strunsigned long address, enum page_check_address_pmd_flag flag, spinlock_t **ptl); +extern int pmd_freeable (pmd_t pmd);#define HPAGE_PMD_ORDER (HPAGE_PMD_SHIFT-PAGE_SHIFT)#define HPAGE_PMD_NR (1<<HPAGE_PMD_ORDER)
mm/huge_memory.c renamed from mm/huge_memory.c~mm-support-madvisemadv_free +35 -0
@@ -1384,6 +1384,36 @@ out:return 0 ; } +int madvise_free_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma, +pmd_t *pmd,unsigned long addr) + +{ +spinlock_t *ptl; +struct mm_struct *mm = tlb->mm; +int ret =1 ; + +if (pmd_trans_huge_lock (pmd, vma, &ptl) ==1 ) { +struct page *page; +pmd_t orig_pmd; + + orig_pmd =pmdp_get_and_clear (mm, addr, pmd); + +/* No hugepage in swapcache */ + page =pmd_page (orig_pmd); +VM_BUG_ON_PAGE (PageSwapCache (page), page); + + orig_pmd =pmd_mkold (orig_pmd); + orig_pmd =pmd_mkclean (orig_pmd); + +set_pmd_at (mm, addr, pmd, orig_pmd); +tlb_remove_pmd_tlb_entry (tlb, pmd, addr); +spin_unlock (ptl); + ret =0 ; + } + +return ret; +} +int zap_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr) {
@@ -1599,6 +1629,11 @@ unlock:return NULL ; } +int pmd_freeable (pmd_t pmd) +{ +return !pmd_dirty (pmd); +} +static int __split_huge_page_splitting (struct page *page,struct vm_area_struct *vma,unsigned long address)
include/linux/swap.h renamed from include/linux/swap.h~mm-support-madvisemadv_free +1 -0
@@ -308,6 +308,7 @@ extern void lru_add_drain_cpu(int cpu);extern void lru_add_drain_all (void );extern void rotate_reclaimable_page (struct page *page);extern void deactivate_file_page (struct page *page); +extern void deactivate_page (struct page *page);extern void swap_setup (void );extern void add_page_to_unevictable_list (struct page *page);
mm/swap.c renamed from mm/swap.c~mm-support-madvisemadv_free +44 -0
74 lines not on this page · raw message
mm/memory.c renamed from mm/memory.c~mm-support-madvisemadv_free +8 -2
@@ -2555,9 +2555,15 @@ static int do_swap_page(struct mm_structinc_mm_counter_fast (mm,MM_ANONPAGES );dec_mm_counter_fast (mm,MM_SWAPENTS ); - pte =mk_pte (page, vma->vm_page_prot); + +/* +* The page is swapping in now was dirty before it was swapped out +* so restore the state again(ie, pte_mkdirty) because MADV_FREE +* relies on the dirty bit on page table. +*/ + pte =pte_mkdirty (mk_pte (page, vma->vm_page_prot));if ((flags &FAULT_FLAG_WRITE ) &&reuse_swap_page (page)) { - pte =maybe_mkwrite (pte_mkdirty (pte), vma); + pte =maybe_mkwrite (pte, vma); flags &= ~FAULT_FLAG_WRITE ; ret |=VM_FAULT_WRITE ; exclusive =1 ;
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Hello Andrew,
Quoted 22 lines · Andrew Morton
Quoted 1 line · On Thu, 9 Apr 2015 08:50:25 +0900 Minchan Kim <[email protected]> wrote:
Bump.
I'm getting the feeling that
MADV_FREEis out of control.Below is the overall rollup of
mm-support-madvisemadv_free.patch mm-support-madvisemadv_free-fix.patch mm-support-madvisemadv_free-fix-2.patch mm-dont-split-thp-page-when-syscall-is-called.patch mm-dont-split-thp-page-when-syscall-is-called-fix.patch mm-dont-split-thp-page-when-syscall-is-called-fix-2.patch mm-free-swp_entry-in-madvise_free.patch mm-move-lazy-free-pages-to-inactive-list.patch mm-move-lazy-free-pages-to-inactive-list-fix.patch mm-move-lazy-free-pages-to-inactive-list-fix-fix.patch mm-move-lazy-free-pages-to-inactive-list-fix-fix-fix.patch mm-make-every-pte-dirty-on-do_swap_page.patch
Quoted 5 lines
It's pretty large and has its sticky little paws in all sorts of places.
The feature would need to be pretty darn useful to justify a mainline merge. Has any such usefulness been demonstrated?
Jemalloc has used MADV_FREE instead of MADV_DONTNEED for a long time in MADV_FREE supporting OSes(FreeBSD, Solaris, Darwin, Windows). It used MADV_DONTNEED on only Linux because there was no the feature.
========================== &< ===========================
jemalloc:
/*
* Methods for purging unused pages differ between operating systems. *
* madvise(..., MADV_DONTNEED) : On Linux, this immediately discards pages,
* such that new pages will be demand-zeroed if
* the address region is later touched.
* madvise(..., MADV_FREE) : On FreeBSD and Darwin, this marks pages as being
* unused, such that they will be discarded rather
* than swapped out.
*/
...
boolpages_purge(void *addr, size_t length)
{
bool unzeroed;#ifdef _WIN32
VirtualAlloc(addr, length, MEM_RESET, PAGE_READWRITE);
unzeroed = true;#elif defined(JEMALLOC_HAVE_MADVISE)
# ifdef JEMALLOC_PURGE_MADVISE_DONTNEED
# define JEMALLOC_MADV_PURGE MADV_DONTNEED
# define JEMALLOC_MADV_ZEROS true
# elif defined(JEMALLOC_PURGE_MADVISE_FREE)
# define JEMALLOC_MADV_PURGE MADV_FREE
# define JEMALLOC_MADV_ZEROS false
# else
# error "No madvise(2) flag defined for purging unused dirty pages."
# endif
int err = madvise(addr, length, JEMALLOC_MADV_PURGE);
unzeroed = (!JEMALLOC_MADV_ZEROS || err != 0);
# undef JEMALLOC_MADV_PURGE
# undef JEMALLOC_MADV_ZEROS
#else
/* Last resort no-op. */
unzeroed = true;
#endif
return (unzeroed);
}Tcmalloc is same page.
========================== &< ===========================
// MADV_FREE is specifically designed for use by malloc(), but only // FreeBSD supports it; in linux we fall back to the somewhat inferior // MADV_DONTNEED.
#if !defined(MADV_FREE) && defined(MADV_DONTNEED)
# define MADV_FREE MADV_DONTNEED #endif
..
bool TCMalloc_SystemRelease(void* start, size_t length) { #ifdef MADV_FREE
if (FLAGS_malloc_devmem_start) {
// It's not safe to use MADV_FREE/MADV_DONTNEED if we've been
// mapping /dev/mem for heap memory.
return false; }
if (FLAGS_malloc_disable_memory_release) return false; if (pagesize == 0) pagesize = getpagesize(); const size_t pagemask = pagesize - 1;
size_t new_start = reinterpret_cast<size_t>(start); size_t end = new_start + length; size_t new_end = end;
// Round up the starting address and round down the ending address // to be page aligned:
new_start = (new_start + pagesize - 1) & ~pagemask; new_end = new_end & ~pagemask;
ASSERT((new_start & pagemask) == 0);
ASSERT((new_end & pagemask) == 0);
ASSERT(new_start >= reinterpret_cast<size_t>(start));
ASSERT(new_end <= end);
if (new_end > new_start) {
int result;
do {
result = madvise(reinterpret_cast<char*>(new_start),
new_end - new_start, MADV_FREE);
} while (result == -1 && errno == EAGAIN);return result != -1;
}
#endif
return false;
}
glibc want it, too.
https://sourceware.org/ml/libc-alpha/2015-02/msg00197.html
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
In reply to Andrew MortonQuoted 22 lines · Andrew Morton
Quoted 1 line · On Thu, 9 Apr 2015 08:50:25 +0900 Minchan Kim <[email protected]> wrote:
Bump.
I'm getting the feeling that
MADV_FREEis out of control.Below is the overall rollup of
mm-support-madvisemadv_free.patch mm-support-madvisemadv_free-fix.patch mm-support-madvisemadv_free-fix-2.patch mm-dont-split-thp-page-when-syscall-is-called.patch mm-dont-split-thp-page-when-syscall-is-called-fix.patch mm-dont-split-thp-page-when-syscall-is-called-fix-2.patch mm-free-swp_entry-in-madvise_free.patch mm-move-lazy-free-pages-to-inactive-list.patch mm-move-lazy-free-pages-to-inactive-list-fix.patch mm-move-lazy-free-pages-to-inactive-list-fix-fix.patch mm-move-lazy-free-pages-to-inactive-list-fix-fix-fix.patch mm-make-every-pte-dirty-on-do_swap_page.patch
Quoted 5 lines
It's pretty large and has its sticky little paws in all sorts of places.
The feature would need to be pretty darn useful to justify a mainline merge. Has any such usefulness been demonstrated?
The performance increase of MADV_FREE over MADV_DONTNEED is quite significant. I suspect this is especially important for mobile devices, which are more memory starved than desktop systems and servers.
Signature · 7 lines
All rights reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
In reply to Minchan KimQuoted 37 lines · Minchan Kim
Bascially,
MADV_FREErelys on the pte dirty to decide whether it allows VM to discard the page. However, if there is swap-in, pte pointed out the page has nopte_dirty. So,MADV_FREEchecks PageDirty and PageSwapCache for those pages to not discard it because swapped-in page could live on swap cache or PageDirty when it is removed from swapcache.The problem in here is that anonymous pages can have PageDirty if it is removed from swapcache so that VM cannot parse those pages as freeable even if we did
madvise_free. Look at below example.ptr =
malloc();
memset(ptr);
..
heavy memory pressure -> swap-out all of pages
..
out of memory pressure so there are lots of free pages
..
var = *ptr; -> swap-in page/remove the page from swapcache. sopte_clean
but SetPageDirty
madvise_free(ptr);
..
..
heavy memory pressure -> VM cannot discard the page by PageDirty.PageDirty for anonymous page aims for avoiding duplicating swapping out. In other words, if a page have swapped-in but live
swapcache(ie, !PageDirty), we could save swapout if the page is selected as victim by VM in future because swap device have kept previous swapped-out contents of the page.So, rather than relying on the
PG_dirtyfor workingmadvise_free,pte_dirtyis more straightforward. Inherently, swapped-out page waspte_dirtyso this patch restores the dirtiness when swap-in fault happens somadvise_freedoesn't rely on the PageDirty any more.
Quoted 5 lines
Cc Hugh Dickins <[email protected]>Cc Cyrill Gorcunov <[email protected]>Cc Pavel Emelyanov <[email protected]>Reported-by Yalin Wang <[email protected]>Signed-off-by Minchan Kim <[email protected]>
Sorry, but NAK to this patch, mm-make-every-pte-dirty-on-do_swap_page.patch in akpm's mm tree (I hope it hasn't reached linux-next yet).
You may well be right that pte_dirty<->PageDirty can be handled differently, in a way more favourable to MADV_FREE. And this patch may be a step in the right direction, but I've barely given it thought.
As it stands, it segfaults more than any patch I've seen in years:
I just tried applying it to 4.0-rc7-mm1, and running kernel builds in low memory with swap. Even if I leave KSM out, and memcg out, and swapoff out, and THP out, and tmpfs out, it still SIGSEGVs very soon.
I have a choice: spend a few hours tracking down the errors, and post a fix patch on top of yours? But even then I'd want to spend a lot longer thinking through every dirty/Dirty in the source before I'd feel comfortable to give an ack.
This is users' data, and we need to be very careful with it: errors in MADV_FREE are one thing, for now that's easy to avoid; but in this patch you're changing the rules for Anon PageDirty for everyone.
I think for now I'll have to leave it to you to do much more source diligence and testing, before coming back with a corrected patch for us then to review, slowly and carefully.
Hugh
Quoted 71 lines
--- mm/madvise.c | 1 - mm/memory.c | 9 +++++++-- mm/rmap.c | 2 +- mm/vmscan.c | 3 +-- 4 files changed, 9 insertions(+), 6 deletions(-)mm/madvise.c +0
-1@@ -325,7 +325,6 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,continue ; } -ClearPageDirty (page);unlock_page (page); }mm/memory.c +7
-2@@ -2521,9 +2521,14 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,inc_mm_counter_fast (mm,MM_ANONPAGES );dec_mm_counter_fast (mm,MM_SWAPENTS ); - pte =mk_pte (page, vma->vm_page_prot); + +/* +* Every page swapped-out was pte_dirty so we make pte dirty again. +* MADV_FREE relies on it. +*/ + pte =pte_mkdirty (mk_pte (page, vma->vm_page_prot));if ((flags &FAULT_FLAG_WRITE ) &&reuse_swap_page (page)) { - pte =maybe_mkwrite (pte_mkdirty (pte), vma); + pte =maybe_mkwrite (pte, vma); flags &= ~FAULT_FLAG_WRITE ; ret |=VM_FAULT_WRITE ; exclusive =1 ;mm/rmap.c +1
-1@@ -1268,7 +1268,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,if (flags &TTU_FREE ) {VM_BUG_ON_PAGE (PageSwapCache (page), page); -if (!dirty && !PageDirty (page)) { +if (!dirty) {/* It's a freeable page by MADV_FREE */ dec_mm_counter (mm,MM_ANONPAGES ); goto discard;mm/vmscan.c +1
-2@@ -805,8 +805,7 @@ static enum page_references page_check_references(struct page *page,return PAGEREF_KEEP ; } -if (PageAnon (page) && !pte_dirty && !PageSwapCache (page) && - !PageDirty (page)) +if (PageAnon (page) && !pte_dirty && !PageSwapCache (page)) *freeable = true;/* Reclaim if clean, defer dirty pages to writeback */ Signature · 1 line
1.9.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Hello Hugh,
Quoted 63 lines · Hugh Dickins
Quoted 37 lines · Minchan Kim
Bascially,
MADV_FREErelys on the pte dirty to decide whether it allows VM to discard the page. However, if there is swap-in, pte pointed out the page has nopte_dirty. So,MADV_FREEchecks PageDirty and PageSwapCache for those pages to not discard it because swapped-in page could live on swap cache or PageDirty when it is removed from swapcache.The problem in here is that anonymous pages can have PageDirty if it is removed from swapcache so that VM cannot parse those pages as freeable even if we did
madvise_free. Look at below example.ptr =
malloc();
memset(ptr);
..
heavy memory pressure -> swap-out all of pages
..
out of memory pressure so there are lots of free pages
..
var = *ptr; -> swap-in page/remove the page from swapcache. sopte_clean
but SetPageDirty
madvise_free(ptr);
..
..
heavy memory pressure -> VM cannot discard the page by PageDirty.PageDirty for anonymous page aims for avoiding duplicating swapping out. In other words, if a page have swapped-in but live
swapcache(ie, !PageDirty), we could save swapout if the page is selected as victim by VM in future because swap device have kept previous swapped-out contents of the page.So, rather than relying on the
PG_dirtyfor workingmadvise_free,pte_dirtyis more straightforward. Inherently, swapped-out page waspte_dirtyso this patch restores the dirtiness when swap-in fault happens somadvise_freedoesn't rely on the PageDirty any more.Quoted 5 lines
Cc Hugh Dickins <[email protected]>Cc Cyrill Gorcunov <[email protected]>Cc Pavel Emelyanov <[email protected]>Reported-by Yalin Wang <[email protected]>Signed-off-by Minchan Kim <[email protected]>Sorry, but NAK to this patch, mm-make-every-pte-dirty-on-do_swap_page.patch in akpm's mm tree (I hope it hasn't reached linux-next yet).
You may well be right that pte_dirty<->PageDirty can be handled differently, in a way more favourable to
MADV_FREE. And this patch may be a step in the right direction, but I've barely given it thought.As it stands, it segfaults more than any patch I've seen in years:
I just tried applying it to 4.0-rc7-mm1, and running kernel builds in low memory with swap. Even if I leave KSM out, and memcg out, and swapoff out, and THP out, and tmpfs out, it still SIGSEGVs very soon.I have a choice: spend a few hours tracking down the errors, and post a fix patch on top of yours? But even then I'd want to spend a lot longer thinking through every dirty/Dirty in the source before I'd feel comfortable to give an ack.
Quoted 7 lines
This is users' data, and we need to be very careful with it: errors in
MADV_FREEare one thing, for now that's easy to avoid; but in this patch you're changing the rules for Anon PageDirty for everyone.I think for now I'll have to leave it to you to do much more source diligence and testing, before coming back with a corrected patch for us then to review, slowly and carefully.
Sorry for my bad. I will keep your advise in mind. I will investigate the problem as soon as I get back to work after vacation.
Thanks for the the review.
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 4/4] mm: make every pte dirty on do_swap_page
Quoted 74 lines · Minchan Kim
Hello Hugh,
Quoted 63 lines · Hugh Dickins
Quoted 37 lines · Minchan Kim
Bascially,
MADV_FREErelys on the pte dirty to decide whether it allows VM to discard the page. However, if there is swap-in, pte pointed out the page has nopte_dirty. So,MADV_FREEchecks PageDirty and PageSwapCache for those pages to not discard it because swapped-in page could live on swap cache or PageDirty when it is removed from swapcache.The problem in here is that anonymous pages can have PageDirty if it is removed from swapcache so that VM cannot parse those pages as freeable even if we did
madvise_free. Look at below example.ptr =
malloc();
memset(ptr);
..
heavy memory pressure -> swap-out all of pages
..
out of memory pressure so there are lots of free pages
..
var = *ptr; -> swap-in page/remove the page from swapcache. sopte_clean
but SetPageDirty
madvise_free(ptr);
..
..
heavy memory pressure -> VM cannot discard the page by PageDirty.PageDirty for anonymous page aims for avoiding duplicating swapping out. In other words, if a page have swapped-in but live
swapcache(ie, !PageDirty), we could save swapout if the page is selected as victim by VM in future because swap device have kept previous swapped-out contents of the page.So, rather than relying on the
PG_dirtyfor workingmadvise_free,pte_dirtyis more straightforward. Inherently, swapped-out page waspte_dirtyso this patch restores the dirtiness when swap-in fault happens somadvise_freedoesn't rely on the PageDirty any more.Quoted 5 lines
Cc Hugh Dickins <[email protected]>Cc Cyrill Gorcunov <[email protected]>Cc Pavel Emelyanov <[email protected]>Reported-by Yalin Wang <[email protected]>Signed-off-by Minchan Kim <[email protected]>Sorry, but NAK to this patch, mm-make-every-pte-dirty-on-do_swap_page.patch in akpm's mm tree (I hope it hasn't reached linux-next yet).
You may well be right that pte_dirty<->PageDirty can be handled differently, in a way more favourable to
MADV_FREE. And this patch may be a step in the right direction, but I've barely given it thought.As it stands, it segfaults more than any patch I've seen in years:
I just tried applying it to 4.0-rc7-mm1, and running kernel builds in low memory with swap. Even if I leave KSM out, and memcg out, and swapoff out, and THP out, and tmpfs out, it still SIGSEGVs very soon.I have a choice: spend a few hours tracking down the errors, and post a fix patch on top of yours? But even then I'd want to spend a lot longer thinking through every dirty/Dirty in the source before I'd feel comfortable to give an ack.
Quoted 7 lines
This is users' data, and we need to be very careful with it: errors in
MADV_FREEare one thing, for now that's easy to avoid; but in this patch you're changing the rules for Anon PageDirty for everyone.I think for now I'll have to leave it to you to do much more source diligence and testing, before coming back with a corrected patch for us then to review, slowly and carefully.
Quoted 5 lines
Sorry for my bad. I will keep your advise in mind. I will investigate the problem as soon as I get back to work after vacation.
Thanks for the the review.
When I look at the code, migration doesn't restore dirty bit of pte in remove_migration_pte and relys on PG_dirty which was set by try_to_unmap_one. I think it was a reason you saw segfault. I will spend more time to investigate another code piece which might ignore dirty bit restore.
Thanks.
Quoted 4 lines
Signature · 3 lines
-- Kind regards, Minchan Kim
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Bump up.
Quoted 88 lines · Minchan Kim
When I test below piece of code with 12
processes(ie, 512M * 12 = 6G consume)on my (3G ram + 12 cpu + 8G swap, themadvise_freeis siginficat slower (ie, 2x times) thanmadvise_dontneed.loop = 5;
mmap(512M);while (loop--) { memset(512M); madvise(MADV_FREE or MADV_DONTNEED); }The reason is lots of swapin.
1) dontneed: 1,612 swapin
2) madvfree: 879,585 swapinIf we find hinted pages were already swapped out when syscall is called, it's pointless to keep the swapped-out pages in pte. Instead, let's free the cold page because swapin is more expensive than (alloc page + zeroing).
With this patch, it reduced swapin from 879,585 to 1,878 so elapsed time
1) dontneed: 6.10user 233.50system 0:50.44elapsed
2) madvfree: 6.03user 401.17system 1:30.67elapsed
2) madvfree + below patch: 6.70user 339.14system 1:04.45elapsedSigned-off-by Minchan Kim <[email protected]>--- mm/madvise.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-)mm/madvise.c +25
-1@@ -274,7 +274,9 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,spinlock_t *ptl;pte_t *pte, ptent;struct page *page; +swp_entry_t entry;unsigned long next; +int nr_swap =0 ; next =pmd_addr_end (addr, end);if (pmd_trans_huge (*pmd)) {@@ -293,8 +295,22 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,for (; addr != end; pte++, addr +=PAGE_SIZE ) { ptent = *pte; -if (!pte_present (ptent)) +if (pte_none (ptent))continue ; +/* +* If the pte has swp_entry, just clear page table to +* prevent swap-in which is more expensive rather than +* (page allocation + zeroing). +*/ +if (!pte_present (ptent)) { + entry =pte_to_swp_entry (ptent); +if (non_swap_entry (entry)) +continue ; + nr_swap--; +free_swap_and_cache (entry); +pte_clear_not_present_full (mm, addr, pte, tlb->fullmm); +continue ; + } page =vm_normal_page (vma, addr, ptent);if (!page)@@ -326,6 +342,14 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,set_pte_at (mm, addr, pte, ptent);tlb_remove_tlb_entry (tlb, pte, addr); } + +if (nr_swap) { +if (current->mm == mm) +sync_mm_rss (mm); + +add_mm_counter (mm,MM_SWAPENTS , nr_swap); + } +arch_leave_lazy_mmu_mode ();pte_unmap_unlock (pte -1 , ptl); next:Signature · 1 line
1.9.3
Signature · 8 lines
Kind regards, Minchan Kim -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>