MADV_FREE support
Subsystems (16)
v10 cover MADV_FREE support
This patch enable MADV_FREE hint for madvise syscall, which have been supported by other OSes. [PATCH 1] includes the details.
[1] support MADVISE_FREE for !THP page so if VM encounter THP page in syscall context, it splits THP page.
[2-6] is to preparing to call madvise syscall without THP plitting
[7] enable THP page support for MADV_FREE.
* From v9
* Add Acked-by - Rik
* Add THP page support - Kirill
* Rebased-on v3.16-rc3-mmotm-2014-07-02-15-07
* From v8
* Rebased-on v3.16-rc2-mmotm-2014-06-25-16-44
* From v7
* Rebased-on next-20140613
* From v6
* Remove page from swapcache in syscal time
* Move utility functions from memory.c to madvise.c - Johannes
* Rename untilify functtions - Johannes
* Remove unnecessary checks from vmscan.c - Johannes
* Rebased-on v3.15-rc5-mmotm-2014-05-16-16-56
* Drop Reviewe-by because there was some changes since then.
* From v5
* Fix PPC problem which don't flush TLB - Rik
* Remove unnecessary lazyfree_range stub function - Rik
* Rebased on v3.15-rc5
* From v4
* Add Reviewed-by: Zhang Yanfei
* Rebase on v3.15-rc1-mmotm-2014-04-15-16-14
* From v3
* Add "how to work part" in description - Zhang
* Add page_discardable utility function - Zhang
* Clean up
* From v2
* Remove forceful dirty marking of swap-readed page - Johannes
* Remove deactivation logic of lazyfreed page
* Rebased on 3.14
* Remove RFC tag
* From v1
* Use custom page table walker for madvise_free - Johannes
* Remove PG_lazypage flag - Johannes
* Do madvise_dontneed instead of madvise_freein swapless system
Minchan Kim (7):
[1] mm: support madvise(MADV_FREE)
[2] x86: add pmd_[dirty|mkclean] for THP
[3] sparc: add pmd_[dirty|mkclean] for THP
[4] powerpc: add pmd_[dirty|mkclean] for THP
[5] s390: add pmd_[dirty|mkclean] for THP
[6] ARM: add pmd_[dirty|mkclean] for THP
[7] mm: Don't split THP page when syscall is called
arch/arm64/include/asm/pgtable.h | 2 + arch/powerpc/include/asm/pgtable-ppc64.h | 2 + arch/s390/include/asm/pgtable.h | 12 ++ arch/sparc/include/asm/pgtable_64.h | 16 +++ arch/x86/include/asm/pgtable.h | 10 ++ include/linux/huge_mm.h | 3 + include/linux/rmap.h | 8 +- include/linux/vm_event_item.h | 1 + include/uapi/asm-generic/mman-common.h | 1 + mm/huge_memory.c | 25 ++++ mm/madvise.c | 189 +++++++++++++++++++++++++++++++ mm/rmap.c | 38 ++++++- mm/vmscan.c | 57 +++++++--- mm/vmstat.c | 1 + 14 files changed, 348 insertions(+), 17 deletions(-)
Signature · 7 lines
2.0.0 -- 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 v10 1/7 mm: support madvise(MADV_FREE)
Linux doesn't have an ability to free pages lazy while other OS already have been supported that named by madvise(MADV_FREE).
The gain is clear that kernel can discard freed pages rather than swapping out or OOM if memory pressure happens.
Without memory pressure, freed pages would be reused by userspace without another additional overhead(ex, page fault + allocation
+ zeroing).
How to work is following as.
When madvise syscall is called, VM clears dirty bit of ptes of the range. If memory pressure happens, VM checks dirty bit of page table and if it found still "clean", it means it's a "lazyfree pages" so VM could discard the page instead of swapping out. Once there was store operation for the page before VM peek a page to reclaim, dirty bit is set so VM can swap out the page instead of discarding.
Firstly, heavy users would be general allocators(ex, jemalloc, tcmalloc and hope glibc supports it) and jemalloc/tcmalloc already have supported the feature for other OS(ex, FreeBSD)
barrios@blaptop:~/benchmark/ebizzy$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 42 Stepping: 7 CPU MHz: 2801.000 BogoMIPS: 5581.64 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 4096K NUMA node0 CPU(s): 0-3
ebizzy benchmark(./ebizzy -S 10 -n 512)
vanilla-jemalloc MADV_free-jemalloc
1 thread
records: 10 records: 10 avg: 7682.10 avg: 15306.10 std: 62.35(0.81%) std: 347.99(2.27%) max: 7770.00 max: 15622.00 min: 7598.00 min: 14772.00
2 thread
records: 10 records: 10 avg: 12747.50 avg: 24171.00 std: 792.06(6.21%) std: 895.18(3.70%) max: 13337.00 max: 26023.00 min: 10535.00 min: 23152.00
4 thread
records: 10 records: 10 avg: 16474.60 avg: 33717.90 std: 1496.45(9.08%) std: 2008.97(5.96%) max: 17877.00 max: 35958.00 min: 12224.00 min: 29565.00
8 thread
records: 10 records: 10 avg: 16778.50 avg: 33308.10 std: 825.53(4.92%) std: 1668.30(5.01%) max: 17543.00 max: 36010.00 min: 14576.00 min: 29577.00
16 thread
records: 10 records: 10 avg: 20614.40 avg: 35516.30 std: 602.95(2.92%) std: 1283.65(3.61%) max: 21753.00 max: 37178.00 min: 19605.00 min: 33217.00
32 thread
records: 10 records: 10 avg: 22771.70 avg: 36018.50 std: 598.94(2.63%) std: 1046.76(2.91%) max: 24035.00 max: 37266.00 min: 22108.00 min: 34149.00
In summary, MADV_FREE is about 2 time faster than MADV_DONTNEED.
--- include/linux/rmap.h | 8 +- include/linux/vm_event_item.h | 1 + include/uapi/asm-generic/mman-common.h | 1 + mm/madvise.c | 174 +++++++++++++++++++++++++++++++++ mm/rmap.c | 34 ++++++- mm/vmscan.c | 37 +++++-- mm/vmstat.c | 1 + 7 files changed, 245 insertions(+), 11 deletions(-)
include/linux/rmap.h +6 -2
@@ -181,7 +181,8 @@ static inline void page_dup_rmap(struct page *page)* 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_dirty);#define TTU_ACTION (x) ((x) & TTU_ACTION_MASK)
@@ -260,9 +261,12 @@ int rmap_walk(struct page *page, struct rmap_walk_control *rwc);static 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 +1 -0
@@ -25,6 +25,7 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,FOR_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 +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 +174 -0
204 lines not on this page · raw message
mm/rmap.c +32 -2
@@ -663,6 +663,7 @@ int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma) }struct page_referenced_arg { +int dirtied;int mapcount;int referenced;unsigned long vm_flags;
@@ -677,6 +678,7 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,struct mm_struct *mm = vma->vm_mm;spinlock_t *ptl;int referenced =0 ; +int dirty =0 ;struct page_referenced_arg *pra = arg;if (unlikely (PageTransHuge (page))) {
@@ -729,6 +731,10 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,if (likely (!(vma->vm_flags &VM_SEQ_READ ))) referenced++; } + +if (pte_dirty (*pte)) + dirty++; +pte_unmap_unlock (pte, ptl); }
@@ -737,6 +743,9 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma, pra->vm_flags |= vma->vm_flags; } +if (dirty) + pra->dirtied++; + pra->mapcount--;if (!pra->mapcount)return SWAP_SUCCESS ;/* To break the loop */
@@ -761,6 +770,7 @@ static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg)* @is_locked: caller holds lock on the page * @memcg: target memory cgroup * @vm_flags: collect encountered vma->vm_flags who actually referenced the page +* @is_pte_dirty: ptes which have marked dirty bit - used for lazyfree page * * Quick test_and_clear_referenced for all mappings to a page, * returns the number of ptes which referenced the page.
@@ -768,7 +778,8 @@ static bool invalid_page_referenced_vma(struct vm_area_struct *vma, void *arg)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) {int ret;int we_locked =0 ;
@@ -783,6 +794,9 @@ int page_referenced(struct page *page, }; *vm_flags =0 ; +if (is_pte_dirty) + *is_pte_dirty =0 ; +if (!page_mapped (page))return 0 ;
@@ -810,6 +824,9 @@ int page_referenced(struct page *page,if (we_locked)unlock_page (page); +if (is_pte_dirty) + *is_pte_dirty = pra.dirtied; +return pra.referenced; }
@@ -1128,6 +1145,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,spinlock_t *ptl;int ret =SWAP_AGAIN ;enum ttu_flags flags = (enum ttu_flags )arg; +int dirty =0 ; pte =page_check_address (page, mm, address, &ptl,0 );if (!pte)
@@ -1157,7 +1175,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, pteval =ptep_clear_flush (vma, address, pte);/* Move the dirty bit to the physical page now the pte is gone. */ -if (pte_dirty (pteval)) + dirty =pte_dirty (pteval); +if (dirty)set_page_dirty (page);/* Update high watermark before we lower rss */
@@ -1204,6 +1223,16 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, }dec_mm_counter (mm,MM_ANONPAGES );inc_mm_counter (mm,MM_SWAPENTS ); + }else if (flags &TTU_UNMAP ) { +if (dirty ||PageDirty (page)) { +set_pte_at (mm, address, pte, pteval); + ret =SWAP_FAIL ; + goto out_unmap; + }else { +/* It's a freeable page by madvise_free */ +dec_mm_counter (mm,MM_ANONPAGES ); + goto discard; + } }else if (IS_ENABLED (CONFIG_MIGRATION )) {/* * Store the pfn of the page in a special migration
@@ -1227,6 +1256,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, }else dec_mm_counter (mm,MM_FILEPAGES ); +discard:page_remove_rmap (page);page_cache_release (page);
mm/vmscan.c +30 -7
@@ -707,13 +707,17 @@ enum page_references { };static enum page_references page_check_references (struct page *page, -struct scan_control *sc) +struct scan_control *sc, +bool *freeable) {int referenced_ptes, referenced_page;unsigned long vm_flags; +int pte_dirty; + +VM_BUG_ON_PAGE (!PageLocked (page), page); referenced_ptes =page_referenced (page,1 , sc->target_mem_cgroup, - &vm_flags); + &vm_flags, &pte_dirty); referenced_page =TestClearPageReferenced (page);/*
@@ -754,6 +758,10 @@ static enum page_references page_check_references(struct page *page,return PAGEREF_KEEP ; } +if (PageAnon (page) && !pte_dirty && !PageSwapCache (page) && + !PageDirty (page)) + *freeable = true; +/* Reclaim if clean, defer dirty pages to writeback */ if (referenced_page && !PageSwapBacked (page))return PAGEREF_RECLAIM_CLEAN ;
@@ -823,6 +831,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,int may_enter_fs;enum page_references references =PAGEREF_RECLAIM_CLEAN ;bool dirty, writeback; +bool freeable = false;cond_resched ();
@@ -945,7 +954,8 @@ static unsigned long shrink_page_list(struct list_head *page_list, }if (!force_reclaim) - references =page_check_references (page, sc); + references =page_check_references (page, sc, + &freeable);switch (references) {case PAGEREF_ACTIVATE :
@@ -961,7 +971,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,* Anonymous process memory has backing store? * Try to allocate it some swap space here. */ -if (PageAnon (page) && !PageSwapCache (page)) { +if (PageAnon (page) && !PageSwapCache (page) && !freeable) {if (!(sc->gfp_mask & __GFP_IO)) goto keep_locked;if (!add_to_swap (page, page_list))
@@ -976,7 +986,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,* The page is mapped into the page tables of one or more * processes. Try to unmap it here. */ -if (page_mapped (page) && mapping) { +if (page_mapped (page) && (mapping || freeable)) {switch (try_to_unmap (page, ttu_flags)) {case SWAP_FAIL : goto activate_locked;
@@ -985,7 +995,20 @@ static unsigned long shrink_page_list(struct list_head *page_list,case SWAP_MLOCK : goto cull_mlocked;case SWAP_SUCCESS : - ;/* try to free the page below */ +/* try to free the page below */ +if (!freeable) +break ; +/* +* Freeable anon page doesn't have mapping +* due to skipping of swapcache so we free +* page in here rather than __remove_mapping. +*/ +VM_BUG_ON_PAGE (PageSwapCache (page), page); +if (!page_freeze_refs (page,1 )) + goto keep_locked; +__clear_page_locked (page); +count_vm_event (PGLAZYFREED ); + goto free_it; } }
@@ -1727,7 +1750,7 @@ static void shrink_active_list(unsigned long nr_to_scan, }if (page_referenced (page,0 , sc->target_mem_cgroup, - &vm_flags)) { + &vm_flags,NULL )) { nr_rotated +=hpage_nr_pages (page);/* * Identify referenced, file-backed active pages and
mm/vmstat.c +1 -0
@@ -794,6 +794,7 @@ const char * const vmstat_text[] = {"pgfault" ,"pgmajfault" , +"pglazyfreed" , TEXTS_FOR_ZONES("pgrefill")TEXTS_FOR_ZONES ("pgsteal_kswapd" )
Signature · 7 lines
2.0.0 -- 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 v10 1/7] mm: support madvise(MADV_FREE)
Quoted 106 lines · Minchan Kim
Linux doesn't have an ability to free pages lazy while other OS already have been supported that named by
madvise(MADV_FREE).The gain is clear that kernel can discard freed pages rather than swapping out or OOM if memory pressure happens.
Without memory pressure, freed pages would be reused by userspace without another additional overhead(ex, page fault + allocation
+ zeroing).How to work is following as.
When madvise syscall is called, VM clears dirty bit of ptes of the range. If memory pressure happens, VM checks dirty bit of page table and if it found still "clean", it means it's a "lazyfree pages" so VM could discard the page instead of swapping out. Once there was store operation for the page before VM peek a page to reclaim, dirty bit is set so VM can swap out the page instead of discarding.
Firstly, heavy users would be general
allocators(ex, jemalloc, tcmalloc and hope glibc supports it)and jemalloc/tcmalloc already have supported the feature for otherOS(ex, FreeBSD)barrios@blaptop:~/benchmark/ebizzy$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 42 Stepping: 7 CPU MHz: 2801.000 BogoMIPS: 5581.64 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 4096K NUMA node0 CPU(s): 0-3ebizzy benchmark(./ebizzy -S 10 -n 512)
vanilla-jemalloc MADV_free-jemalloc
1 thread
records: 10 records: 10 avg: 7682.10 avg: 15306.10 std: 62.35(0.81%) std: 347.99(2.27%) max: 7770.00 max: 15622.00 min: 7598.00 min: 14772.002 thread
records: 10 records: 10 avg: 12747.50 avg: 24171.00 std: 792.06(6.21%) std: 895.18(3.70%) max: 13337.00 max: 26023.00 min: 10535.00 min: 23152.004 thread
records: 10 records: 10 avg: 16474.60 avg: 33717.90 std: 1496.45(9.08%) std: 2008.97(5.96%) max: 17877.00 max: 35958.00 min: 12224.00 min: 29565.008 thread
records: 10 records: 10 avg: 16778.50 avg: 33308.10 std: 825.53(4.92%) std: 1668.30(5.01%) max: 17543.00 max: 36010.00 min: 14576.00 min: 29577.0016 thread
records: 10 records: 10 avg: 20614.40 avg: 35516.30 std: 602.95(2.92%) std: 1283.65(3.61%) max: 21753.00 max: 37178.00 min: 19605.00 min: 33217.0032 thread
records: 10 records: 10 avg: 22771.70 avg: 36018.50 std: 598.94(2.63%) std: 1046.76(2.91%) max: 24035.00 max: 37266.00 min: 22108.00 min: 34149.00In summary,
MADV_FREEis about 2 time faster thanMADV_DONTNEED.Cc Michael Kerrisk <[email protected]>Cc Linux API <[email protected]>Cc Hugh Dickins <[email protected]>Cc Johannes Weiner <[email protected]>Cc KOSAKI Motohiro <[email protected]>Cc Mel Gorman <[email protected]>Cc Jason Evans <[email protected]>Cc Zhang Yanfei <[email protected]>Acked-by Rik van Riel <[email protected]>Signed-off-by Minchan Kim <[email protected]>---
...
Quoted 7 lines
mm/madvise.c +7
-0+static void madvise_free_page_range (struct mmu_gather *tlb, +struct vm_area_struct *vma, +unsigned long addr,unsigned long end) +{ +pgd_t *pgd; +unsigned long next; +
mm/madvise.c static long madvise_willneed(struct vm_area_struct *vma, · line 376
Quoted 10 lines
mm/madvise.c +10
-0+BUG_ON (addr >= end); +tlb_start_vma (tlb, vma); + pgd =pgd_offset (vma->vm_mm, addr); +do { + next =pgd_addr_end (addr, end); +if (pgd_none_or_clear_bad (pgd)) +continue ; + next =madvise_free_pud_range (tlb, vma, pgd, addr, next); + }while (pgd++, addr = next, addr != end); +tlb_end_vma (tlb, vma);
Any particular reason why pagewalker can't be used here?
Quoted 1 line
+}
...
mm/madvise.c madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, · line 556
Quoted 11 lines
mm/madvise.c +7
-0@@ -381,6 +547,13 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,return madvise_remove (vma, prev, start, end);case MADV_WILLNEED :return madvise_willneed (vma, prev, start, end); +case MADV_FREE : +/* +* XXX: In this implementation, MADV_FREE works like +* MADV_DONTNEED on swapless system or full swap. +*/ +if (get_nr_swap_pages () >0 ) +return madvise_free (vma, prev, start, end);
Looks racy wrt to full swap. What will happen if we will do madvise_free() on full swap?
Quoted 3 lines
mm/madvise.c +0
-0case MADV_DONTNEED :return madvise_dontneed (vma, prev, start, end);default :
...
mm/rmap.c static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, · line 1230
Quoted 9 lines
mm/rmap.c +5
-0@@ -1204,6 +1223,16 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, }dec_mm_counter (mm,MM_ANONPAGES );inc_mm_counter (mm,MM_SWAPENTS ); + }else if (flags &TTU_UNMAP ) { +if (dirty ||PageDirty (page)) { +set_pte_at (mm, address, pte, pteval); + ret =SWAP_FAIL ; + goto out_unmap;
I don't get this part.
Looks like it will fail to unmap the page if it's dirty and not backed by swapcache. Current code doesn't have such limitation.
Do we really need this?
Quoted 8 lines
mm/rmap.c +5
-0+ }else { +/* It's a freeable page by madvise_free */ +dec_mm_counter (mm,MM_ANONPAGES ); + goto discard; + } }else if (IS_ENABLED (CONFIG_MIGRATION )) {/* * Store the pfn of the page in a special migration
Signature · 7 lines
Kirill A. Shutemov -- 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 v10 1/7] mm: support madvise(MADV_FREE)
Quoted 121 lines · Kirill A. Shutemov
Quoted 106 lines · Minchan Kim
Linux doesn't have an ability to free pages lazy while other OS already have been supported that named by
madvise(MADV_FREE).The gain is clear that kernel can discard freed pages rather than swapping out or OOM if memory pressure happens.
Without memory pressure, freed pages would be reused by userspace without another additional overhead(ex, page fault + allocation
+ zeroing).How to work is following as.
When madvise syscall is called, VM clears dirty bit of ptes of the range. If memory pressure happens, VM checks dirty bit of page table and if it found still "clean", it means it's a "lazyfree pages" so VM could discard the page instead of swapping out. Once there was store operation for the page before VM peek a page to reclaim, dirty bit is set so VM can swap out the page instead of discarding.
Firstly, heavy users would be general
allocators(ex, jemalloc, tcmalloc and hope glibc supports it)and jemalloc/tcmalloc already have supported the feature for otherOS(ex, FreeBSD)barrios@blaptop:~/benchmark/ebizzy$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 2 Core(s) per socket: 2 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 42 Stepping: 7 CPU MHz: 2801.000 BogoMIPS: 5581.64 Virtualization: VT-x L1d cache: 32K L1i cache: 32K L2 cache: 256K L3 cache: 4096K NUMA node0 CPU(s): 0-3ebizzy benchmark(./ebizzy -S 10 -n 512)
vanilla-jemalloc MADV_free-jemalloc
1 thread
records: 10 records: 10 avg: 7682.10 avg: 15306.10 std: 62.35(0.81%) std: 347.99(2.27%) max: 7770.00 max: 15622.00 min: 7598.00 min: 14772.002 thread
records: 10 records: 10 avg: 12747.50 avg: 24171.00 std: 792.06(6.21%) std: 895.18(3.70%) max: 13337.00 max: 26023.00 min: 10535.00 min: 23152.004 thread
records: 10 records: 10 avg: 16474.60 avg: 33717.90 std: 1496.45(9.08%) std: 2008.97(5.96%) max: 17877.00 max: 35958.00 min: 12224.00 min: 29565.008 thread
records: 10 records: 10 avg: 16778.50 avg: 33308.10 std: 825.53(4.92%) std: 1668.30(5.01%) max: 17543.00 max: 36010.00 min: 14576.00 min: 29577.0016 thread
records: 10 records: 10 avg: 20614.40 avg: 35516.30 std: 602.95(2.92%) std: 1283.65(3.61%) max: 21753.00 max: 37178.00 min: 19605.00 min: 33217.0032 thread
records: 10 records: 10 avg: 22771.70 avg: 36018.50 std: 598.94(2.63%) std: 1046.76(2.91%) max: 24035.00 max: 37266.00 min: 22108.00 min: 34149.00In summary,
MADV_FREEis about 2 time faster thanMADV_DONTNEED.Cc Michael Kerrisk <[email protected]>Cc Linux API <[email protected]>Cc Hugh Dickins <[email protected]>Cc Johannes Weiner <[email protected]>Cc KOSAKI Motohiro <[email protected]>Cc Mel Gorman <[email protected]>Cc Jason Evans <[email protected]>Cc Zhang Yanfei <[email protected]>Acked-by Rik van Riel <[email protected]>Signed-off-by Minchan Kim <[email protected]>---
...
Quoted 11 lines
(quoted diff) +11
-0+static void madvise_free_page_range(struct mmu_gather *tlb, + struct vm_area_struct *vma, + unsigned long addr, unsigned long end) +{ + pgd_t *pgd; + unsigned long next; + + BUG_ON(addr >= end); + tlb_start_vma(tlb, vma); + pgd = pgd_offset(vma->vm_mm, addr); + do {
Quoted 8 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ next = pgd_addr_end(addr, end); + if (pgd_none_or_clear_bad(pgd)) + continue; + next = madvise_free_pud_range(tlb, vma, pgd, addr, next); + } while (pgd++, addr = next, addr != end); + tlb_end_vma(tlb, vma);Any particular reason why pagewalker can't be used here?
Nothing special. I just copied from MADV_DONTNEED. Will try it.
Quoted 5 lines
Quoted 2 lines
+}
...
Quoted 14 lines
Review madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, · line 556
Quoted 11 lines
(quoted diff) +7
-0@@ -381,6 +547,13 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, return madvise_remove(vma, prev, start, end); case MADV_WILLNEED: return madvise_willneed(vma, prev, start, end); + case MADV_FREE: + /* + * XXX: In this implementation, MADV_FREE works like + * MADV_DONTNEED on swapless system or full swap. + */ + if (get_nr_swap_pages() > 0) + return madvise_free(vma, prev, start, end);Looks racy wrt to full swap. What will happen if we will do
madvise_free()on full swap?
Now, we don't age anonymous LRU list if swap is full so that VM would lose the chance to discard freed page via shrink_page_list in this implementation if that race hppanes.
But it would be not severe because MADV_FREE semantic doesn't say VM must discard them but it is just hint from userside that specified range is no longer important so that VM can gave a freedom to free and I think it's not a common case.
In addition, I have a plan to support MADV_FREE on swapless system, too.
Quoted 7 lines
Quoted 4 lines
(quoted diff) +0
-0case MADV_DONTNEED: return madvise_dontneed(vma, prev, start, end); default:...
Quoted 14 lines
Review static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, · line 1230
Quoted 9 lines
(quoted diff) +5
-0@@ -1204,6 +1223,16 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, } dec_mm_counter(mm, MM_ANONPAGES); inc_mm_counter(mm, MM_SWAPENTS); + } else if (flags & TTU_UNMAP) { + if (dirty || PageDirty(page)) { + set_pte_at(mm, address, pte, pteval); + ret = SWAP_FAIL; + goto out_unmap;I don't get this part.
Looks like it will fail to unmap the page if it's dirty and not backed by swapcache. Current code doesn't have such limitation.
Do we really need this?
Good point. Code is rather ugly even, it has side-effect with hwpoisend page unmapping.
How about this? I didn't test it but if there is no objection, I will go this with stress testing.
--- include/linux/rmap.h | 1 + mm/rmap.c | 22 ++++++++++++---------- mm/vmscan.c | 5 +++-- 3 files changed, 16 insertions(+), 12 deletions(-)
include/linux/rmap.h +1 -0
@@ -75,6 +75,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 */
mm/rmap.c +12 -10
@@ -1209,6 +1209,18 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,swp_entry_t entry = { .val =page_private (page) };pte_t swp_pte; +if (flags &TTU_FREE ) { +if (dirty ||PageDirty (page)) { +set_pte_at (mm, address, pte, pteval); + ret =SWAP_FAIL ; + goto out_unmap; + }else { +/* It's a freeable page by MADV_FREE */ +dec_mm_counter (mm,MM_ANONPAGES ); + goto discard; + } + } +if (PageSwapCache (page)) {/* * Store the swap location in the pte.
@@ -1227,16 +1239,6 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, }dec_mm_counter (mm,MM_ANONPAGES );inc_mm_counter (mm,MM_SWAPENTS ); - }else if (flags &TTU_UNMAP ) { -if (dirty ||PageDirty (page)) { -set_pte_at (mm, address, pte, pteval); - ret =SWAP_FAIL ; - goto out_unmap; - }else { -/* It's a freeable page by madvise_free */ -dec_mm_counter (mm,MM_ANONPAGES ); - goto discard; - } }else if (IS_ENABLED (CONFIG_MIGRATION )) {/* * Store the pfn of the page in a special migration
mm/vmscan.c +3 -2
@@ -1549,8 +1549,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,if (nr_taken ==0 )return 0 ; - nr_reclaimed =shrink_page_list (&page_list, zone, sc,TTU_UNMAP , - &nr_dirty, &nr_unqueued_dirty, &nr_congested, + nr_reclaimed =shrink_page_list (&page_list, zone, sc, +TTU_UNMAP |TTU_FREE , &nr_dirty, + &nr_unqueued_dirty, &nr_congested, &nr_writeback, &nr_immediate, false);
Signature · 1 line
2.0.0
Quoted 18 lines
Quoted 9 lines
(quoted diff) +5
-0+ } else { + /* It's a freeable page by madvise_free */ + dec_mm_counter(mm, MM_ANONPAGES); + goto discard; + } } else if (IS_ENABLED(CONFIG_MIGRATION)) { /* * Store the pfn of the page in a special migrationSignature · 7 lines
Kirill A. Shutemov -- 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>
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 v10 1/7] mm: support madvise(MADV_FREE)
In reply to Minchan KimHi Minchan,
Quoted 6 lines · Minchan Kim
Linux doesn't have an ability to free pages lazy while other OS already have been supported that named by
madvise(MADV_FREE).The gain is clear that kernel can discard freed pages rather than swapping out or OOM if memory pressure happens.
Quoted 8 lines
Without memory pressure, freed pages would be reused by userspace without another additional overhead(ex, page fault + allocation
+ zeroing).How to work is following as.
When madvise syscall is called, VM clears dirty bit of ptes of the range.
This should be updated because the implementation has been changed. It also remove the page from the swapcache if it is.
Thank you for your effort!
Signature · 2 lines
Thanks. Zhang Yanfei
Re: [PATCH v10 1/7] mm: support madvise(MADV_FREE)
Hello Zhang,
Quoted 13 lines · Zhang Yanfei
Hi Minchan,
Quoted 10 lines · Minchan Kim
Linux doesn't have an ability to free pages lazy while other OS already have been supported that named by
madvise(MADV_FREE).The gain is clear that kernel can discard freed pages rather than swapping out or OOM if memory pressure happens.
Without memory pressure, freed pages would be reused by userspace without another additional overhead(ex, page fault + allocation
+ zeroing).
Quoted 7 lines
Quoted 4 lines
How to work is following as.
When madvise syscall is called, VM clears dirty bit of ptes of the range.
This should be updated because the implementation has been changed. It also remove the page from the swapcache if it is.
You're right in current implementation but it's rather one of implementation technique(ie, it could be changed later) but still main main logic from MADV_FREE is tightly coupled with pte dirty bit so I don't feel I added it in description but it would be better to add it as comment.
Thanks for the review!
Quoted 12 lines
Thank you for your effort!
Signature · 8 lines
Thanks. Zhang Yanfei -- 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>
Signature · 2 lines
Kind regards, Minchan Kim
PATCH v10 2/7 x86: add pmd_[dirty|mkclean] for THP
In reply to Minchan KimMADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent overwrite of the contents since MADV_FREE syscall is called for THP page.
This patch adds pmd_dirty and pmd_mkclean for THP page MADV_FREE support.
--- arch/x86/include/asm/pgtable.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
arch/x86/include/asm/pgtable.h +10 -0
@@ -104,6 +104,11 @@ static inline int pmd_young(pmd_t pmd)return pmd_flags (pmd) & _PAGE_ACCESSED; } +static inline int pmd_dirty (pmd_t pmd) +{ +return pmd_flags (pmd) & _PAGE_DIRTY; +} +static inline int pte_write (pte_t pte) {return pte_flags (pte) & _PAGE_RW;
@@ -267,6 +272,11 @@ static inline pmd_t pmd_mkold(pmd_t pmd)return pmd_clear_flags (pmd, _PAGE_ACCESSED); } +static inline pmd_t pmd_mkclean (pmd_t pmd) +{ +return pmd_clear_flags (pmd, _PAGE_DIRTY); +} +static inline pmd_t pmd_wrprotect (pmd_t pmd) {return pmd_clear_flags (pmd, _PAGE_RW);
Signature · 7 lines
2.0.0 -- 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 v10 2/7] x86: add pmd_[dirty|mkclean] for THP
Quoted 4 lines · Minchan Kim
MADV_FREEneedspmd_dirtyandpmd_mkcleanfor detecting recent overwrite of the contents sinceMADV_FREEsyscall is called for THP page.
Quoted 8 lines
This patch adds
pmd_dirtyandpmd_mkcleanfor THP pageMADV_FREEsupport.Cc Thomas Gleixner <[email protected]>Cc Ingo Molnar <[email protected]>Cc "H. Peter Anvin" <[email protected]>Signed-off-by Minchan Kim <[email protected]>
Signature · 7 lines
Kirill A. Shutemov -- 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 v10 3/7 sparc: add pmd_[dirty|mkclean] for THP
In reply to Minchan KimMADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent overwrite of the contents since MADV_FREE syscall is called for THP page.
This patch adds pmd_dirty and pmd_mkclean for THP page MADV_FREE support.
--- arch/sparc/include/asm/pgtable_64.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
arch/sparc/include/asm/pgtable_64.h +16 -0
@@ -666,6 +666,13 @@ static inline unsigned long pmd_young(pmd_t pmd)return pte_young (pte); } +static inline int pmd_dirty (pmd_t pmd) +{ +pte_t pte =__pte (pmd_val (pmd)); + +return pte_dirty (pte); +} +static inline unsigned long pmd_write (pmd_t pmd) {pte_t pte =__pte (pmd_val (pmd));
@@ -723,6 +730,15 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)return __pmd (pte_val (pte)); } +static inline pmd_mkclean(pmd_t pmd) +{ +pte_t pte =__pte (pmd_val (pmd)); + + pte =pte_mkclean (pte); + +return __pmd (pte_val (pte)); +} +static inline pmd_t pmd_mkyoung (pmd_t pmd) {pte_t pte =__pte (pmd_val (pmd));
Signature · 7 lines
2.0.0 -- 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 v10 4/7 powerpc: add pmd_[dirty|mkclean] for THP
In reply to Minchan KimMADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent overwrite of the contents since MADV_FREE syscall is called for THP page.
This patch adds pmd_dirty and pmd_mkclean for THP page MADV_FREE support.
--- arch/powerpc/include/asm/pgtable-ppc64.h | 2 ++ 1 file changed, 2 insertions(+)
arch/powerpc/include/asm/pgtable-ppc64.h +2 -0
@@ -468,9 +468,11 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)#define pmd_pfn (pmd) pte_pfn(pmd_pte(pmd))#define pmd_young (pmd) pte_young(pmd_pte(pmd)) +#define pmd_dirty (pmd) pte_dirty(pmd_pte(pmd))#define pmd_mkold (pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))#define pmd_wrprotect (pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))#define pmd_mkdirty (pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) +#define pmd_mkclean (pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))#define pmd_mkyoung (pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))#define pmd_mkwrite (pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
Signature · 1 line
2.0.0
PATCH v10 5/7 s390: add pmd_[dirty|mkclean] for THP
In reply to Minchan KimMADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent overwrite of the contents since MADV_FREE syscall is called for THP page but for s390 pmds only referenced bit is available because there is no free bit left in the pmd entry for the software dirty bit so this patch adds dumb pmd_dirty which returns always true by suggesting by Martin.
They finally find a solution in future.
http://marc.info/?l=linux-api&m=140440328820808&w=2
--- arch/s390/include/asm/pgtable.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
arch/s390/include/asm/pgtable.h +12 -0
@@ -1586,6 +1586,18 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)return pmd; } +static inline int pmd_dirty (pmd_t pmd) +{ +/* No dirty bit in the segment table entry */ +return 1 ; +} + +static inline pmd_t pmd_mkclean (pmd_t pmd) +{ +/* No dirty bit in the segment table entry */ +return pmd; +} +#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNGstatic inline int pmdp_test_and_clear_young (struct vm_area_struct *vma,unsigned long address,pmd_t *pmdp)
Signature · 7 lines
2.0.0 -- 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 v10 5/7] s390: add pmd_[dirty|mkclean] for THP
Quoted 17 lines · On Mon, 7 Jul 2014 09:53:56 +0900 Minchan Kim…
MADV_FREEneedspmd_dirtyandpmd_mkcleanfor detecting recent overwrite of the contents sinceMADV_FREEsyscall is called for THP page but for s390 pmds only referenced bit is available because there is no free bit left in the pmd entry for the software dirty bit so this patch adds dumbpmd_dirtywhich returns always true by suggesting by Martin.They finally find a solution in future.
http://marc.info/?l=linux-api&m=140440328820808&w=2Cc Martin Schwidefsky <[email protected]>Cc Heiko Carstens <[email protected]>Cc Gerald Schaefer <[email protected]>Cc Dominik Dingel <[email protected]>Cc Christian Borntraeger <[email protected]>Signed-off-by Minchan Kim <[email protected]>
Quoted 3 lines
--- arch/s390/include/asm/pgtable.h | 12 ++++++++++++ 1 file changed, 12 insertions(+)
PATCH v10 6/7 ARM: add pmd_[dirty|mkclean] for THP
In reply to Minchan KimMADV_FREE needs pmd_dirty and pmd_mkclean for detecting recent overwrite of the contents since MADV_FREE syscall is called for THP page.
This patch adds pmd_dirty and pmd_mkclean for THP page MADV_FREE support.
--- arch/arm64/include/asm/pgtable.h | 2 ++ 1 file changed, 2 insertions(+)
arch/arm64/include/asm/pgtable.h +2 -0
@@ -240,10 +240,12 @@ static inline pmd_t pte_pmd(pte_t pte)#endif #define pmd_young (pmd) pte_young(pmd_pte(pmd)) +#define pmd_dirty (pmd) pte_dirty(pmd_pte(pmd))#define pmd_wrprotect (pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))#define pmd_mksplitting (pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))#define pmd_mkold (pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))#define pmd_mkwrite (pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) +#define pmd_mkclean (pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))#define pmd_mkdirty (pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))#define pmd_mkyoung (pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))#define pmd_mknotpresent (pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))
Signature · 7 lines
2.0.0 -- 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 v10 6/7] ARM: add pmd_[dirty|mkclean] for THP
Quoted 6 lines · Minchan Kim
MADV_FREEneedspmd_dirtyandpmd_mkcleanfor detecting recent overwrite of the contents sinceMADV_FREEsyscall is called for THP page.This patch adds
pmd_dirtyandpmd_mkcleanfor THP pageMADV_FREEsupport.
Looks fine to me, but it would be good if Steve can take a look too.
BTW: the subject of the patch says 'ARM:' but this only affects arm64. Is there a corresponding patch for arch/arm/ too?
Will
Re: [PATCH v10 6/7] ARM: add pmd_[dirty|mkclean] for THP
In reply to Minchan KimQuoted 37 lines · Minchan Kim
MADV_FREEneedspmd_dirtyandpmd_mkcleanfor detecting recent overwrite of the contents sinceMADV_FREEsyscall is called for THP page.This patch adds
pmd_dirtyandpmd_mkcleanfor THP pageMADV_FREEsupport.Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>Cc Steve Capper <[email protected]>Cc Russell King <linux-lFZ/[email protected]>Cc linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.orgSigned-off-by Minchan Kim <[email protected]>--- arch/arm64/include/asm/pgtable.h | 2 ++ 1 file changed, 2 insertions(+)arch/arm64/include/asm/pgtable.h +2
-0@@ -240,10 +240,12 @@ static inline pmd_t pte_pmd(pte_t pte)#endif #define pmd_young (pmd) pte_young(pmd_pte(pmd)) +#define pmd_dirty (pmd) pte_dirty(pmd_pte(pmd))#define pmd_wrprotect (pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))#define pmd_mksplitting (pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))#define pmd_mkold (pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))#define pmd_mkwrite (pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) +#define pmd_mkclean (pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))#define pmd_mkdirty (pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))#define pmd_mkyoung (pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))#define pmd_mknotpresent (pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))Signature · 1 line
2.0.0
Hi Minchan,
This looks good to me too.
As Will said this applies to arm64, we will also need a version for:arch/arm/include/asm/pgtable-3level.h.
Is there a testcase we can run to check that this patch set is working well for arm/arm64?
Cheers,
Signature · 1 line
Steve
Re: [PATCH v10 6/7] ARM: add pmd_[dirty|mkclean] for THP
Quoted 25 lines · Steve Capper
Quoted 24 lines · Minchan Kim
MADV_FREEneedspmd_dirtyandpmd_mkcleanfor detecting recent overwrite of the contents sinceMADV_FREEsyscall is called for THP page.This patch adds
pmd_dirtyandpmd_mkcleanfor THP pageMADV_FREEsupport.Cc Catalin Marinas <[email protected]>Cc Will Deacon <[email protected]>Cc Steve Capper <[email protected]>Cc Russell King <[email protected]>Signed-off-by Minchan Kim <[email protected]>--- arch/arm64/include/asm/pgtable.h | 2 ++ 1 file changed, 2 insertions(+)arch/arm64/include/asm/pgtable.h +0
-0@@ -240,10 +240,12 @@ static inline pmd_t pte_pmd(pte_t pte)#endif
Quoted 15 lines
Quoted 13 lines
arch/arm64/include/asm/pgtable.h +2
-0#define pmd_young (pmd) pte_young(pmd_pte(pmd)) +#define pmd_dirty (pmd) pte_dirty(pmd_pte(pmd))#define pmd_wrprotect (pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))#define pmd_mksplitting (pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))#define pmd_mkold (pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))#define pmd_mkwrite (pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) +#define pmd_mkclean (pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))#define pmd_mkdirty (pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))#define pmd_mkyoung (pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))#define pmd_mknotpresent (pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))Signature · 1 line
2.0.0Hi Minchan,
Hello Steve and Will,
Quoted 4 lines
This looks good to me too.
As Will said this applies to arm64, we will also need a version for:arch/arm/include/asm/pgtable-3level.h.
Does it work?
arch/arm/include/asm/pgtable-3level.h +3 -0
@@ -220,6 +220,8 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)#define pmd_trans_splitting (pmd) (pmd_val(pmd) & PMD_SECT_SPLITTING)#endif +#define pmd_dirty (pmd_val(pmd) & PMD_SECT_DIRTY) +#define PMD_BIT_FUNC (fn,op) \ static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
@@ -228,6 +230,7 @@ PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF); PMD_BIT_FUNC(mksplitting, |= PMD_SECT_SPLITTING); PMD_BIT_FUNC(mkwrite, &= ~PMD_SECT_RDONLY); PMD_BIT_FUNC(mkdirty, |= PMD_SECT_DIRTY); +PMD_BIT_FUNC(mkclean, &= ~PMD_SECT_DIRTY); PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);#define pmd_mkhuge (pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
Signature · 1 line
2.0.0
Quoted 3 lines
Is there a testcase we can run to check that this patch set is working well for arm/arm64?
I just run several instance of attached simple stress with heavy kernel build in parallel on 1G RAM machine.
Thanks for the review!
Quoted 10 lines
Cheers,
Signature · 7 lines
Steve -- 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>
Signature · 2 lines
Kind regards, Minchan Kim
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#define CHUNK_SIZE (20<<20)
#define SLEEP_TIME_SEC 2
#define NUM_THREAD 12
#define QUIT 1000
int quit;
void alloc_thp()
{
int i;
int ret;
char *ptr;
/* should be aligned with 2M which is THP page size */
ret = posix_memalign((void**)&ptr, 2<<20, CHUNK_SIZE);
if (ret) {
fprintf(stderr, "fail to allocate\n");
return;
}
memset(ptr, 'a', CHUNK_SIZE);
ret = madvise(ptr, CHUNK_SIZE, 5);
if (ret) {
perror("fail to madvise");
return;
}
sleep(SLEEP_TIME_SEC);
memset(ptr, 'b', CHUNK_SIZE);
sleep(SLEEP_TIME_SEC);
for (i = 0; i < CHUNK_SIZE; i++) {
if (ptr[i] != 'b') {
fprintf(stderr, "fail to verify\n");
fprintf(stderr, "Something wrong\n");
return;
}
}
free(ptr);
}void *thread_alloc(void *priv)
{
int n = 0;
while(!quit) {
alloc_thp();
if (!(n++ % 5))
printf("I'm working\n");
if (n == QUIT)
return;
}
}int main()
{
int i, ret;
pthread_t thread[NUM_THREAD];
for (i = 0; i < NUM_THREAD; i++) {
ret = pthread_create(&thread[i], NULL, thread_alloc, NULL);
if (ret) {
perror("fail to create thread\n");
return 1;
}
}
scanf("%d", &quit);
for (i = 0; i < NUM_THREAD; i++)
pthread_join(thread[i], NULL);
printf("Test Done\n");
return 0;
}PATCH v10 7/7 mm: Don't split THP page when syscall is called
In reply to Minchan KimWe don't need to split THP page when MADV_FREE syscall is called. It could be done when VM decide really frees it so we could reduce the number of THP split.
--- include/linux/huge_mm.h | 3 +++ mm/huge_memory.c | 25 +++++++++++++++++++++++++ mm/madvise.c | 19 +++++++++++++++++-- mm/rmap.c | 4 ++++ mm/vmscan.c | 24 ++++++++++++++++-------- 5 files changed, 65 insertions(+), 10 deletions(-)
include/linux/huge_mm.h +3 -0
@@ -19,6 +19,9 @@ extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,unsigned long addr, pmd_t *pmd, unsigned int flags); +extern int madvise_free_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);
mm/huge_memory.c +25 -0
@@ -1384,6 +1384,31 @@ out:return 0 ; } +int madvise_free_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma, +pmd_t *pmd,unsigned long addr) +{ +spinlock_t *ptl; +int ret =0 ; + +if (__pmd_trans_huge_lock (pmd, vma, &ptl) ==1 ) { +pmd_t orig_pmd; +struct mm_struct *mm = vma->vm_mm; + +/* No hugepage in swapcache */ +VM_BUG_ON (PageSwapCache (pmd_page (orig_pmd))); + + orig_pmd =pmdp_get_and_clear (tlb->mm, addr, pmd); + 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 =1 ; + } +return ret; +} +int zap_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr) {
mm/madvise.c +17 -2
@@ -320,8 +320,23 @@ static inline unsigned long madvise_free_pmd_range(struct mmu_gather *tlb,* if the range covers. */ next =pmd_addr_end (addr, end); -if (pmd_trans_huge (*pmd)) -split_huge_page_pmd (vma, addr, pmd); +if (pmd_trans_huge (*pmd)) { +if (next - addr !=HPAGE_PMD_SIZE ) { +#ifdef CONFIG_DEBUG_VM +if (!rwsem_is_locked (&tlb->mm->mmap_sem)) { +pr_err ("%s: mmap_sem is unlocked! addr=0x%lx end=0x%lx vma->vm_start=0x%lx vma->vm_end=0x%lx\n" , + __func__, addr, end, + vma->vm_start, + vma->vm_end); +BUG (); + } +#endif +split_huge_page_pmd (vma, addr, pmd); + }else if (madvise_free_pmd (tlb, vma, pmd, addr)) + goto next; +/* fall through */ + } +/* * Here there can be other concurrent MADV_DONTNEED or * trans huge page faults running, and if the pmd is
mm/rmap.c +4 -0
@@ -702,6 +702,10 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,/* go ahead even if the pmd is pmd_trans_splitting() */ if (pmdp_clear_flush_young_notify (vma, address, pmd)) referenced++; + +if (pmd_dirty (*pmd)) + dirty++; +spin_unlock (ptl); }else {pte_t *pte;
mm/vmscan.c +16 -8
@@ -971,15 +971,23 @@ static unsigned long shrink_page_list(struct list_head *page_list,* Anonymous process memory has backing store? * Try to allocate it some swap space here. */ -if (PageAnon (page) && !PageSwapCache (page) && !freeable) { -if (!(sc->gfp_mask & __GFP_IO)) - goto keep_locked; -if (!add_to_swap (page, page_list)) - goto activate_locked; - may_enter_fs =1 ; +if (PageAnon (page) && !PageSwapCache (page)) { +if (!freeable) { +if (!(sc->gfp_mask & __GFP_IO)) + goto keep_locked; +if (!add_to_swap (page, page_list)) + goto activate_locked; + may_enter_fs =1 ; -/* Adding to swap updated mapping */ - mapping =page_mapping (page); +/* Adding to swap updated mapping */ + mapping =page_mapping (page); + }else { +if (unlikely (PageTransHuge (page))) { +if (unlikely (split_huge_page_to_list ( + page, page_list))) + goto keep_locked; + } + } }/*
Signature · 1 line
2.0.0
Re: [PATCH v10 7/7] mm: Don't split THP page when syscall is called
Quoted 37 lines · Minchan Kim
We don't need to split THP page when
MADV_FREEsyscall is called. It could be done when VM decide really frees it so we could reduce the number of THP split.Signed-off-by Minchan Kim <[email protected]>--- include/linux/huge_mm.h | 3 +++ mm/huge_memory.c | 25 +++++++++++++++++++++++++ mm/madvise.c | 19 +++++++++++++++++-- mm/rmap.c | 4 ++++ mm/vmscan.c | 24 ++++++++++++++++-------- 5 files changed, 65 insertions(+), 10 deletions(-)include/linux/huge_mm.h +3
-0@@ -19,6 +19,9 @@ extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,unsigned long addr, pmd_t *pmd, unsigned int flags); +extern int madvise_free_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);mm/huge_memory.c +2
-0@@ -1384,6 +1384,31 @@ out:return 0 ; } +int madvise_free_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma, +pmd_t *pmd,unsigned long addr)
mm/huge_memory.c out: · line 1398
Quoted 10 lines
mm/huge_memory.c +10
-0+{ +spinlock_t *ptl; +int ret =0 ; + +if (__pmd_trans_huge_lock (pmd, vma, &ptl) ==1 ) { +pmd_t orig_pmd; +struct mm_struct *mm = vma->vm_mm; + +/* No hugepage in swapcache */ +VM_BUG_ON (PageSwapCache (pmd_page (orig_pmd)));
VM_BUG_ON_PAGE() ?
Quoted 82 lines
mm/huge_memory.c +13
-0+ + orig_pmd =pmdp_get_and_clear (tlb->mm, addr, pmd); + 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 =1 ; + } +return ret; +} +int zap_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr) {mm/madvise.c +17
-2@@ -320,8 +320,23 @@ static inline unsigned long madvise_free_pmd_range(struct mmu_gather *tlb,* if the range covers. */ next =pmd_addr_end (addr, end); -if (pmd_trans_huge (*pmd)) -split_huge_page_pmd (vma, addr, pmd); +if (pmd_trans_huge (*pmd)) { +if (next - addr !=HPAGE_PMD_SIZE ) { +#ifdef CONFIG_DEBUG_VM +if (!rwsem_is_locked (&tlb->mm->mmap_sem)) { +pr_err ("%s: mmap_sem is unlocked! addr=0x%lx end=0x%lx vma->vm_start=0x%lx vma->vm_end=0x%lx\n" , + __func__, addr, end, + vma->vm_start, + vma->vm_end); +BUG (); + } +#endif +split_huge_page_pmd (vma, addr, pmd); + }else if (madvise_free_pmd (tlb, vma, pmd, addr)) + goto next; +/* fall through */ + } +/* * Here there can be other concurrent MADV_DONTNEED or * trans huge page faults running, and if the pmd is mm/rmap.c +4
-0@@ -702,6 +702,10 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,/* go ahead even if the pmd is pmd_trans_splitting() */ if (pmdp_clear_flush_young_notify (vma, address, pmd)) referenced++; + +if (pmd_dirty (*pmd)) + dirty++; +spin_unlock (ptl); }else {pte_t *pte;mm/vmscan.c +7
-6@@ -971,15 +971,23 @@ static unsigned long shrink_page_list(struct list_head *page_list,* Anonymous process memory has backing store? * Try to allocate it some swap space here. */ -if (PageAnon (page) && !PageSwapCache (page) && !freeable) { -if (!(sc->gfp_mask & __GFP_IO)) - goto keep_locked; -if (!add_to_swap (page, page_list)) - goto activate_locked; - may_enter_fs =1 ; +if (PageAnon (page) && !PageSwapCache (page)) { +if (!freeable) { +if (!(sc->gfp_mask & __GFP_IO)) + goto keep_locked; +if (!add_to_swap (page, page_list)) + goto activate_locked; + may_enter_fs =1 ;
mm/vmscan.c static unsigned long shrink_page_list(struct list_head *page_list, · line 988
Quoted 10 lines
mm/vmscan.c +7
-2-/* Adding to swap updated mapping */ - mapping =page_mapping (page); +/* Adding to swap updated mapping */ + mapping =page_mapping (page); + }else { +if (unlikely (PageTransHuge (page))) { +if (unlikely (split_huge_page_to_list ( + page, page_list))) + goto keep_locked;
Hm. It would be better to free the huge page without splitting. It shouldn't be a big deal: walk over rmap and zap all pmds. Or I miss something?
Quoted 12 lines
mm/vmscan.c +2
-0+ } + } }/* Signature · 6 lines
2.0.0 -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 7 lines
Kirill A. Shutemov -- 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 v10 7/7] mm: Don't split THP page when syscall is called
Quoted 36 lines · Kirill A. Shutemov
Quoted 35 lines · Minchan Kim
We don't need to split THP page when
MADV_FREEsyscall is called. It could be done when VM decide really frees it so we could reduce the number of THP split.Signed-off-by Minchan Kim <[email protected]>--- include/linux/huge_mm.h | 3 +++ mm/huge_memory.c | 25 +++++++++++++++++++++++++ mm/madvise.c | 19 +++++++++++++++++-- mm/rmap.c | 4 ++++ mm/vmscan.c | 24 ++++++++++++++++-------- 5 files changed, 65 insertions(+), 10 deletions(-)include/linux/huge_mm.h +3
-0@@ -19,6 +19,9 @@ extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,unsigned long addr, pmd_t *pmd, unsigned int flags); +extern int madvise_free_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);mm/huge_memory.c +0
-0@@ -1384,6 +1384,31 @@ out:return 0 ; }
Quoted 14 lines
mm/huge_memory.c out: · line 1398
Quoted 12 lines
mm/huge_memory.c +12
-0+int madvise_free_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma, +pmd_t *pmd,unsigned long addr) +{ +spinlock_t *ptl; +int ret =0 ; + +if (__pmd_trans_huge_lock (pmd, vma, &ptl) ==1 ) { +pmd_t orig_pmd; +struct mm_struct *mm = vma->vm_mm; + +/* No hugepage in swapcache */ +VM_BUG_ON (PageSwapCache (pmd_page (orig_pmd)));
VM_BUG_ON_PAGE()?
NP.
Quoted 84 lines
Quoted 84 lines
mm/huge_memory.c +13
-0+ + orig_pmd =pmdp_get_and_clear (tlb->mm, addr, pmd); + 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 =1 ; + } +return ret; +} +int zap_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr) {mm/madvise.c +17
-2@@ -320,8 +320,23 @@ static inline unsigned long madvise_free_pmd_range(struct mmu_gather *tlb,* if the range covers. */ next =pmd_addr_end (addr, end); -if (pmd_trans_huge (*pmd)) -split_huge_page_pmd (vma, addr, pmd); +if (pmd_trans_huge (*pmd)) { +if (next - addr !=HPAGE_PMD_SIZE ) { +#ifdef CONFIG_DEBUG_VM +if (!rwsem_is_locked (&tlb->mm->mmap_sem)) { +pr_err ("%s: mmap_sem is unlocked! addr=0x%lx end=0x%lx vma->vm_start=0x%lx vma->vm_end=0x%lx\n" , + __func__, addr, end, + vma->vm_start, + vma->vm_end); +BUG (); + } +#endif +split_huge_page_pmd (vma, addr, pmd); + }else if (madvise_free_pmd (tlb, vma, pmd, addr)) + goto next; +/* fall through */ + } +/* * Here there can be other concurrent MADV_DONTNEED or * trans huge page faults running, and if the pmd is mm/rmap.c +4
-0@@ -702,6 +702,10 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,/* go ahead even if the pmd is pmd_trans_splitting() */ if (pmdp_clear_flush_young_notify (vma, address, pmd)) referenced++; + +if (pmd_dirty (*pmd)) + dirty++; +spin_unlock (ptl); }else {pte_t *pte;mm/vmscan.c +7
-6@@ -971,15 +971,23 @@ static unsigned long shrink_page_list(struct list_head *page_list,* Anonymous process memory has backing store? * Try to allocate it some swap space here. */ -if (PageAnon (page) && !PageSwapCache (page) && !freeable) { -if (!(sc->gfp_mask & __GFP_IO)) - goto keep_locked; -if (!add_to_swap (page, page_list)) - goto activate_locked; - may_enter_fs =1 ; +if (PageAnon (page) && !PageSwapCache (page)) { +if (!freeable) { +if (!(sc->gfp_mask & __GFP_IO)) + goto keep_locked; +if (!add_to_swap (page, page_list)) + goto activate_locked; + may_enter_fs =1 ;
Quoted 13 lines
mm/vmscan.c static unsigned long shrink_page_list(struct list_head *page_list, · line 988
Quoted 9 lines
mm/vmscan.c +7
-2-/* Adding to swap updated mapping */ - mapping =page_mapping (page); +/* Adding to swap updated mapping */ + mapping =page_mapping (page); + }else { +if (unlikely (PageTransHuge (page))) { +if (unlikely (split_huge_page_to_list ( + page, page_list))) + goto keep_locked;Hm. It would be better to free the huge page without splitting. It shouldn't be a big deal: walk over rmap and zap all pmds. Or I miss something?
Actually, I did but found no problem except CONFIG_DEBUG_VM but rollback after peeking [1].
When I read the description in detail by your review, I think we can remove BUG_ON(PageTransHuge(page)) in try_to_unmap and go with no split for lazyfree page because they are not in swapcache any more so the assumption of [1] is not valid. Will do it in next revision.
Thanks for the review, Kirill!
[1] thp: split_huge_page paging, 3f04f62f9
Quoted 22 lines
Quoted 13 lines
mm/vmscan.c +2
-0+ } + } }/* Signature · 6 lines
2.0.0 -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.htmlSignature · 7 lines
Kirill A. Shutemov -- 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>
Signature · 2 lines
Kind regards, Minchan Kim
Re: [PATCH v10 7/7] mm: Don't split THP page when syscall is called
Quoted 159 lines · Minchan Kim
Quoted 36 lines · Kirill A. Shutemov
Quoted 35 lines · Minchan Kim
We don't need to split THP page when
MADV_FREEsyscall is called. It could be done when VM decide really frees it so we could reduce the number of THP split.Signed-off-by Minchan Kim <[email protected]>--- include/linux/huge_mm.h | 3 +++ mm/huge_memory.c | 25 +++++++++++++++++++++++++ mm/madvise.c | 19 +++++++++++++++++-- mm/rmap.c | 4 ++++ mm/vmscan.c | 24 ++++++++++++++++-------- 5 files changed, 65 insertions(+), 10 deletions(-)include/linux/huge_mm.h +3
-0@@ -19,6 +19,9 @@ extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,unsigned long addr, pmd_t *pmd, unsigned int flags); +extern int madvise_free_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);mm/huge_memory.c +0
-0@@ -1384,6 +1384,31 @@ out:return 0 ; }Quoted 14 lines
mm/huge_memory.c out: · line 1398
Quoted 12 lines
mm/huge_memory.c +12
-0+int madvise_free_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma, +pmd_t *pmd,unsigned long addr) +{ +spinlock_t *ptl; +int ret =0 ; + +if (__pmd_trans_huge_lock (pmd, vma, &ptl) ==1 ) { +pmd_t orig_pmd; +struct mm_struct *mm = vma->vm_mm; + +/* No hugepage in swapcache */ +VM_BUG_ON (PageSwapCache (pmd_page (orig_pmd)));
VM_BUG_ON_PAGE()?NP.
Quoted 84 lines
Quoted 84 lines
mm/huge_memory.c +13
-0+ + orig_pmd =pmdp_get_and_clear (tlb->mm, addr, pmd); + 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 =1 ; + } +return ret; +} +int zap_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr) {mm/madvise.c +17
-2@@ -320,8 +320,23 @@ static inline unsigned long madvise_free_pmd_range(struct mmu_gather *tlb,* if the range covers. */ next =pmd_addr_end (addr, end); -if (pmd_trans_huge (*pmd)) -split_huge_page_pmd (vma, addr, pmd); +if (pmd_trans_huge (*pmd)) { +if (next - addr !=HPAGE_PMD_SIZE ) { +#ifdef CONFIG_DEBUG_VM +if (!rwsem_is_locked (&tlb->mm->mmap_sem)) { +pr_err ("%s: mmap_sem is unlocked! addr=0x%lx end=0x%lx vma->vm_start=0x%lx vma->vm_end=0x%lx\n" , + __func__, addr, end, + vma->vm_start, + vma->vm_end); +BUG (); + } +#endif +split_huge_page_pmd (vma, addr, pmd); + }else if (madvise_free_pmd (tlb, vma, pmd, addr)) + goto next; +/* fall through */ + } +/* * Here there can be other concurrent MADV_DONTNEED or * trans huge page faults running, and if the pmd is mm/rmap.c +4
-0@@ -702,6 +702,10 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma,/* go ahead even if the pmd is pmd_trans_splitting() */ if (pmdp_clear_flush_young_notify (vma, address, pmd)) referenced++; + +if (pmd_dirty (*pmd)) + dirty++; +spin_unlock (ptl); }else {pte_t *pte;mm/vmscan.c +7
-6@@ -971,15 +971,23 @@ static unsigned long shrink_page_list(struct list_head *page_list,* Anonymous process memory has backing store? * Try to allocate it some swap space here. */ -if (PageAnon (page) && !PageSwapCache (page) && !freeable) { -if (!(sc->gfp_mask & __GFP_IO)) - goto keep_locked; -if (!add_to_swap (page, page_list)) - goto activate_locked; - may_enter_fs =1 ; +if (PageAnon (page) && !PageSwapCache (page)) { +if (!freeable) { +if (!(sc->gfp_mask & __GFP_IO)) + goto keep_locked; +if (!add_to_swap (page, page_list)) + goto activate_locked; + may_enter_fs =1 ;Quoted 13 lines
mm/vmscan.c static unsigned long shrink_page_list(struct list_head *page_list, · line 988
Quoted 9 lines
mm/vmscan.c +7
-2-/* Adding to swap updated mapping */ - mapping =page_mapping (page); +/* Adding to swap updated mapping */ + mapping =page_mapping (page); + }else { +if (unlikely (PageTransHuge (page))) { +if (unlikely (split_huge_page_to_list ( + page, page_list))) + goto keep_locked;Hm. It would be better to free the huge page without splitting. It shouldn't be a big deal: walk over rmap and zap all pmds. Or I miss something?
Actually, I did but found no problem except
CONFIG_DEBUG_VMbut rollback after peeking [1].
When I read the description in detail by your review, I think we can remove BUG_ON(PageTransHuge(page)) intry_to_unmapand go with no split for lazyfree page because they are not in swapcache any more so the assumption of [1] is not valid. Will do it in next revision.
Quoted 3 lines
Thanks for the review, Kirill!
[1] thp:
split_huge_pagepaging,3f04f62f9
I just respin without this part because it needs more review but no enough time to me at the moment.
Nontheless, I want to get review other parts from community.
It's like one of optimization so I think it shouldn't a party pooper. But finally I will have a time to see that.(ie, I just added some comment to make try_to_unmap be aware of THP freeing)
Thanks for the review!
Signature · 2 lines
Kind regards, Minchan Kim
Re: [PATCH v10 7/7] mm: Don't split THP page when syscall is called
In reply to Minchan KimQuoted 6 lines · Minchan Kim
Actually, I did but found no problem except
CONFIG_DEBUG_VMbut rollback after peeking [1].
When I read the description in detail by your review, I think we can remove BUG_ON(PageTransHuge(page)) intry_to_unmapand go with no split for lazyfree page because they are not in swapcache any more so the assumption of [1] is not valid. Will do it in next revision.
No. try_to_unmap() knows nothing about PMDs, so page_check_address() will always return NULL for THP and you will not unmap anything.
Signature · 7 lines
Kirill A. Shutemov -- 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>