MADV_FREE support
Subsystems (20)
v5 cover MADV_FREE support
In v4, Andrew wanted to settle in old basic MADV_FREE and introduces new stuffs(ie, lazyfree LRU, swapless support and lazyfreeness) later so this version doesn't include them.
I have been tested it on mmotm-2015-11-25-17-08 with additional patch[1] from Kirill to prevent BUG_ON which he didn't send to linux-mm yet as formal patch. With it, I couldn't find any problem so far.
Note that this version is based on THP refcount redesign so I needed some modification on MADV_FREE because split_huge_pmd doesn't split a THP page any more and pmd_trans_huge(pmd) is not enough to guarantee the page is not THP page.
As well, for MAVD_FREE lazy-split, THP split should respect pmd's dirtiness rather than marking ptes of all subpages dirty unconditionally. Please, review last patch in this patchset.
mm: don't split THP page when syscall is called
[1] https://lkml.org/lkml/2015/11/17/134
git: git://git.kernel.org/pub/scm/linux/kernel/git/minchan/linux.git
branch: mm/madv_free-v4.4-rc2-mmotm-2015-11-25-17-08-v5r2
In this stage, I don't think we need to write man page. It could be done after solid policy and implementation.
* Change from v4
* drop lazyfree LRU
* drop swapless support
* drop lazyfreeness
* rebase on recent mmotom with THP refcount redesign
* Change from v3
* some bug fix
* code refactoring
* lazyfree reclaim logic change
* reordering patch
* Change from v2
* vm_lazyfreeness tuning knob
* add new LRU list - Johannes, Shaohua
* support swapless - Johannes
* Change from v1
* Don't do unnecessary TLB flush - Shaohua
* Added Acked-by - Hugh, Michal
* Merge deactivate_page and deactivate_file_page
* Add pmd_dirty/pmd_mkclean patches for several arches
* Add lazy THP split patch
* Drop [email protected] - Delivery Failure
Chen Gang (1):
arch: uapi: asm: mman.h: Let MADV_FREE have same value for all
architectures
Minchan Kim (11):
mm: support madvise(MADV_FREE)
mm: define MADV_FREE for some arches
mm: free swp_entry in madvise_free
mm: move lazily freed pages to inactive list
mm: mark stable page dirty in KSM
x86: add pmd_[dirty|mkclean] for THP
sparc: add pmd_[dirty|mkclean] for THP
powerpc: add pmd_[dirty|mkclean] for THP
arm: add pmd_mkclean for THP
arm64: add pmd_mkclean for THP
mm: don't split THP page when syscall is called
arch/alpha/include/uapi/asm/mman.h | 2 + arch/arm/include/asm/pgtable-3level.h | 1 + arch/arm64/include/asm/pgtable.h | 1 + arch/mips/include/uapi/asm/mman.h | 2 + arch/parisc/include/uapi/asm/mman.h | 2 + arch/powerpc/include/asm/pgtable-ppc64.h | 2 + arch/sparc/include/asm/pgtable_64.h | 9 ++ arch/x86/include/asm/pgtable.h | 5 + arch/xtensa/include/uapi/asm/mman.h | 2 + include/linux/huge_mm.h | 3 + include/linux/rmap.h | 1 + include/linux/swap.h | 1 + include/linux/vm_event_item.h | 1 + include/uapi/asm-generic/mman-common.h | 1 + mm/huge_memory.c | 87 +++++++++++++- mm/ksm.c | 6 + mm/madvise.c | 199 +++++++++++++++++++++++++++++++ mm/rmap.c | 8 ++ mm/swap.c | 44 +++++++ mm/swap_state.c | 5 +- mm/vmscan.c | 10 +- mm/vmstat.c | 1 + 22 files changed, 383 insertions(+), 10 deletions(-)
Signature · 7 lines
1.9.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>
PATCH v5 1/12 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).
Jason Evans said:
: Facebook has been using MAP_UNINITIALIZED
: (https://lkml.org/lkml/2012/1/18/308) in some of its applications for : several years, but there are operational costs to maintaining this : out-of-tree in our kernel and in jemalloc, and we are anxious to retire it : in favor of MADV_FREE. When we first enabled MAP_UNINITIALIZED it : increased throughput for much of our workload by ~5%, and although the : benefit has decreased using newer hardware and kernels, there is still : enough benefit that we cannot reasonably retire it without a replacement. :
: Aside from Facebook operations, there are numerous broadly used : applications that would benefit from MADV_FREE. The ones that immediately : come to mind are redis, varnish, and MariaDB. I don't have much insight : into Android internals and development process, but I would hope to see : MADV_FREE support eventually end up there as well to benefit applications : linked with the integrated jemalloc.
:
: jemalloc will use MADV_FREE once it becomes available in the Linux kernel. : In fact, jemalloc already uses MADV_FREE or equivalent everywhere it's : available: *BSD, OS X, Windows, and Solaris -- every platform except Linux : (and AIX, but I'm not sure it even compiles on AIX). The lack of : MADV_FREE on Linux forced me down a long series of increasingly : sophisticated heuristics for madvise() volume reduction, and even so this : remains a common performance issue for people using jemalloc on Linux. : Please integrate MADV_FREE; many people will benefit substantially.
How it works:
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.
One thing we should notice is that basically, MADV_FREE relies on dirty bit in page table entry to decide whether VM allows to discard the page or not. IOW, if page table entry includes marked dirty bit, VM shouldn't discard the page.
However, as a example, if swap-in by read fault happens, page table entry doesn't have dirty bit so MADV_FREE could discard the page wrongly.
For avoiding the problem, MADV_FREE did more checks with PageDirty and PageSwapCache. It worked out because swapped-in page lives on swap cache and since it is evicted from the swap cache, the page has PG_dirty flag. So both page flags check effectively prevent wrong discarding by MADV_FREE.
However, a problem in above logic is that swapped-in page has PG_dirty still after they are removed from swap cache so VM cannot consider the page as freeable any more even if madvise_free is called in future.
Look at below example for detail.
ptr = malloc();
memset(ptr);
..
..
.. heavy memory pressure so all of pages are swapped out
..
..
var = *ptr; -> a page swapped-in and could be removed from
swapcache. Then, page table doesn't mark
dirty bit and page descriptor includes PG_dirty
..
..
madvise_free(ptr); -> It doesn't clear PG_dirty of the page.
..
..
..
.. heavy memory pressure again.
.. In this time, VM cannot discard the page because the page
.. has *PG_dirty*To solve the problem, this patch clears PG_dirty if only the page is owned exclusively by current process when madvise is called because PG_dirty represents ptes's dirtiness in several processes so we could clear it only if we own it exclusively.
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): 12 On-line CPU(s) list: 0-11 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 12 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 2 Stepping: 3 CPU MHz: 3200.185 BogoMIPS: 6400.53 Virtualization: VT-x Hypervisor vendor: KVM Virtualization type: full L1d cache: 32K L1i cache: 32K L2 cache: 4096K NUMA node0 CPU(s): 0-11 ebizzy benchmark(./ebizzy -S 10 -n 512)
Higher avg is better.
vanilla-jemalloc MADV_free-jemalloc
1 thread
records: 10 records: 10
avg: 2961.90 avg: 12069.70
std: 71.96(2.43%) std: 186.68(1.55%)
max: 3070.00 max: 12385.00 min: 2796.00 min: 11746.00
2 thread
records: 10 records: 10
avg: 5020.00 avg: 17827.00
std: 264.87(5.28%) std: 358.52(2.01%)
max: 5244.00 max: 18760.00 min: 4251.00 min: 17382.00
4 thread
records: 10 records: 10
avg: 8988.80 avg: 27930.80 std: 1175.33(13.08%) std: 3317.33(11.88%) max: 9508.00 max: 30879.00 min: 5477.00 min: 21024.00
8 thread
records: 10 records: 10
avg: 13036.50 avg: 33739.40
std: 170.67(1.31%) std: 5146.22(15.25%)
max: 13371.00 max: 40572.00 min: 12785.00 min: 24088.00
16 thread
records: 10 records: 10
avg: 11092.40 avg: 31424.20
std: 710.60(6.41%) std: 3763.89(11.98%)
max: 12446.00 max: 36635.00
min: 9949.00 min: 25669.00
32 thread
records: 10 records: 10
avg: 11067.00 avg: 34495.80
std: 971.06(8.77%) std: 2721.36(7.89%)
max: 12010.00 max: 38598.00
min: 9002.00 min: 30636.00
In summary, MADV_FREE is about much faster than MADV_DONTNEED.
--- include/linux/rmap.h | 1 + include/linux/vm_event_item.h | 1 + include/uapi/asm-generic/mman-common.h | 1 + mm/madvise.c | 168 +++++++++++++++++++++++++++++++++ mm/rmap.c | 8 ++ mm/swap_state.c | 5 +- mm/vmscan.c | 10 +- mm/vmstat.c | 1 + 8 files changed, 190 insertions(+), 5 deletions(-)
include/linux/rmap.h +1 -0
@@ -85,6 +85,7 @@ enum ttu_flags {TTU_UNMAP =1 ,/* unmap mode */ TTU_MIGRATION =2 ,/* migration mode */ TTU_MUNLOCK =4 ,/* munlock mode */ +TTU_LZFREE =8 ,/* lazy free mode */ TTU_IGNORE_MLOCK = (1 <<8 ),/* ignore mlock */ TTU_IGNORE_ACCESS = (1 << 9), /* don't age */
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
@@ -39,6 +39,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 +168 -0
198 lines not on this page · raw message
mm/rmap.c +8 -0
@@ -1508,6 +1508,13 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,* See handle_pte_fault() ... */ VM_BUG_ON_PAGE (!PageSwapCache (page), page); + +if (!PageDirty (page) && (flags &TTU_LZFREE )) { +/* It's a freeable page by MADV_FREE */ +dec_mm_counter (mm,MM_ANONPAGES ); + goto discard; + } +if (swap_duplicate (entry) <0 ) {set_pte_at (mm, address, pte, pteval); ret =SWAP_FAIL ;
@@ -1528,6 +1535,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, }else dec_mm_counter (mm,mm_counter_file (page)); +discard:page_remove_rmap (page,PageHuge (page));page_cache_release (page);
mm/swap_state.c +2 -3
@@ -185,13 +185,12 @@ int add_to_swap(struct page *page, struct list_head *list)* deadlock in the swap out path. */ /* -* Add it to the swap cache and mark it dirty +* Add it to the swap cache. */ err =add_to_swap_cache (page, entry, __GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN); -if (!err) {/* Success */ -SetPageDirty (page); +if (!err) {return 1 ; }else {/* -ENOMEM radix-tree allocation failure */ /*
mm/vmscan.c +8 -2
@@ -908,6 +908,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 lazyfree = false;cond_resched ();
@@ -1051,6 +1052,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, goto keep_locked;if (!add_to_swap (page, page_list)) goto activate_locked; + lazyfree = true; may_enter_fs =1 ;/* Adding to swap updated mapping */
@@ -1062,8 +1064,9 @@ static unsigned long shrink_page_list(struct list_head *page_list,* processes. Try to unmap it here. */ if (page_mapped (page) && mapping) { -switch (try_to_unmap (page, - ttu_flags|TTU_BATCH_FLUSH )) { +switch (try_to_unmap (page, lazyfree ? + (ttu_flags |TTU_BATCH_FLUSH |TTU_LZFREE ) : + (ttu_flags |TTU_BATCH_FLUSH ))) {case SWAP_FAIL : goto activate_locked;case SWAP_AGAIN :
@@ -1188,6 +1191,9 @@ static unsigned long shrink_page_list(struct list_head *page_list,*/ __ClearPageLocked (page); free_it: +if (lazyfree && !PageDirty (page)) +count_vm_event (PGLAZYFREED ); + nr_reclaimed++;/*
mm/vmstat.c +1 -0
@@ -781,6 +781,7 @@ const char * const vmstat_text[] = {"pgfault" ,"pgmajfault" , +"pglazyfreed" , TEXTS_FOR_ZONES("pgrefill")TEXTS_FOR_ZONES ("pgsteal_kswapd" )
Signature · 7 lines
1.9.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 v5 01/12] mm: support madvise(MADV_FREE)
Quoted 14 lines
mm/madvise.c +14
-0+* If pmd isn't transhuge but the page is THP and +* is owned by only this process, split it and +* deactivate all pages. +*/ +if (PageTransCompound (page)) { +if (page_mapcount (page) !=1 ) + goto out; +get_page (page); +if (!trylock_page (page)) { +put_page (page); + goto out; + } +pte_unmap_unlock (orig_pte, ptl); +if (split_huge_page (page)) {
mm/madvise.c static long madvise_willneed(struct vm_area_struct *vma, · line 314
Quoted 10 lines
mm/madvise.c +10
-0+unlock_page (page); +put_page (page); +pte_offset_map_lock (mm, pmd, addr, &ptl); + goto out; + } + pte =pte_offset_map_lock (mm, pmd, addr, &ptl); + pte--; + addr -=PAGE_SIZE ; +continue ; + }
looks like this leaks page count if split_huge_page() is succesfull (returns zero).
--Mika
Re: [PATCH v5 01/12] mm: support madvise(MADV_FREE)
Quoted 19 lines · Mika Penttilä
Quoted 19 lines
(quoted diff) +19
-0+ * If pmd isn't transhuge but the page is THP and + * is owned by only this process, split it and + * deactivate all pages. + */ + if (PageTransCompound(page)) { + if (page_mapcount(page) != 1) + goto out; + get_page(page); + if (!trylock_page(page)) { + put_page(page); + goto out; + } + pte_unmap_unlock(orig_pte, ptl); + if (split_huge_page(page)) { + unlock_page(page); + put_page(page); + pte_offset_map_lock(mm, pmd, addr, &ptl); + goto out; + }
Quoted 8 lines
Review
Quoted 5 lines
(quoted diff) +5
-0+ pte = pte_offset_map_lock(mm, pmd, addr, &ptl); + pte--; + addr -= PAGE_SIZE; + continue; + }looks like this leaks page count if
split_huge_page()is succesfull (returns zero).
Even, I missed unlock_page.
Thanks for the review!
PATCH v5 2/12 mm: define MADV_FREE for some arches
In reply to Minchan KimMost architectures use asm-generic, but alpha, mips, parisc, xtensa need their own definitions.
This patch defines MADV_FREE for them so it should fix build break for their architectures.
Maybe, I should split and feed piecies to arch maintainers but included here for mmotm convenience.
--- 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 + 4 files changed, 4 insertions(+)
arch/alpha/include/uapi/asm/mman.h +1 -0
@@ -47,6 +47,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 +1 -0
@@ -73,6 +73,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 +1 -0
@@ -43,6 +43,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 +1 -0
@@ -86,6 +86,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 */
Signature · 7 lines
1.9.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>
PATCH v5 3/12 arch: uapi: asm: mman.h: Let MADV_FREE have same value for all architectures
In reply to Minchan KimFrom: Chen Gang <[email protected]>
For uapi, need try to let all macros have same value, and MADV_FREE is added into main branch recently, so need redefine MADV_FREE for it.
At present, '8' can be shared with all architectures, so redefine it to '8'.
--- 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/uapi/asm-generic/mman-common.h | 2 +- 5 files changed, 5 insertions(+), 1 deletion(-)
arch/alpha/include/uapi/asm/mman.h +1 -0
@@ -50,6 +50,7 @@#define MADV_FREE 7/* free pages only if memory pressure */ /* common/generic parameters */ +#define MADV_FREE 8/* free pages only if memory pressure */ #define MADV_REMOVE 9/* remove these pages & resources */ #define MADV_DONTFORK 10/* don't inherit across fork */ #define MADV_DOFORK 11/* do inherit across fork */
arch/mips/include/uapi/asm/mman.h +1 -0
@@ -76,6 +76,7 @@#define MADV_FREE 5/* free pages only if memory pressure */ /* common parameters: try to keep these consistent across architectures */ +#define MADV_FREE 8/* free pages only if memory pressure */ #define MADV_REMOVE 9/* remove these pages & resources */ #define MADV_DONTFORK 10/* don't inherit across fork */ #define MADV_DOFORK 11/* do inherit across fork */
arch/parisc/include/uapi/asm/mman.h +1 -0
@@ -46,6 +46,7 @@#define MADV_FREE 8/* free pages only if memory pressure */ /* common/generic parameters */ +#define MADV_FREE 8/* free pages only if memory pressure */ #define MADV_REMOVE 9/* remove these pages & resources */ #define MADV_DONTFORK 10/* don't inherit across fork */ #define MADV_DOFORK 11/* do inherit across fork */
arch/xtensa/include/uapi/asm/mman.h +1 -0
@@ -89,6 +89,7 @@#define MADV_FREE 5/* free pages only if memory pressure */ /* common parameters: try to keep these consistent across architectures */ +#define MADV_FREE 8/* free pages only if memory pressure */ #define MADV_REMOVE 9/* remove these pages & resources */ #define MADV_DONTFORK 10/* don't inherit across fork */ #define MADV_DOFORK 11/* do inherit across fork */
include/uapi/asm-generic/mman-common.h +1 -1
@@ -39,9 +39,9 @@#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_FREE 8/* free pages only if memory pressure */ #define MADV_REMOVE 9/* remove these pages & resources */ #define MADV_DONTFORK 10/* don't inherit across fork */ #define MADV_DOFORK 11/* do inherit across fork */
Signature · 1 line
1.9.1
PATCH v5 4/12 mm: free swp_entry in madvise_free
In reply to Minchan KimWhen 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 | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
mm/madvise.c +24 -1
@@ -270,6 +270,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,spinlock_t *ptl;pte_t *orig_pte, *pte, ptent;struct page *page; +int nr_swap =0 ;split_huge_pmd (vma, pmd, addr);if (pmd_trans_unstable (pmd))
@@ -280,8 +281,24 @@ 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)) { +swp_entry_t entry; + + 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)
@@ -353,6 +370,12 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr, } } out: +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 (orig_pte, ptl);cond_resched ();
Signature · 7 lines
1.9.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>
PATCH v5 5/12 mm: move lazily freed pages to inactive list
In reply to Minchan KimMADV_FREE is a hint that it's okay to discard pages if there is memory pressure and we use reclaimers(ie, kswapd and direct reclaim) to free them so there is no value keeping them in the 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.
An arguable issue for the approach would be whether we should put the page to the head or tail of the inactive list. I chose head because the 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 a comprimise for various usecases.
This fixes 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 | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 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
@@ -366,6 +366,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 +44 -0
74 lines not on this page · raw message
Signature · 7 lines
1.9.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>
PATCH v5 6/12 mm: mark stable page dirty in KSM
In reply to Minchan KimThe MADV_FREE patchset changes page reclaim to simply free a clean anonymous page with no dirty ptes, instead of swapping it out; but KSM uses clean write-protected ptes to reference the stable ksm page. So be sure to mark that page dirty, so it's never mistakenly discarded.
--- mm/ksm.c | 6 ++++++ 1 file changed, 6 insertions(+)
mm/ksm.c +6 -0
@@ -1015,6 +1015,12 @@ static int try_to_merge_one_page(struct vm_area_struct *vma,*/ set_page_stable_node (page,NULL );mark_page_accessed (page); +/* +* Page reclaim just frees a clean page with no dirty +* ptes: make sure that the ksm page would be swapped. +*/ +if (!PageDirty (page)) +SetPageDirty (page); err =0 ; }else if (pages_identical (page, kpage)) err =replace_page (vma, page, kpage, orig_pte);
Signature · 7 lines
1.9.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>
PATCH v5 7/12 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 | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/include/asm/pgtable.h +5 -0
@@ -269,6 +269,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
1.9.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>
PATCH v5 8/12 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 | 9 +++++++++ 1 file changed, 9 insertions(+)
arch/sparc/include/asm/pgtable_64.h +9 -0
@@ -710,6 +710,15 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)return __pmd (pte_val (pte)); } +static inline pmd_t 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
1.9.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>
PATCH v5 9/12 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
@@ -502,9 +502,11 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)#define pmd_pfn (pmd) pte_pfn(pmd_pte(pmd))#define pmd_dirty (pmd) pte_dirty(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 · 7 lines
1.9.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>
PATCH v5 10/12 arm: add pmd_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_mkclean for THP page MADV_FREE support.
--- arch/arm/include/asm/pgtable-3level.h | 1 + 1 file changed, 1 insertion(+)
arch/arm/include/asm/pgtable-3level.h +1 -0
@@ -240,6 +240,7 @@ PMD_BIT_FUNC(wrprotect, |= L_PMD_SECT_RDONLY); PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF); PMD_BIT_FUNC(mkwrite, &= ~L_PMD_SECT_RDONLY); PMD_BIT_FUNC(mkdirty, |= L_PMD_SECT_DIRTY); +PMD_BIT_FUNC(mkclean, &= ~L_PMD_SECT_DIRTY); PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);#define pmd_mkhuge (pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
Signature · 7 lines
1.9.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>
PATCH v5 11/12 arm64: add pmd_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_mkclean for THP page MADV_FREE support.
--- arch/arm64/include/asm/pgtable.h | 1 + 1 file changed, 1 insertion(+)
arch/arm64/include/asm/pgtable.h +1 -0
@@ -340,6 +340,7 @@ static inline pgprot_t mk_sect_prot(pgprot_t prot)#define pmd_wrprotect (pmd) pte_pmd(pte_wrprotect(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
1.9.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>
PATCH v5 12/12 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 if [start, len] is aligned with THP size. The split could be done when VM decide to free it in reclaim path if memory pressure is heavy. With that, we could avoid unnecessary THP split.
For the feature, this patch changes pte dirtness marking logic of THP. Now, it marks every ptes of pages dirty unconditionally in splitting, which makes MADV_FREE void. So, instead, this patch propagates pmd dirtiness to all pages via PG_dirty and restores pte dirtiness from PG_dirty. With this, if pmd is clean(ie, MADV_FREEed) when split happens(e,g, shrink_page_list), all of pages are clean too so we could discard them.
--- include/linux/huge_mm.h | 3 ++ mm/huge_memory.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++--- mm/madvise.c | 8 ++++- 3 files changed, 92 insertions(+), 6 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_huge_pmd (struct mmu_gather *tlb, +struct vm_area_struct *vma, +pmd_t *pmd,unsigned long addr,unsigned long next);extern int zap_huge_pmd (struct mmu_gather *tlb,struct vm_area_struct *vma,pmd_t *pmd,unsigned long addr);
mm/huge_memory.c +82 -5
134 lines not on this page · raw message
mm/madvise.c +7 -1
@@ -271,8 +271,13 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,pte_t *orig_pte, *pte, ptent;struct page *page;int nr_swap =0 ; +unsigned long next; + + next =pmd_addr_end (addr, end); +if (pmd_trans_huge (*pmd)) +if (madvise_free_huge_pmd (tlb, vma, pmd, addr, next)) + goto next; -split_huge_pmd (vma, pmd, addr);if (pmd_trans_unstable (pmd))return 0 ;
@@ -381,6 +386,7 @@ static int madvise_free_pte_range(pmd_t *pmd, unsigned long addr,arch_leave_lazy_mmu_mode ();pte_unmap_unlock (orig_pte, ptl);cond_resched (); +next:return 0 ; }
Signature · 7 lines
1.9.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>
Hello Minchan,
Quoted 9 lines · Minchan Kim
In v4, Andrew wanted to settle in old basic
MADV_FREEand introduces newstuffs(ie, lazyfree LRU, swapless support and lazyfreeness)later so this version doesn't include them.I have been tested it on mmotm-2015-11-25-17-08 with additional patch[1] from Kirill to prevent
BUG_ONwhich he didn't send to linux-mm yet as formal patch. With it, I couldn't find any problem so far.
Quoted 7 lines
Note that this version is based on THP refcount redesign so I needed some modification on
MADV_FREEbecausesplit_huge_pmddoesn't split a THP page any more andpmd_trans_huge(pmd)is not enough to guarantee the page is not THP page.
As well, forMAVD_FREElazy-split, THP split should respect pmd's dirtiness rather than marking ptes of all subpages dirty unconditionally. Please, review last patch in this patchset.
Now that MADV_FREE has been merged, would you be willing to write patch to the madvise(2) man page that describes the semantics, noes limitations and restrictions, and (ideally) has some sentences describing use cases?
Thanks,
Michael
Quoted 76 lines
mm: don't split THP page when syscall is called
[1] https://lkml.org/lkml/2015/11/17/134
git:
git://git.kernel.org/pub/scm/linux/kernel/git/minchan/linux.git
branch:mm/madv_free-v4.4-rc2-mmotm-2015-11-25-17-08-v5r2In this stage, I don't think we need to write man page. It could be done after solid policy and implementation.
* Change from v4
* drop lazyfree LRU
* drop swapless support
* drop lazyfreeness
* rebase on recent mmotom with THP refcount redesign* Change from v3
* some bug fix
* code refactoring
* lazyfree reclaim logic change
* reordering patch* Change from v2
*vm_lazyfreenesstuning knob
* add new LRU list - Johannes, Shaohua
* support swapless - Johannes* Change from v1
* Don't do unnecessary TLB flush - Shaohua
* Added Acked-by - Hugh, Michal
* Mergedeactivate_pageanddeactivate_file_page
* Add pmd_dirty/pmd_mkclean patches for several arches
* Add lazy THP split patch
* Drop [email protected] - Delivery FailureChen Gang (1):
arch: uapi: asm:mman.h: LetMADV_FREEhave same value for all
architecturesMinchan Kim (11):
mm: supportmadvise(MADV_FREE)
mm: defineMADV_FREEfor some arches
mm: freeswp_entryinmadvise_free
mm: move lazily freed pages to inactive list
mm: mark stable page dirty in KSM
x86: add pmd_[dirty|mkclean] for THP
sparc: add pmd_[dirty|mkclean] for THP
powerpc: add pmd_[dirty|mkclean] for THP
arm: addpmd_mkcleanfor THP
arm64: addpmd_mkcleanfor THP
mm: don't split THP page when syscall is calledarch/alpha/include/uapi/asm/mman.h | 2 + arch/arm/include/asm/pgtable-3level.h | 1 + arch/arm64/include/asm/pgtable.h | 1 + arch/mips/include/uapi/asm/mman.h | 2 + arch/parisc/include/uapi/asm/mman.h | 2 + arch/powerpc/include/asm/pgtable-ppc64.h | 2 + arch/sparc/include/asm/pgtable_64.h | 9 ++ arch/x86/include/asm/pgtable.h | 5 + arch/xtensa/include/uapi/asm/mman.h | 2 + include/linux/huge_mm.h | 3 + include/linux/rmap.h | 1 + include/linux/swap.h | 1 + include/linux/vm_event_item.h | 1 + include/uapi/asm-generic/mman-common.h | 1 + mm/huge_memory.c | 87 +++++++++++++- mm/ksm.c | 6 + mm/madvise.c | 199 +++++++++++++++++++++++++++++++ mm/rmap.c | 8 ++ mm/swap.c | 44 +++++++ mm/swap_state.c | 5 +- mm/vmscan.c | 10 +- mm/vmstat.c | 1 + 22 files changed, 383 insertions(+), 10 deletions(-)
Signature · 9 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/ -- 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>
Hello Michael,
Quoted 20 lines · Michael Kerrisk (man-pages)
Hello Minchan,
Quoted 9 lines · Minchan Kim
In v4, Andrew wanted to settle in old basic
MADV_FREEand introduces newstuffs(ie, lazyfree LRU, swapless support and lazyfreeness)later so this version doesn't include them.I have been tested it on mmotm-2015-11-25-17-08 with additional patch[1] from Kirill to prevent
BUG_ONwhich he didn't send to linux-mm yet as formal patch. With it, I couldn't find any problem so far.Quoted 7 lines
Note that this version is based on THP refcount redesign so I needed some modification on
MADV_FREEbecausesplit_huge_pmddoesn't split a THP page any more andpmd_trans_huge(pmd)is not enough to guarantee the page is not THP page.
As well, forMAVD_FREElazy-split, THP split should respect pmd's dirtiness rather than marking ptes of all subpages dirty unconditionally. Please, review last patch in this patchset.
Quoted 4 lines
Now that
MADV_FREEhas been merged, would you be willing to write patch to the madvise(2) man page that describes the semantics, noes limitations and restrictions, and (ideally) has some sentences describing use cases?
I will try next week.
Thanks for the heads up.
Quoted 74 lines
Thanks,
Michael
Quoted 68 lines
mm: don't split THP page when syscall is called
[1] https://lkml.org/lkml/2015/11/17/134
git:
git://git.kernel.org/pub/scm/linux/kernel/git/minchan/linux.git
branch:mm/madv_free-v4.4-rc2-mmotm-2015-11-25-17-08-v5r2In this stage, I don't think we need to write man page. It could be done after solid policy and implementation.
* Change from v4
* drop lazyfree LRU
* drop swapless support
* drop lazyfreeness
* rebase on recent mmotom with THP refcount redesign* Change from v3
* some bug fix
* code refactoring
* lazyfree reclaim logic change
* reordering patch* Change from v2
*vm_lazyfreenesstuning knob
* add new LRU list - Johannes, Shaohua
* support swapless - Johannes* Change from v1
* Don't do unnecessary TLB flush - Shaohua
* Added Acked-by - Hugh, Michal
* Mergedeactivate_pageanddeactivate_file_page
* Add pmd_dirty/pmd_mkclean patches for several arches
* Add lazy THP split patch
* Drop [email protected] - Delivery FailureChen Gang (1):
arch: uapi: asm:mman.h: LetMADV_FREEhave same value for all
architecturesMinchan Kim (11):
mm: supportmadvise(MADV_FREE)
mm: defineMADV_FREEfor some arches
mm: freeswp_entryinmadvise_free
mm: move lazily freed pages to inactive list
mm: mark stable page dirty in KSM
x86: add pmd_[dirty|mkclean] for THP
sparc: add pmd_[dirty|mkclean] for THP
powerpc: add pmd_[dirty|mkclean] for THP
arm: addpmd_mkcleanfor THP
arm64: addpmd_mkcleanfor THP
mm: don't split THP page when syscall is calledarch/alpha/include/uapi/asm/mman.h | 2 + arch/arm/include/asm/pgtable-3level.h | 1 + arch/arm64/include/asm/pgtable.h | 1 + arch/mips/include/uapi/asm/mman.h | 2 + arch/parisc/include/uapi/asm/mman.h | 2 + arch/powerpc/include/asm/pgtable-ppc64.h | 2 + arch/sparc/include/asm/pgtable_64.h | 9 ++ arch/x86/include/asm/pgtable.h | 5 + arch/xtensa/include/uapi/asm/mman.h | 2 + include/linux/huge_mm.h | 3 + include/linux/rmap.h | 1 + include/linux/swap.h | 1 + include/linux/vm_event_item.h | 1 + include/uapi/asm-generic/mman-common.h | 1 + mm/huge_memory.c | 87 +++++++++++++- mm/ksm.c | 6 +
Quoted 14 lines
Quoted 8 lines
mm/madvise.c | 199 +++++++++++++++++++++++++++++++ mm/rmap.c | 8 ++ mm/swap.c | 44 +++++++ mm/swap_state.c | 5 +- mm/vmscan.c | 10 +- mm/vmstat.c | 1 + 22 files changed, 383 insertions(+), 10 deletions(-)Signature · 3 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Linux/UNIX System Programming Training: http://man7.org/training/
--
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>