Follow-up for speed up page cache truncation
Subsystems (47)
cover Follow-up for speed up page cache truncation
(cc'ing those that reviewed Jan's series as this series is on top)
This series is a follow-on for Jan Kara's series "Speed up page cache truncation" series. We both ended up looking at the same problem but saw different problems based on the same data. This series builds upon his work. The performance comparisons use 4.14-rc4 + Jan's series as a baseline.
A variety of workloads were compared on four separate machines but each machine showed gains albeit at different levels. Minimally, some of the differences are due to NUMA where truncating data from a remote node is slower than a local node. The workloads checked were
o sparse truncate microbenchmark, tiny
o sparse truncate microbenchmark, large
o reaim-io disk workfile
o dbench4 (modified by mmtests to produce more stable results)
o filebench varmail configuration for small memory size
o bonnie, directory operations, working set size 2*RAM
reaim-io, dbench and filebench all showed minor gains. Truncation does not dominate those workloads but were tested to ensure no other regressions. They will not be reported further.
The sparse truncate microbench was written by Jan. It creates a number of files and then times how long it takes to truncate each one. The "tiny" configuraiton creates a number of files that easily fits in memory and times how long it takes to truncate files with page cache. The large configuration uses enough files to have data that is twice the size of memory and so timings there include truncating page cache and working set shadow entries in the radix tree.
Patches 1-4 are the most relevant parts of this series. Patches 5-8 are optional as they are deleting code that is essentially useless but has a negligible performance impact.
The changelogs have more information on performance but just for bonnie delete options, the main comparison is
bonnie
4.14.0-rc4 4.14.0-rc4 4.14.0-rc4
janbatch-v1r1 vanilla nocold-v1r1
Hmean SeqCreate del 24963.95 ( 0.00%) 21313.45 ( -14.62%) 26842.24 ( 7.52%) Hmean RandCreate del 23377.66 ( 0.00%) 19974.03 ( -14.56%) 25262.42 ( 8.06%)
Jan's series is the baseline and the vanilla kernel is 14% slower where as this series on top gains another 7-8%.
arch/powerpc/mm/mmu_context_book3s64.c | 2 +- arch/powerpc/mm/pgtable_64.c | 2 +- arch/sparc/mm/init_64.c | 2 +- arch/tile/mm/homecache.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 +- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- drivers/gpu/drm/i915/i915_gem_userptr.c | 4 +- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- drivers/net/ethernet/amazon/ena/ena_netdev.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 2 +- drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 3 +- .../net/ethernet/cavium/liquidio/octeon_network.h | 2 +- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 5 +- .../net/ethernet/netronome/nfp/nfp_net_common.c | 4 +- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 3 +- drivers/net/ethernet/sfc/falcon/rx.c | 2 +- drivers/net/ethernet/sfc/rx.c | 2 +- drivers/net/ethernet/synopsys/dwc-xlgmac-desc.c | 2 +- drivers/net/ethernet/ti/netcp_core.c | 2 +- drivers/net/virtio_net.c | 1 - drivers/staging/lustre/lustre/mdc/mdc_request.c | 2 +- fs/afs/write.c | 4 +- fs/btrfs/extent_io.c | 4 +- fs/buffer.c | 4 +- fs/cachefiles/rdwr.c | 10 +-- fs/ceph/addr.c | 4 +- fs/dax.c | 2 +- fs/ext4/file.c | 2 +- fs/ext4/inode.c | 6 +- fs/f2fs/checkpoint.c | 2 +- fs/f2fs/data.c | 2 +- fs/f2fs/file.c | 2 +- fs/f2fs/node.c | 8 +- fs/fscache/page.c | 2 +- fs/fuse/dev.c | 2 +- fs/gfs2/aops.c | 2 +- fs/hugetlbfs/inode.c | 2 +- fs/nilfs2/btree.c | 2 +- fs/nilfs2/page.c | 8 +- fs/nilfs2/segment.c | 4 +- include/linux/gfp.h | 9 +-- include/linux/pagemap.h | 10 +-- include/linux/pagevec.h | 6 +- include/linux/skbuff.h | 2 +- include/linux/slab.h | 3 - include/linux/swap.h | 13 ++- include/trace/events/kmem.h | 11 +-- include/trace/events/mmflags.h | 1 - kernel/power/snapshot.c | 4 +- mm/filemap.c | 15 ++-- mm/mlock.c | 4 +- mm/page-writeback.c | 2 +- mm/page_alloc.c | 89 ++++++++++++--------- mm/percpu-vm.c | 2 +- mm/rmap.c | 2 +- mm/shmem.c | 6 +- mm/swap.c | 15 ++-- mm/swap_state.c | 2 +- mm/truncate.c | 92 +++++++++++++++------- mm/vmscan.c | 6 +- mm/workingset.c | 8 +- net/core/skbuff.c | 4 +- tools/perf/builtin-kmem.c | 1 - 66 files changed, 239 insertions(+), 204 deletions(-)
Signature · 7 lines
2.14.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 1/8 mm, page_alloc: Enable/disable IRQs once when freeing a list of pages
Freeing a list of pages current enables/disables IRQs for each page freed. This patch splits freeing a list of pages into two operations -- preparing the pages for freeing and the actual freeing. This is a tradeoff - we're taking two passes of the list to free in exchange for avoiding multiple enable/disable of IRQs.
sparsetruncate (tiny)
4.14.0-rc4 4.14.0-rc4
janbatch-v1r1 oneirq-v1r1
Min Time 149.00 ( 0.00%) 141.00 ( 5.37%)
1st-qrtle Time 150.00 ( 0.00%) 142.00 ( 5.33%)
2nd-qrtle Time 151.00 ( 0.00%) 142.00 ( 5.96%)
3rd-qrtle Time 151.00 ( 0.00%) 143.00 ( 5.30%)
Max-90% Time 153.00 ( 0.00%) 144.00 ( 5.88%)
Max-95% Time 155.00 ( 0.00%) 147.00 ( 5.16%)
Max-99% Time 201.00 ( 0.00%) 195.00 ( 2.99%)
Max Time 236.00 ( 0.00%) 230.00 ( 2.54%)
Amean Time 152.65 ( 0.00%) 144.37 ( 5.43%)
Stddev Time 9.78 ( 0.00%) 10.44 ( -6.72%)
Coeff Time 6.41 ( 0.00%) 7.23 ( -12.84%)
Best99%Amean Time 152.07 ( 0.00%) 143.72 ( 5.50%)
Best95%Amean Time 150.75 ( 0.00%) 142.37 ( 5.56%)
Best90%Amean Time 150.59 ( 0.00%) 142.19 ( 5.58%)
Best75%Amean Time 150.36 ( 0.00%) 141.92 ( 5.61%)
Best50%Amean Time 150.04 ( 0.00%) 141.69 ( 5.56%)
Best25%Amean Time 149.85 ( 0.00%) 141.38 ( 5.65%)With a tiny number of files, each file truncated has resident page cache and it shows that time to truncate is roughtly 5-6% with some minor jitter.
4.14.0-rc4 4.14.0-rc4
janbatch-v1r1 oneirq-v1r1
Hmean SeqCreate ops 65.27 ( 0.00%) 81.86 ( 25.43%)
Hmean SeqCreate read 39.48 ( 0.00%) 47.44 ( 20.16%)
Hmean SeqCreate del 24963.95 ( 0.00%) 26319.99 ( 5.43%)
Hmean RandCreate ops 65.47 ( 0.00%) 82.01 ( 25.26%)
Hmean RandCreate read 42.04 ( 0.00%) 51.75 ( 23.09%)
Hmean RandCreate del 23377.66 ( 0.00%) 23764.79 ( 1.66%)As expected, there is a small gain for the delete operation.
--- mm/page_alloc.c | 58 +++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 14 deletions(-)
mm/page_alloc.c +44 -14
@@ -2590,24 +2590,26 @@ void mark_free_pages(struct zone *zone) }#endif /* CONFIG_PM */ -/* -* Free a 0-order page -* cold == true ? free a cold page : free a hot page -*/ -void free_hot_cold_page (struct page *page,bool cold) +static bool free_hot_cold_page_prepare (struct page *page,unsigned long pfn) { -struct zone *zone =page_zone (page); -struct per_cpu_pages *pcp; -unsigned long flags; -unsigned long pfn =page_to_pfn (page);int migratetype;if (!free_pcp_prepare (page)) -return ; +return false; migratetype =get_pfnblock_migratetype (page, pfn);set_pcppage_migratetype (page, migratetype); -local_irq_save (flags); +return true; +} + +static void free_hot_cold_page_commit (struct page *page,unsigned long pfn, +bool cold) +{ +struct zone *zone =page_zone (page); +struct per_cpu_pages *pcp; +int migratetype; + + migratetype =get_pcppage_migratetype (page);__count_vm_event (PGFREE );/*
@@ -2620,7 +2622,7 @@ void free_hot_cold_page(struct page *page, bool cold)if (migratetype >=MIGRATE_PCPTYPES ) {if (unlikely (is_migrate_isolate (migratetype))) {free_one_page (zone, page, pfn,0 , migratetype); - goto out; +return ; } migratetype =MIGRATE_MOVABLE ; }
@@ -2636,8 +2638,22 @@ void free_hot_cold_page(struct page *page, bool cold)free_pcppages_bulk (zone, batch, pcp); pcp->count -= batch; } +} -out: +/* +* Free a 0-order page +* cold == true ? free a cold page : free a hot page +*/ +void free_hot_cold_page (struct page *page,bool cold) +{ +unsigned long flags; +unsigned long pfn =page_to_pfn (page); + +if (!free_hot_cold_page_prepare (page, pfn)) +return ; + +local_irq_save (flags); +free_hot_cold_page_commit (page, pfn, cold);local_irq_restore (flags); }
@@ -2647,11 +2663,25 @@ void free_hot_cold_page(struct page *page, bool cold)void free_hot_cold_page_list (struct list_head *list,bool cold) {struct page *page, *next; +unsigned long flags, pfn; + +/* Prepare pages for freeing */ +list_for_each_entry_safe (page, next, list, lru) { + pfn =page_to_pfn (page); +if (!free_hot_cold_page_prepare (page, pfn)) +list_del (&page->lru); + page->private = pfn; + } +local_irq_save (flags);list_for_each_entry_safe (page, next, list, lru) { +unsigned long pfn = page->private; + + page->private =0 ;trace_mm_page_free_batched (page, cold); -free_hot_cold_page (page, cold); +free_hot_cold_page_commit (page, pfn, cold); } +local_irq_restore (flags); }/*
Signature · 1 line
2.14.0
PATCH 2/8 mm, truncate: Do not check mapping for every page being truncated
In reply to Mel GormanDuring truncation, the mapping has already been checked for shmem and dax so it's known that workingset_update_node is required. This patch avoids the checks on mapping for each page being truncated. In all other cases, a lookup helper is used to determine if workingset_update_node() needs to be called. The one danger is that the API is slightly harder to use as calling workingset_update_node directly without checking for dax or shmem mappings could lead to surprises. However, the API rarely needs to be used and hopefully the comment is enough to give people the hint.
sparsetruncate (tiny)
4.14.0-rc4 4.14.0-rc4
oneirq-v1r1 pickhelper-v1r1
Min Time 141.00 ( 0.00%) 140.00 ( 0.71%)
1st-qrtle Time 142.00 ( 0.00%) 141.00 ( 0.70%)
2nd-qrtle Time 142.00 ( 0.00%) 142.00 ( 0.00%)
3rd-qrtle Time 143.00 ( 0.00%) 143.00 ( 0.00%)
Max-90% Time 144.00 ( 0.00%) 144.00 ( 0.00%)
Max-95% Time 147.00 ( 0.00%) 145.00 ( 1.36%)
Max-99% Time 195.00 ( 0.00%) 191.00 ( 2.05%)
Max Time 230.00 ( 0.00%) 205.00 ( 10.87%)
Amean Time 144.37 ( 0.00%) 143.82 ( 0.38%)
Stddev Time 10.44 ( 0.00%) 9.00 ( 13.74%)
Coeff Time 7.23 ( 0.00%) 6.26 ( 13.41%)
Best99%Amean Time 143.72 ( 0.00%) 143.34 ( 0.26%)
Best95%Amean Time 142.37 ( 0.00%) 142.00 ( 0.26%)
Best90%Amean Time 142.19 ( 0.00%) 141.85 ( 0.24%)
Best75%Amean Time 141.92 ( 0.00%) 141.58 ( 0.24%)
Best50%Amean Time 141.69 ( 0.00%) 141.31 ( 0.27%)
Best25%Amean Time 141.38 ( 0.00%) 140.97 ( 0.29%)As you'd expect, the gain is marginal but it can be detected. The differences in bonnie are all within the noise which is not surprising given the impact on the microbenchmark.
--- include/linux/swap.h | 11 +++++++++++ mm/filemap.c | 7 ++++--- mm/workingset.c | 8 +------- 3 files changed, 16 insertions(+), 10 deletions(-)
include/linux/swap.h +11 -0
@@ -292,8 +292,19 @@ struct vma_swap_readahead {void *workingset_eviction (struct address_space *mapping,struct page *page);bool workingset_refault (void *shadow);void workingset_activation (struct page *page); + +/* Do not use directly, use workingset_lookup_update */ void workingset_update_node (struct radix_tree_node *node,void *private); +/* Returns workingset_update_node() if the mapping has shadow entries. */ +#define workingset_lookup_update (mapping) \ +({ \ + radix_tree_update_node_t __helper = workingset_update_node; \ + if (dax_mapping(mapping) || shmem_mapping(mapping)) \ + __helper = NULL; \ + __helper; \ +}) +/* linux/mm/page_alloc.c */ extern unsigned long totalram_pages;extern unsigned long totalreserve_pages;
mm/filemap.c +4 -3
@@ -35,6 +35,7 @@#include <linux/hugetlb.h> #include <linux/memcontrol.h> #include <linux/cleancache.h> +#include <linux/shmem_fs.h> #include <linux/rmap.h> #include "internal.h"
@@ -134,7 +135,7 @@ static int page_cache_tree_insert(struct address_space *mapping, *shadowp = p; }__radix_tree_replace (&mapping->page_tree, node, slot, page, - workingset_update_node, mapping); +workingset_lookup_update (mapping), mapping); mapping->nrpages++;return 0 ; }
@@ -162,7 +163,7 @@ static void page_cache_tree_delete(struct address_space *mapping,radix_tree_clear_tags (&mapping->page_tree, node, slot);__radix_tree_replace (&mapping->page_tree, node, slot, shadow, - workingset_update_node, mapping); +workingset_lookup_update (mapping), mapping); } page->mapping =NULL ;
@@ -360,7 +361,7 @@ page_cache_tree_delete_batch(struct address_space *mapping, int count, }radix_tree_clear_tags (&mapping->page_tree, iter.node, slot);__radix_tree_replace (&mapping->page_tree, iter.node, slot,NULL , - workingset_update_node, mapping); +workingset_lookup_update (mapping), mapping); total_pages++; } mapping->nrpages -= total_pages;
mm/workingset.c +1 -7
@@ -341,12 +341,6 @@ static struct list_lru shadow_nodes;void workingset_update_node (struct radix_tree_node *node,void *private) { -struct address_space *mapping = private; - -/* Only regular page cache has shadow entries */ -if (dax_mapping (mapping) ||shmem_mapping (mapping)) -return ; -/* * Track non-empty nodes that contain only shadow entries; * unlink those that contain pages or are being freed.
@@ -474,7 +468,7 @@ static enum lru_status shadow_lru_isolate(struct list_head *item, goto out_invalid;inc_lruvec_page_state (virt_to_page (node),WORKINGSET_NODERECLAIM );__radix_tree_delete_node (&mapping->page_tree, node, - workingset_update_node, mapping); +workingset_lookup_update (mapping), mapping); out_invalid:spin_unlock (&mapping->tree_lock);
Signature · 7 lines
2.14.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>
Jan Kara
maintainerRe: [PATCH 2/8] mm, truncate: Do not check mapping for every page being truncated
Quoted 35 lines · Mel Gorman
During truncation, the mapping has already been checked for shmem and dax so it's known that
workingset_update_nodeis required. This patch avoids the checks on mapping for each page being truncated. In all other cases, a lookup helper is used to determine ifworkingset_update_node()needs to be called. The one danger is that the API is slightly harder to use as callingworkingset_update_nodedirectly without checking for dax or shmem mappings could lead to surprises. However, the API rarely needs to be used and hopefully the comment is enough to give people the hint.sparsetruncate (tiny)
4.14.0-rc4 4.14.0-rc4 oneirq-v1r1 pickhelper-v1r1 Min Time 141.00 ( 0.00%) 140.00 ( 0.71%) 1st-qrtle Time 142.00 ( 0.00%) 141.00 ( 0.70%) 2nd-qrtle Time 142.00 ( 0.00%) 142.00 ( 0.00%) 3rd-qrtle Time 143.00 ( 0.00%) 143.00 ( 0.00%) Max-90% Time 144.00 ( 0.00%) 144.00 ( 0.00%) Max-95% Time 147.00 ( 0.00%) 145.00 ( 1.36%) Max-99% Time 195.00 ( 0.00%) 191.00 ( 2.05%) Max Time 230.00 ( 0.00%) 205.00 ( 10.87%) Amean Time 144.37 ( 0.00%) 143.82 ( 0.38%) Stddev Time 10.44 ( 0.00%) 9.00 ( 13.74%) Coeff Time 7.23 ( 0.00%) 6.26 ( 13.41%) Best99%Amean Time 143.72 ( 0.00%) 143.34 ( 0.26%) Best95%Amean Time 142.37 ( 0.00%) 142.00 ( 0.26%) Best90%Amean Time 142.19 ( 0.00%) 141.85 ( 0.24%) Best75%Amean Time 141.92 ( 0.00%) 141.58 ( 0.24%) Best50%Amean Time 141.69 ( 0.00%) 141.31 ( 0.27%) Best25%Amean Time 141.38 ( 0.00%) 140.97 ( 0.29%)As you'd expect, the gain is marginal but it can be detected. The differences in bonnie are all within the noise which is not surprising given the impact on the microbenchmark.
Signed-off-by Mel Gorman <[email protected]>
...
Quoted 5 lines
mm/workingset.c +0
-0
mm/workingset.c static struct list_lru shadow_nodes; · line 349
Quoted 9 lines
mm/workingset.c +0
-6@@ -341,12 +341,6 @@ static struct list_lru shadow_nodes;void workingset_update_node (struct radix_tree_node *node,void *private) { -struct address_space *mapping = private; - -/* Only regular page cache has shadow entries */ -if (dax_mapping (mapping) ||shmem_mapping (mapping)) -return ; -
Hum, we don't need to pass 'mapping' from call sites then? Either pass NULL or just remove the argument completely since nobody needs it anymore... Otherwise the patch looks good.
Honza
Signature · 8 lines
Jan Kara <[email protected]> SUSE Labs, CR -- 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 2/8] mm, truncate: Do not check mapping for every page being truncated
Quoted 6 lines · Jan Kara
Quoted 6 lines
mm/workingset.c +0
-0@@ -341,12 +341,6 @@ static struct list_lru shadow_nodes;
Quoted 13 lines
mm/workingset.c static struct list_lru shadow_nodes; · line 349
Quoted 8 lines
mm/workingset.c +0
-6void workingset_update_node (struct radix_tree_node *node,void *private) { -struct address_space *mapping = private; - -/* Only regular page cache has shadow entries */ -if (dax_mapping (mapping) ||shmem_mapping (mapping)) -return ; -Hum, we don't need to pass 'mapping' from call sites then? Either pass NULL or just remove the argument completely since nobody needs it anymore... Otherwise the patch looks good.
You're right. Initially, I was preserving the signature as it's defined by radix_tree_update_node_t but the only user is workingset_update_node so it can be changed.
Signature · 8 lines
Mel Gorman SUSE Labs -- 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 2/8] mm, truncate: Do not check mapping for every page being truncated
In reply to Mel GormanQuoted 30 lines · Mel Gorman
During truncation, the mapping has already been checked for shmem and dax so it's known that
workingset_update_nodeis required. This patch avoids the checks on mapping for each page being truncated. In all other cases, a lookup helper is used to determine ifworkingset_update_node()needs to be called. The one danger is that the API is slightly harder to use as callingworkingset_update_nodedirectly without checking for dax or shmem mappings could lead to surprises. However, the API rarely needs to be used and hopefully the comment is enough to give people the hint.sparsetruncate (tiny)
4.14.0-rc4 4.14.0-rc4 oneirq-v1r1 pickhelper-v1r1 Min Time 141.00 ( 0.00%) 140.00 ( 0.71%) 1st-qrtle Time 142.00 ( 0.00%) 141.00 ( 0.70%) 2nd-qrtle Time 142.00 ( 0.00%) 142.00 ( 0.00%) 3rd-qrtle Time 143.00 ( 0.00%) 143.00 ( 0.00%) Max-90% Time 144.00 ( 0.00%) 144.00 ( 0.00%) Max-95% Time 147.00 ( 0.00%) 145.00 ( 1.36%) Max-99% Time 195.00 ( 0.00%) 191.00 ( 2.05%) Max Time 230.00 ( 0.00%) 205.00 ( 10.87%) Amean Time 144.37 ( 0.00%) 143.82 ( 0.38%) Stddev Time 10.44 ( 0.00%) 9.00 ( 13.74%) Coeff Time 7.23 ( 0.00%) 6.26 ( 13.41%) Best99%Amean Time 143.72 ( 0.00%) 143.34 ( 0.26%) Best95%Amean Time 142.37 ( 0.00%) 142.00 ( 0.26%) Best90%Amean Time 142.19 ( 0.00%) 141.85 ( 0.24%) Best75%Amean Time 141.92 ( 0.00%) 141.58 ( 0.24%) Best50%Amean Time 141.69 ( 0.00%) 141.31 ( 0.27%) Best25%Amean Time 141.38 ( 0.00%) 140.97 ( 0.29%)
Quoted 5 lines
As you'd expect, the gain is marginal but it can be detected. The differences in bonnie are all within the noise which is not surprising given the impact on the microbenchmark.
Signed-off-by Mel Gorman <[email protected]>
With Jan's suggestion to remove the private parameter,
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/8 mm, truncate: Remove all exceptional entries from pagevec under one lock
In reply to Mel GormanDuring truncate each entry in a pagevec is checked to see if it is an exceptional entry and if so, the shadow entry is cleaned up. This is potentially expensive as multiple entries for a mapping locks/unlocks the tree lock. This batches the operation such that any exceptional entries removed from a pagevec only acquire the mapping tree lock once. The corner case where this is more expensive is where there is only one exceptional entry but this is unlikely due to temporal locality and how it affects LRU ordering. Note that for truncations of small files created recently, this patch should show no gain because it only batches the handling of exceptional entries.
sparsetruncate (large)
4.14.0-rc4 4.14.0-rc4
pickhelper-v1r1 batchshadow-v1r1
Min Time 38.00 ( 0.00%) 27.00 ( 28.95%)
1st-qrtle Time 40.00 ( 0.00%) 28.00 ( 30.00%)
2nd-qrtle Time 44.00 ( 0.00%) 41.00 ( 6.82%)
3rd-qrtle Time 146.00 ( 0.00%) 147.00 ( -0.68%)
Max-90% Time 153.00 ( 0.00%) 153.00 ( 0.00%)
Max-95% Time 155.00 ( 0.00%) 156.00 ( -0.65%)
Max-99% Time 181.00 ( 0.00%) 171.00 ( 5.52%)
Amean Time 93.04 ( 0.00%) 88.43 ( 4.96%)
Best99%Amean Time 92.08 ( 0.00%) 86.13 ( 6.46%)
Best95%Amean Time 89.19 ( 0.00%) 83.13 ( 6.80%)
Best90%Amean Time 85.60 ( 0.00%) 79.15 ( 7.53%)
Best75%Amean Time 72.95 ( 0.00%) 65.09 ( 10.78%)
Best50%Amean Time 39.86 ( 0.00%) 28.20 ( 29.25%)
Best25%Amean Time 39.44 ( 0.00%) 27.70 ( 29.77%)bonnie
4.14.0-rc4 4.14.0-rc4
pickhelper-v1r1 batchshadow-v1r1
Hmean SeqCreate ops 71.92 ( 0.00%) 76.78 ( 6.76%)
Hmean SeqCreate read 42.42 ( 0.00%) 45.01 ( 6.10%)
Hmean SeqCreate del 26519.88 ( 0.00%) 27191.87 ( 2.53%)
Hmean RandCreate ops 71.92 ( 0.00%) 76.95 ( 7.00%)
Hmean RandCreate read 44.44 ( 0.00%) 49.23 ( 10.78%)
Hmean RandCreate del 24948.62 ( 0.00%) 24764.97 ( -0.74%)Truncation of a large number of files shows a substantial gain with 99% of files being trruncated 6.46% faster. bonnie shows a modest gain of 2.53%
--- mm/truncate.c | 86 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 25 deletions(-)
mm/truncate.c +61 -25
@@ -25,44 +25,77 @@#include <linux/rmap.h> #include "internal.h" -static void clear_shadow_entry (struct address_space *mapping,pgoff_t index, -void *entry) +/* +* Regular page slots are stabilized by the page lock even without the tree +* itself locked. These unlocked entries need verification under the tree +* lock. +*/ +static inline void __clear_shadow_entry (struct address_space *mapping, +pgoff_t index,void *entry) {struct radix_tree_node *node;void **slot; -spin_lock_irq (&mapping->tree_lock); -/* -* Regular page slots are stabilized by the page lock even -* without the tree itself locked. These unlocked entries -* need verification under the tree lock. -*/ if (!__radix_tree_lookup (&mapping->page_tree, index, &node, &slot)) - goto unlock; +return ;if (*slot != entry) - goto unlock; +return ;__radix_tree_replace (&mapping->page_tree, node, slot,NULL , workingset_update_node, mapping); mapping->nrexceptional--; -unlock: +} + +static void clear_shadow_entry (struct address_space *mapping,pgoff_t index, +void *entry) +{ +spin_lock_irq (&mapping->tree_lock); +__clear_shadow_entry (mapping, index, entry);spin_unlock_irq (&mapping->tree_lock); }/* -* Unconditionally remove exceptional entry. Usually called from truncate path. +* Unconditionally remove exceptional entries. Usually called from truncate +* path. Note that the pagevec may be altered by this function by removing +* exceptional entries similar to what pagevec_remove_exceptionals does. */ -static void truncate_exceptional_entry (struct address_space *mapping, -pgoff_t index,void *entry) +static void truncate_exceptional_pvec_entries (struct address_space *mapping, +struct pagevec *pvec,pgoff_t *indices,int ei) { +int i, j; +bool dax; + +/* Return immediately if caller indicates there are no entries */ +if (ei ==PAGEVEC_SIZE ) +return ; +/* Handled by shmem itself */ if (shmem_mapping (mapping))return ; -if (dax_mapping (mapping)) { -dax_delete_mapping_entry (mapping, index); -return ; + dax =dax_mapping (mapping); +if (!dax) +spin_lock_irq (&mapping->tree_lock); + +for (i = ei, j = ei; i <pagevec_count (pvec); i++) { +struct page *page = pvec->pages[i]; +pgoff_t index = indices[i]; + +if (!radix_tree_exceptional_entry (page)) { + pvec->pages[j++] = page; +continue ; + } + +if (unlikely (dax)) { +dax_delete_mapping_entry (mapping, index); +continue ; + } + +__clear_shadow_entry (mapping, index, page); } -clear_shadow_entry (mapping, index, entry); + +if (!dax) +spin_unlock_irq (&mapping->tree_lock); + pvec->nr = j; }/*
@@ -301,6 +334,7 @@ void truncate_inode_pages_range(struct address_space *mapping,*/ struct page *pages[PAGEVEC_SIZE ];int batch_count =0 ; +int ei =PAGEVEC_SIZE ;for (i =0 ; i <pagevec_count (&pvec); i++) {struct page *page = pvec.pages[i];
@@ -311,8 +345,8 @@ void truncate_inode_pages_range(struct address_space *mapping,break ;if (radix_tree_exceptional_entry (page)) { -truncate_exceptional_entry (mapping, index, - page); +if (ei ==PAGEVEC_SIZE ) + ei = i;continue ; }
@@ -334,12 +368,11 @@ void truncate_inode_pages_range(struct address_space *mapping,delete_from_page_cache_batch (mapping, batch_count, pages);for (i =0 ; i < batch_count; i++)unlock_page (pages[i]); -pagevec_remove_exceptionals (&pvec); +truncate_exceptional_pvec_entries (mapping, &pvec, indices, ei);pagevec_release (&pvec);cond_resched (); index++; } -if (partial_start) {struct page *page =find_lock_page (mapping, start -1 );if (page) {
@@ -381,6 +414,8 @@ void truncate_inode_pages_range(struct address_space *mapping, index = start;for ( ; ; ) { +int ei =PAGEVEC_SIZE ; +cond_resched ();if (!pagevec_lookup_entries (&pvec, mapping, index,min (end - index, (pgoff_t )PAGEVEC_SIZE ), indices)) {
@@ -397,6 +432,7 @@ void truncate_inode_pages_range(struct address_space *mapping,pagevec_release (&pvec);break ; } +for (i =0 ; i <pagevec_count (&pvec); i++) {struct page *page = pvec.pages[i];
@@ -409,8 +445,8 @@ void truncate_inode_pages_range(struct address_space *mapping, }if (radix_tree_exceptional_entry (page)) { -truncate_exceptional_entry (mapping, index, - page); +if (ei !=PAGEVEC_SIZE ) + ei = i;continue ; }
@@ -420,7 +456,7 @@ void truncate_inode_pages_range(struct address_space *mapping,truncate_inode_page (mapping, page);unlock_page (page); } -pagevec_remove_exceptionals (&pvec); +truncate_exceptional_pvec_entries (mapping, &pvec, indices, ei);pagevec_release (&pvec); index++; }
Signature · 7 lines
2.14.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 3/8] mm, truncate: Remove all exceptional entries from pagevec under one lock
Quoted 135 lines · Mel Gorman
During truncate each entry in a pagevec is checked to see if it is an exceptional entry and if so, the shadow entry is cleaned up. This is potentially expensive as multiple entries for a mapping locks/unlocks the tree lock. This batches the operation such that any exceptional entries removed from a pagevec only acquire the mapping tree lock once. The corner case where this is more expensive is where there is only one exceptional entry but this is unlikely due to temporal locality and how it affects LRU ordering. Note that for truncations of small files created recently, this patch should show no gain because it only batches the handling of exceptional entries.
sparsetruncate (large)
4.14.0-rc4 4.14.0-rc4 pickhelper-v1r1 batchshadow-v1r1 Min Time 38.00 ( 0.00%) 27.00 ( 28.95%) 1st-qrtle Time 40.00 ( 0.00%) 28.00 ( 30.00%) 2nd-qrtle Time 44.00 ( 0.00%) 41.00 ( 6.82%) 3rd-qrtle Time 146.00 ( 0.00%) 147.00 ( -0.68%) Max-90% Time 153.00 ( 0.00%) 153.00 ( 0.00%) Max-95% Time 155.00 ( 0.00%) 156.00 ( -0.65%) Max-99% Time 181.00 ( 0.00%) 171.00 ( 5.52%) Amean Time 93.04 ( 0.00%) 88.43 ( 4.96%) Best99%Amean Time 92.08 ( 0.00%) 86.13 ( 6.46%) Best95%Amean Time 89.19 ( 0.00%) 83.13 ( 6.80%) Best90%Amean Time 85.60 ( 0.00%) 79.15 ( 7.53%) Best75%Amean Time 72.95 ( 0.00%) 65.09 ( 10.78%) Best50%Amean Time 39.86 ( 0.00%) 28.20 ( 29.25%) Best25%Amean Time 39.44 ( 0.00%) 27.70 ( 29.77%)bonnie
4.14.0-rc4 4.14.0-rc4 pickhelper-v1r1 batchshadow-v1r1 Hmean SeqCreate ops 71.92 ( 0.00%) 76.78 ( 6.76%) Hmean SeqCreate read 42.42 ( 0.00%) 45.01 ( 6.10%) Hmean SeqCreate del 26519.88 ( 0.00%) 27191.87 ( 2.53%) Hmean RandCreate ops 71.92 ( 0.00%) 76.95 ( 7.00%) Hmean RandCreate read 44.44 ( 0.00%) 49.23 ( 10.78%) Hmean RandCreate del 24948.62 ( 0.00%) 24764.97 ( -0.74%)Truncation of a large number of files shows a substantial gain with 99% of files being trruncated 6.46% faster. bonnie shows a modest gain of 2.53%
Signed-off-by Mel Gorman <[email protected]>--- mm/truncate.c | 86 ++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 25 deletions(-)mm/truncate.c +44
-17@@ -25,44 +25,77 @@#include <linux/rmap.h> #include "internal.h" -static void clear_shadow_entry (struct address_space *mapping,pgoff_t index, -void *entry) +/* +* Regular page slots are stabilized by the page lock even without the tree +* itself locked. These unlocked entries need verification under the tree +* lock. +*/ +static inline void __clear_shadow_entry (struct address_space *mapping, +pgoff_t index,void *entry) {struct radix_tree_node *node;void **slot; -spin_lock_irq (&mapping->tree_lock); -/* -* Regular page slots are stabilized by the page lock even -* without the tree itself locked. These unlocked entries -* need verification under the tree lock. -*/ if (!__radix_tree_lookup (&mapping->page_tree, index, &node, &slot)) - goto unlock; +return ;if (*slot != entry) - goto unlock; +return ;__radix_tree_replace (&mapping->page_tree, node, slot,NULL , workingset_update_node, mapping); mapping->nrexceptional--; -unlock: +} + +static void clear_shadow_entry (struct address_space *mapping,pgoff_t index, +void *entry) +{ +spin_lock_irq (&mapping->tree_lock); +__clear_shadow_entry (mapping, index, entry);spin_unlock_irq (&mapping->tree_lock); }/* -* Unconditionally remove exceptional entry. Usually called from truncate path. +* Unconditionally remove exceptional entries. Usually called from truncate +* path. Note that the pagevec may be altered by this function by removing +* exceptional entries similar to what pagevec_remove_exceptionals does. */ -static void truncate_exceptional_entry (struct address_space *mapping, -pgoff_t index,void *entry) +static void truncate_exceptional_pvec_entries (struct address_space *mapping, +struct pagevec *pvec,pgoff_t *indices,int ei) { +int i, j; +bool dax; + +/* Return immediately if caller indicates there are no entries */ +if (ei ==PAGEVEC_SIZE ) +return ; +/* Handled by shmem itself */ if (shmem_mapping (mapping))return ; -if (dax_mapping (mapping)) { -dax_delete_mapping_entry (mapping, index); -return ; + dax =dax_mapping (mapping); +if (!dax) +spin_lock_irq (&mapping->tree_lock); + +for (i = ei, j = ei; i <pagevec_count (pvec); i++) { +struct page *page = pvec->pages[i]; +pgoff_t index = indices[i]; + +if (!radix_tree_exceptional_entry (page)) { + pvec->pages[j++] = page; +continue ; + } + +if (unlikely (dax)) { +dax_delete_mapping_entry (mapping, index); +continue ;
mm/truncate.c line 99
Quoted 10 lines
mm/truncate.c +7
-1+ } + +__clear_shadow_entry (mapping, index, page); } -clear_shadow_entry (mapping, index, entry); + +if (!dax) +spin_unlock_irq (&mapping->tree_lock); + pvec->nr = j; }
When I look at this I think could make things cleaner. I have the following observations:
1) All truncate_inode_pages(), invalidate_mapping_pages(), invalidate_inode_pages2_range() essentially do very similar thing and would benefit from a similar kind of batching.
2) As you observed and measured, batching of radix tree operations makes sense both when removing pages and shadow entries, I'm very confident it would make sense for DAX exceptional entries as well.
3) In all cases (i.e., those three functions and for all entry types) the workflow seems to be:
* lockless lookup of entries
* prepare entry for reclaim (or determine it is not elligible)
* lock mapping->tree_lock
* verify entry is still elligible for reclaim (otherwise bail)
* clear radix tree entry
* unlock mapping->tree_lock
* final cleanup of the entry
So I'm wondering whether we cannot somehow refactor stuff so that batching of radix tree operations could be shared and we wouldn't have to duplicate it in all those cases.
But it would be rather large overhaul of the code so it may be a bit out of scope for these improvements...
mm/truncate.c void truncate_inode_pages_range(struct address_space *mapping, · line 449
Quoted 8 lines
mm/truncate.c +2
-2@@ -409,8 +445,8 @@ void truncate_inode_pages_range(struct address_space *mapping, }if (radix_tree_exceptional_entry (page)) { -truncate_exceptional_entry (mapping, index, - page); +if (ei !=PAGEVEC_SIZE ) + ei = i;
This should be ei == PAGEVEC_SIZE I think.
Otherwise the patch looks good to me so feel free to add:
Honza
Signature · 8 lines
Jan Kara <[email protected]> SUSE Labs, CR -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 3/8] mm, truncate: Remove all exceptional entries from pagevec under one lock
Quoted 35 lines · Jan Kara
Quoted 21 lines
mm/truncate.c +16
-3return ; -if (dax_mapping (mapping)) { -dax_delete_mapping_entry (mapping, index); -return ; + dax =dax_mapping (mapping); +if (!dax) +spin_lock_irq (&mapping->tree_lock); + +for (i = ei, j = ei; i <pagevec_count (pvec); i++) { +struct page *page = pvec->pages[i]; +pgoff_t index = indices[i]; + +if (!radix_tree_exceptional_entry (page)) { + pvec->pages[j++] = page; +continue ; + } + +if (unlikely (dax)) { +dax_delete_mapping_entry (mapping, index); +continue ;mm/truncate.c line 99
Quoted 10 lines
mm/truncate.c +7
-1+ } + +__clear_shadow_entry (mapping, index, page); } -clear_shadow_entry (mapping, index, entry); + +if (!dax) +spin_unlock_irq (&mapping->tree_lock); + pvec->nr = j; }When I look at this I think could make things cleaner. I have the following observations:
Quoted 4 lines
1) All
truncate_inode_pages(),invalidate_mapping_pages(),invalidate_inode_pages2_range()essentially do very similar thing and would benefit from a similar kind of batching.
While this is true, the benefit is much more marginal that I didn't feel the level of churn was justified. Primarily it would help fadvise() and invalidating when buffered and direct IO is mixed. I didn't think it would be that much cleaner as a result so I left it.
Quoted 4 lines
2) As you observed and measured, batching of radix tree operations makes sense both when removing pages and shadow entries, I'm very confident it would make sense for DAX exceptional entries as well.
True, but I didn't have a suitable setup for testing DAX so I wasn't comfortable with making the change. dax_delete_mapping_entry can sleep but it should be as simple as not taking the spinlock in dax_delete_mapping_entry and always locking in truncate_exceptional_pvec_entries. dax is already releasing the mapping->tree_lock if it needs to sleep and I didn't spot any other gotcha but I'd prefer that change was done by someone that can verify it works properly.
Quoted 10 lines
3) In all cases (i.e., those three functions and for all entry types) the workflow seems to be:
* lockless lookup of entries
* prepare entry for reclaim (or determine it is not elligible)
* lockmapping->tree_lock
* verify entry is still elligible for reclaim (otherwise bail)
* clear radix tree entry
* unlockmapping->tree_lock
* final cleanup of the entry
Quoted 7 lines
So I'm wondering whether we cannot somehow refactor stuff so that batching of radix tree operations could be shared and we wouldn't have to duplicate it in all those cases.
But it would be rather large overhaul of the code so it may be a bit out of scope for these improvements...
I think it would be out of scope for this improvement but I can look into it if the series is accepted. I think it would be a lot of churn for fairly marginal benefit though.
Quoted 11 lines
mm/truncate.c void truncate_inode_pages_range(struct address_space *mapping, · line 449
Quoted 8 lines
mm/truncate.c +2
-2@@ -409,8 +445,8 @@ void truncate_inode_pages_range(struct address_space *mapping, }if (radix_tree_exceptional_entry (page)) { -truncate_exceptional_entry (mapping, index, - page); +if (ei !=PAGEVEC_SIZE ) + ei = i;This should be ei ==
PAGEVEC_SIZEI think.
Quoted 2 lines
Otherwise the patch looks good to me so feel free to add:
Fixed.
Quoted 1 line
Reviewed-by Jan Kara <[email protected]>
Thanks
Signature · 8 lines
Mel Gorman SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [PATCH 3/8] mm, truncate: Remove all exceptional entries from pagevec under one lock
In reply to Mel GormanQuoted 39 lines · Mel Gorman
During truncate each entry in a pagevec is checked to see if it is an exceptional entry and if so, the shadow entry is cleaned up. This is potentially expensive as multiple entries for a mapping locks/unlocks the tree lock. This batches the operation such that any exceptional entries removed from a pagevec only acquire the mapping tree lock once. The corner case where this is more expensive is where there is only one exceptional entry but this is unlikely due to temporal locality and how it affects LRU ordering. Note that for truncations of small files created recently, this patch should show no gain because it only batches the handling of exceptional entries.
sparsetruncate (large)
4.14.0-rc4 4.14.0-rc4 pickhelper-v1r1 batchshadow-v1r1 Min Time 38.00 ( 0.00%) 27.00 ( 28.95%) 1st-qrtle Time 40.00 ( 0.00%) 28.00 ( 30.00%) 2nd-qrtle Time 44.00 ( 0.00%) 41.00 ( 6.82%) 3rd-qrtle Time 146.00 ( 0.00%) 147.00 ( -0.68%) Max-90% Time 153.00 ( 0.00%) 153.00 ( 0.00%) Max-95% Time 155.00 ( 0.00%) 156.00 ( -0.65%) Max-99% Time 181.00 ( 0.00%) 171.00 ( 5.52%) Amean Time 93.04 ( 0.00%) 88.43 ( 4.96%) Best99%Amean Time 92.08 ( 0.00%) 86.13 ( 6.46%) Best95%Amean Time 89.19 ( 0.00%) 83.13 ( 6.80%) Best90%Amean Time 85.60 ( 0.00%) 79.15 ( 7.53%) Best75%Amean Time 72.95 ( 0.00%) 65.09 ( 10.78%) Best50%Amean Time 39.86 ( 0.00%) 28.20 ( 29.25%) Best25%Amean Time 39.44 ( 0.00%) 27.70 ( 29.77%)bonnie
4.14.0-rc4 4.14.0-rc4 pickhelper-v1r1 batchshadow-v1r1 Hmean SeqCreate ops 71.92 ( 0.00%) 76.78 ( 6.76%) Hmean SeqCreate read 42.42 ( 0.00%) 45.01 ( 6.10%) Hmean SeqCreate del 26519.88 ( 0.00%) 27191.87 ( 2.53%) Hmean RandCreate ops 71.92 ( 0.00%) 76.95 ( 7.00%) Hmean RandCreate read 44.44 ( 0.00%) 49.23 ( 10.78%) Hmean RandCreate del 24948.62 ( 0.00%) 24764.97 ( -0.74%)
Quoted 4 lines
Truncation of a large number of files shows a substantial gain with 99% of files being trruncated 6.46% faster. bonnie shows a modest gain of 2.53%
Signed-off-by Mel Gorman <[email protected]>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/8 mm: Only drain per-cpu pagevecs once per pagevec usage
In reply to Mel GormanWhen a pagevec is initialised on the stack, it is generally used multiple times over a range of pages, looking up entries and then releasing them. On each pagevec_release, the per-cpu deferred LRU pagevecs are drained on the grounds the page being released may be on those queues and the pages may be cache hot. In many cases only the first drain is necessary as it's unlikely that the range of pages being walked is racing against LRU addition. Even if there is such a race, the impact is marginal where as constantly redraining the lru pagevecs costs.
This patch ensures that pagevec is only drained once in a given lifecycle without increasing the cache footprint of the pagevec structure. Only sparsetruncate tiny is shown here as large files have many exceptional entries and calls pagecache_release less frequently.
sparsetruncate (tiny)
4.14.0-rc4 4.14.0-rc4
batchshadow-v1r1 onedrain-v1r1
Min Time 141.00 ( 0.00%) 141.00 ( 0.00%)
1st-qrtle Time 142.00 ( 0.00%) 142.00 ( 0.00%)
2nd-qrtle Time 142.00 ( 0.00%) 142.00 ( 0.00%)
3rd-qrtle Time 143.00 ( 0.00%) 143.00 ( 0.00%)
Max-90% Time 144.00 ( 0.00%) 144.00 ( 0.00%)
Max-95% Time 146.00 ( 0.00%) 145.00 ( 0.68%)
Max-99% Time 198.00 ( 0.00%) 194.00 ( 2.02%)
Max Time 254.00 ( 0.00%) 208.00 ( 18.11%)
Amean Time 145.12 ( 0.00%) 144.30 ( 0.56%)
Stddev Time 12.74 ( 0.00%) 9.62 ( 24.49%)
Coeff Time 8.78 ( 0.00%) 6.67 ( 24.06%)
Best99%Amean Time 144.29 ( 0.00%) 143.82 ( 0.32%)
Best95%Amean Time 142.68 ( 0.00%) 142.31 ( 0.26%)
Best90%Amean Time 142.52 ( 0.00%) 142.19 ( 0.24%)
Best75%Amean Time 142.26 ( 0.00%) 141.98 ( 0.20%)
Best50%Amean Time 141.90 ( 0.00%) 141.71 ( 0.13%)
Best25%Amean Time 141.80 ( 0.00%) 141.43 ( 0.26%)The impact on bonnie is marginal and within the noise because a significant percentage of the file being truncated has been reclaimed and consists of shadow entries which reduce the hotness of the pagevec_release path.
--- include/linux/pagevec.h | 4 +++- mm/swap.c | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-)
include/linux/pagevec.h +3 -1
@@ -16,7 +16,8 @@ struct address_space;struct pagevec {unsigned long nr; -unsigned long cold; +bool cold; +bool drained;struct page *pages[PAGEVEC_SIZE ]; };
@@ -45,6 +46,7 @@ static inline void pagevec_init(struct pagevec *pvec, int cold) { pvec->nr =0 ; pvec->cold = cold; + pvec->drained = false; }static inline void pagevec_reinit (struct pagevec *pvec)
mm/swap.c +4 -1
@@ -833,7 +833,10 @@ EXPORT_SYMBOL(release_pages);*/ void __pagevec_release (struct pagevec *pvec) { -lru_add_drain (); +if (!pvec->drained) { +lru_add_drain (); + pvec->drained = true; + }release_pages (pvec->pages,pagevec_count (pvec), pvec->cold);pagevec_reinit (pvec); }
Signature · 7 lines
2.14.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 5/8 mm, pagevec: Remove cold parameter for pagevecs
In reply to Mel GormanEvery pagevec_init user claims the pages being released are false even in cases where it is unlikely the pages are hot. As no one cares about the hotness of pages being released to the allocator, just ditch the parameter.
No performance impact is expected as the overhead is marginal. The parameter is removed simply because it is a bit stupid to have a useless parameter copied everywhere.
--- drivers/gpu/drm/i915/i915_gem_gtt.c | 2 +- fs/afs/write.c | 4 ++-- fs/btrfs/extent_io.c | 4 ++-- fs/buffer.c | 4 ++-- fs/cachefiles/rdwr.c | 4 ++-- fs/ceph/addr.c | 4 ++-- fs/dax.c | 2 +- fs/ext4/file.c | 2 +- fs/ext4/inode.c | 6 +++--- fs/f2fs/checkpoint.c | 2 +- fs/f2fs/data.c | 2 +- fs/f2fs/file.c | 2 +- fs/f2fs/node.c | 8 ++++---- fs/fscache/page.c | 2 +- fs/gfs2/aops.c | 2 +- fs/hugetlbfs/inode.c | 2 +- fs/nilfs2/btree.c | 2 +- fs/nilfs2/page.c | 8 ++++---- fs/nilfs2/segment.c | 4 ++-- include/linux/pagevec.h | 4 +--- mm/filemap.c | 2 +- mm/mlock.c | 4 ++-- mm/page-writeback.c | 2 +- mm/shmem.c | 6 +++--- mm/swap.c | 4 ++-- mm/truncate.c | 6 +++--- 26 files changed, 46 insertions(+), 48 deletions(-)
drivers/gpu/drm/i915/i915_gem_gtt.c +1 -1
@@ -1866,7 +1866,7 @@ static void i915_address_space_init(struct i915_address_space *vm,INIT_LIST_HEAD (&vm->unbound_list);list_add_tail (&vm->global_link, &dev_priv->vm_list); -pagevec_init (&vm->free_pages, false); +pagevec_init (&vm->free_pages); }static void i915_address_space_fini (struct i915_address_space *vm)
fs/afs/write.c +2 -2
@@ -308,7 +308,7 @@ static void afs_kill_pages(struct afs_vnode *vnode, bool error,_enter ("{%x:%u},%lx-%lx" , vnode->fid.vid, vnode->fid.vnode, first, last); -pagevec_init (&pv,0 ); +pagevec_init (&pv); do { _debug("kill %lx-%lx", first, last);
@@ -609,7 +609,7 @@ void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)ASSERT (wb !=NULL ); -pagevec_init (&pv,0 ); +pagevec_init (&pv); do { _debug("done %lx-%lx", first, last);
fs/btrfs/extent_io.c +2 -2
@@ -3801,7 +3801,7 @@ int btree_write_cache_pages(struct address_space *mapping,int scanned =0 ;int tag; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);if (wbc->range_cyclic) { index = mapping->writeback_index;/* Start from prev offset */ end =-1 ;
@@ -3945,7 +3945,7 @@ static int extent_write_cache_pages(struct address_space *mapping,if (!igrab (inode))return 0 ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);if (wbc->range_cyclic) { index = mapping->writeback_index;/* Start from prev offset */ end =-1 ;
fs/buffer.c +2 -2
@@ -1632,7 +1632,7 @@ void clean_bdev_aliases(struct block_device *bdev, sector_t block, sector_t len)struct buffer_head *head; end = (block + len -1 ) >> (PAGE_SHIFT - bd_inode->i_blkbits); -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (pagevec_lookup_range (&pvec, bd_mapping, &index, end)) { count =pagevec_count (&pvec);for (i =0 ; i < count; i++) {
@@ -3545,7 +3545,7 @@ page_cache_seek_hole_data(struct inode *inode, loff_t offset, loff_t length,if (length <=0 )return -ENOENT ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); do { unsigned nr_pages, i;
fs/cachefiles/rdwr.c +2 -2
@@ -710,7 +710,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,/* calculate the shift required to use bmap */ shift =PAGE_SHIFT - inode->i_sb->s_blocksize_bits; -pagevec_init (&pagevec,0 ); +pagevec_init (&pagevec); op->op.flags &=FSCACHE_OP_KEEP_FLAGS ; op->op.flags |=FSCACHE_OP_ASYNC ;
@@ -844,7 +844,7 @@ int cachefiles_allocate_pages(struct fscache_retrieval *op, ret =cachefiles_has_space (cache,0 , *nr_pages);if (ret ==0 ) { -pagevec_init (&pagevec,0 ); +pagevec_init (&pagevec);list_for_each_entry (page, pages, lru) {if (pagevec_add (&pagevec, page) ==0 )
fs/ceph/addr.c +2 -2
@@ -679,7 +679,7 @@ static void ceph_release_pages(struct page **pages, int num)struct pagevec pvec;int i; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);for (i =0 ; i < num; i++) {if (pagevec_add (&pvec, pages[i]) ==0 )pagevec_release (&pvec);
@@ -810,7 +810,7 @@ static int ceph_writepages_start(struct address_space *mapping,if (fsc->mount_options->wsize < wsize) wsize = fsc->mount_options->wsize; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); start_index = wbc->range_cyclic ? mapping->writeback_index :0 ; index = start_index;
fs/dax.c +1 -1
@@ -789,7 +789,7 @@ int dax_writeback_mapping_range(struct address_space *mapping,tag_pages_for_writeback (mapping, start_index, end_index); -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (!done) { pvec.nr = find_get_entries_tag(mapping, start_index, PAGECACHE_TAG_TOWRITE, PAGEVEC_SIZE,
fs/ext4/file.c +1 -1
@@ -475,7 +475,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, index = startoff >>PAGE_SHIFT ; end = (endoff -1 ) >>PAGE_SHIFT ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); do { int i; unsigned long nr_pages;
fs/ext4/inode.c +3 -3
@@ -1718,7 +1718,7 @@ static void mpage_release_unused_pages(struct mpage_da_data *mpd,ext4_es_remove_extent (inode, start, last - start +1 ); } -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (index <= end) { nr_pages =pagevec_lookup_range (&pvec, mapping, &index, end);if (nr_pages ==0 )
@@ -2344,7 +2344,7 @@ static int mpage_map_and_submit_buffers(struct mpage_da_data *mpd) lblk = start << bpp_bits; pblock = mpd->map.m_pblk; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (start <= end) { nr_pages =pagevec_lookup_range (&pvec, inode->i_mapping, &start, end);
@@ -2615,7 +2615,7 @@ static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd)else tag =PAGECACHE_TAG_DIRTY ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); mpd->map.m_len =0 ; mpd->next_page = index;while (index <= end) {
fs/f2fs/checkpoint.c +1 -1
@@ -313,7 +313,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type, };struct blk_plug plug; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);blk_start_plug (&plug);
fs/f2fs/data.c +1 -1
@@ -1635,7 +1635,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,int range_whole =0 ;int tag; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);if (get_dirty_pages (mapping->host) <=SM_I (F2FS_M_SB (mapping))->min_hot_blocks)
fs/f2fs/file.c +1 -1
@@ -320,7 +320,7 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping,return 0 ;/* find first dirty page index */ -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); nr_pages =pagevec_lookup_tag (&pvec, mapping, &pgofs,PAGECACHE_TAG_DIRTY ,1 ); pgofs = nr_pages ? pvec.pages[0 ]->index :ULONG_MAX ;
fs/f2fs/node.c +4 -4
@@ -1281,7 +1281,7 @@ static struct page *last_fsync_dnode(struct f2fs_sb_info *sbi, nid_t ino)struct pagevec pvec;struct page *last_page =NULL ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); index =0 ; end =ULONG_MAX ;
@@ -1439,7 +1439,7 @@ int fsync_node_pages(struct f2fs_sb_info *sbi, struct inode *inode,return PTR_ERR_OR_ZERO (last_page); } retry: -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); index =0 ; end =ULONG_MAX ;
@@ -1554,7 +1554,7 @@ int sync_node_pages(struct f2fs_sb_info *sbi, struct writeback_control *wbc,int nwritten =0 ;int ret =0 ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); next_step: index =0 ;
@@ -1659,7 +1659,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)struct pagevec pvec;int ret2, ret =0 ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (index <= end) {int i, nr_pages;
fs/fscache/page.c +1 -1
@@ -1175,7 +1175,7 @@ void __fscache_uncache_all_inode_pages(struct fscache_cookie *cookie,return ; } -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); next =0 ; do { if (!pagevec_lookup(&pvec, mapping, &next))
fs/gfs2/aops.c +1 -1
@@ -387,7 +387,7 @@ static int gfs2_write_cache_jdata(struct address_space *mapping,int range_whole =0 ;int tag; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);if (wbc->range_cyclic) { writeback_index = mapping->writeback_index;/* prev offset */ index = writeback_index;
fs/hugetlbfs/inode.c +1 -1
@@ -407,7 +407,7 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,memset (&pseudo_vma,0 ,sizeof (struct vm_area_struct )); pseudo_vma.vm_flags = (VM_HUGETLB |VM_MAYSHARE |VM_SHARED ); -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); next = start;while (next < end) {/*
fs/nilfs2/btree.c +1 -1
@@ -2156,7 +2156,7 @@ static void nilfs_btree_lookup_dirty_buffers(struct nilfs_bmap *btree, level++)INIT_LIST_HEAD (&lists[level]); -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (pagevec_lookup_tag (&pvec, btcache, &index,PAGECACHE_TAG_DIRTY ,PAGEVEC_SIZE )) {
fs/nilfs2/page.c +4 -4
@@ -255,7 +255,7 @@ int nilfs_copy_dirty_pages(struct address_space *dmap,pgoff_t index =0 ;int err =0 ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); repeat:if (!pagevec_lookup_tag (&pvec, smap, &index,PAGECACHE_TAG_DIRTY ,PAGEVEC_SIZE ))
@@ -310,7 +310,7 @@ void nilfs_copy_back_pages(struct address_space *dmap,pgoff_t index =0 ;int err; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); repeat: n =pagevec_lookup (&pvec, smap, &index);if (!n)
@@ -374,7 +374,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping, bool silent)unsigned int i;pgoff_t index =0 ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (pagevec_lookup_tag (&pvec, mapping, &index,PAGECACHE_TAG_DIRTY ,PAGEVEC_SIZE )) {
@@ -519,7 +519,7 @@ unsigned long nilfs_find_uncommitted_extent(struct inode *inode, index = start_blk >> (PAGE_SHIFT - inode->i_blkbits); nblocks_in_page =1U << (PAGE_SHIFT - inode->i_blkbits); -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); repeat: pvec.nr = find_get_pages_contig(inode->i_mapping, index, PAGEVEC_SIZE,
fs/nilfs2/segment.c +2 -2
@@ -708,7 +708,7 @@ static size_t nilfs_lookup_dirty_data_buffers(struct inode *inode, index = start >>PAGE_SHIFT ; last = end >>PAGE_SHIFT ; } -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); repeat:if (unlikely (index > last) || !pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_DIRTY,
@@ -757,7 +757,7 @@ static void nilfs_lookup_dirty_node_buffers(struct inode *inode,unsigned int i;pgoff_t index =0 ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (pagevec_lookup_tag (&pvec, mapping, &index,PAGECACHE_TAG_DIRTY ,PAGEVEC_SIZE )) {
include/linux/pagevec.h +1 -3
@@ -16,7 +16,6 @@ struct address_space;struct pagevec {unsigned long nr; -bool cold;bool drained;struct page *pages[PAGEVEC_SIZE ]; };
@@ -42,10 +41,9 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping, pgoff_t *index, int tag, unsigned nr_pages); -static inline void pagevec_init (struct pagevec *pvec,int cold) +static inline void pagevec_init (struct pagevec *pvec) { pvec->nr =0 ; - pvec->cold = cold; pvec->drained = false; }
mm/filemap.c +1 -1
@@ -520,7 +520,7 @@ static void __filemap_fdatawait_range(struct address_space *mapping,if (end_byte < start_byte)return ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); while ((index <= end) && (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, PAGECACHE_TAG_WRITEBACK,
mm/mlock.c +2 -2
@@ -288,7 +288,7 @@ static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)struct pagevec pvec_putback;int pgrescued =0 ; -pagevec_init (&pvec_putback,0 ); +pagevec_init (&pvec_putback);/* Phase 1: page isolation */ spin_lock_irq (zone_lru_lock (zone));
@@ -447,7 +447,7 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,struct pagevec pvec;struct zone *zone; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);/* * Although FOLL_DUMP is intended for get_dump_page(), * it just so happens that its special treatment of the
mm/page-writeback.c +1 -1
@@ -2167,7 +2167,7 @@ int write_cache_pages(struct address_space *mapping,int range_whole =0 ;int tag; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);if (wbc->range_cyclic) { writeback_index = mapping->writeback_index;/* prev offset */ index = writeback_index;
mm/shmem.c +3 -3
@@ -747,7 +747,7 @@ void shmem_unlock_mapping(struct address_space *mapping)pgoff_t indices[PAGEVEC_SIZE ];pgoff_t index =0 ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);/* * Minor point, but we might as well stop if someone else SHM_LOCKs it. */
@@ -790,7 +790,7 @@ static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend,if (lend ==-1 ) end =-1 ;/* unsigned, so actually very big */ -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); index = start;while (index < end) { pvec.nr = find_get_entries(mapping, index,
@@ -2528,7 +2528,7 @@ static pgoff_t shmem_seek_hole_data(struct address_space *mapping,bool done = false;int i; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); pvec.nr =1 ;/* start small: we may be there already */ while (!done) { pvec.nr = find_get_entries(mapping, index,
mm/swap.c +2 -2
@@ -210,7 +210,7 @@ static void pagevec_lru_move_fn(struct pagevec *pvec, }if (pgdat)spin_unlock_irqrestore (&pgdat->lru_lock, flags); -release_pages (pvec->pages, pvec->nr, pvec->cold); +release_pages (pvec->pages, pvec->nr,0 );pagevec_reinit (pvec); }
@@ -837,7 +837,7 @@ void __pagevec_release(struct pagevec *pvec)lru_add_drain (); pvec->drained = true; } -release_pages (pvec->pages,pagevec_count (pvec), pvec->cold); +release_pages (pvec->pages,pagevec_count (pvec),0 );pagevec_reinit (pvec); }EXPORT_SYMBOL (__pagevec_release);
mm/truncate.c +3 -3
@@ -322,7 +322,7 @@ void truncate_inode_pages_range(struct address_space *mapping, else end = (lend +1 ) >>PAGE_SHIFT ; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); index = start; while (index < end && pagevec_lookup_entries(&pvec, mapping, index, min(end - index, (pgoff_t)PAGEVEC_SIZE),
@@ -554,7 +554,7 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping,unsigned long count =0 ;int i; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec);while (index <= end &&pagevec_lookup_entries (&pvec, mapping, index,min (end - index, (pgoff_t )PAGEVEC_SIZE -1 ) +1 , indices)) {
@@ -684,7 +684,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,if (mapping->nrpages ==0 && mapping->nrexceptional ==0 ) goto out; -pagevec_init (&pvec,0 ); +pagevec_init (&pvec); index = start; while (index <= end && pagevec_lookup_entries(&pvec, mapping, index, min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1,
Signature · 1 line
2.14.0
PATCH 6/8 mm: Remove cold parameter for release_pages
In reply to Mel GormanAll callers of release_pages claim the pages being released are cache hot. As no one cares about the hotness of pages being released to the allocator, just ditch the parameter.
No performance impact is expected as the overhead is marginal. The parameter is removed simply because it is a bit stupid to have a useless parameter copied everywhere.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 ++---- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 6 +++--- drivers/gpu/drm/i915/i915_gem_userptr.c | 4 ++-- drivers/gpu/drm/radeon/radeon_ttm.c | 2 +- fs/fuse/dev.c | 2 +- include/linux/pagemap.h | 2 +- include/linux/swap.h | 2 +- mm/swap.c | 8 ++++---- mm/swap_state.c | 2 +- 11 files changed, 18 insertions(+), 20 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +2 -4
@@ -553,8 +553,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,* invalidated it. Free it and try again */ release_pages (e->user_pages, - e->robj->tbo.ttm->num_pages, - false); + e->robj->tbo.ttm->num_pages);kvfree (e->user_pages); e->user_pages =NULL ; }
@@ -691,8 +690,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,continue ;release_pages (e->user_pages, - e->robj->tbo.ttm->num_pages, - false); + e->robj->tbo.ttm->num_pages);kvfree (e->user_pages); } }
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +1 -1
@@ -347,7 +347,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,return 0 ; free_pages: -release_pages (bo->tbo.ttm->pages, bo->tbo.ttm->num_pages, false); +release_pages (bo->tbo.ttm->pages, bo->tbo.ttm->num_pages); unlock_mmap_sem:up_read (¤t->mm->mmap_sem);
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +1 -1
@@ -659,7 +659,7 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)return 0 ; release_pages: -release_pages (pages, pinned,0 ); +release_pages (pages, pinned);return r; }
drivers/gpu/drm/etnaviv/etnaviv_gem.c +3 -3
@@ -779,7 +779,7 @@ static struct page **etnaviv_gem_userptr_do_get_pages(up_read (&mm->mmap_sem);if (ret <0 ) { -release_pages (pvec, pinned,0 ); +release_pages (pvec, pinned);kvfree (pvec);return ERR_PTR (ret); }
@@ -852,7 +852,7 @@ static int etnaviv_gem_userptr_get_pages(struct etnaviv_gem_object *etnaviv_obj) } } -release_pages (pvec, pinned,0 ); +release_pages (pvec, pinned);kvfree (pvec); work =kmalloc (sizeof (*work),GFP_KERNEL );
@@ -886,7 +886,7 @@ static void etnaviv_gem_userptr_release(struct etnaviv_gem_object *etnaviv_obj)if (etnaviv_obj->pages) {int npages = etnaviv_obj->base.size >>PAGE_SHIFT ; -release_pages (etnaviv_obj->pages, npages,0 ); +release_pages (etnaviv_obj->pages, npages);kvfree (etnaviv_obj->pages); }put_task_struct (etnaviv_obj->userptr.task);
drivers/gpu/drm/i915/i915_gem_userptr.c +2 -2
@@ -554,7 +554,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) }mutex_unlock (&obj->mm.lock); -release_pages (pvec, pinned,0 ); +release_pages (pvec, pinned);kvfree (pvec);i915_gem_object_put (obj);
@@ -668,7 +668,7 @@ i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)__i915_gem_userptr_set_active (obj, true);if (IS_ERR (pages)) -release_pages (pvec, pinned,0 ); +release_pages (pvec, pinned);kvfree (pvec);return pages;
drivers/gpu/drm/radeon/radeon_ttm.c +1 -1
@@ -597,7 +597,7 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)kfree (ttm->sg); release_pages: -release_pages (ttm->pages, pinned,0 ); +release_pages (ttm->pages, pinned);return r; }
fs/fuse/dev.c +1 -1
@@ -1636,7 +1636,7 @@ static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,static void fuse_retrieve_end (struct fuse_conn *fc,struct fuse_req *req) { -release_pages (req->pages, req->num_pages, false); +release_pages (req->pages, req->num_pages); } static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode,
include/linux/pagemap.h +1 -1
@@ -115,7 +115,7 @@ static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask) m->gfp_mask = mask; } -void release_pages (struct page **pages,int nr,bool cold); +void release_pages (struct page **pages,int nr);/* * speculatively take a reference to a page.
include/linux/swap.h +1 -1
@@ -492,7 +492,7 @@ extern void exit_swap_address_space(unsigned int type);#define free_page_and_swap_cache (page) \ put_page(page)#define free_pages_and_swap_cache (pages, nr) \ - release_pages((pages), (nr), false); + release_pages((pages), (nr));static inline void show_swap_cache_info (void ) {
mm/swap.c +4 -4
@@ -210,7 +210,7 @@ static void pagevec_lru_move_fn(struct pagevec *pvec, }if (pgdat)spin_unlock_irqrestore (&pgdat->lru_lock, flags); -release_pages (pvec->pages, pvec->nr,0 ); +release_pages (pvec->pages, pvec->nr);pagevec_reinit (pvec); }
@@ -740,7 +740,7 @@ void lru_add_drain_all(void)* Decrement the reference count on all the pages in @pages. If it * fell to zero, remove the page from the LRU and free it. */ -void release_pages (struct page **pages,int nr,bool cold) +void release_pages (struct page **pages,int nr) {int i;LIST_HEAD (pages_to_free);
@@ -817,7 +817,7 @@ void release_pages(struct page **pages, int nr, bool cold)spin_unlock_irqrestore (&locked_pgdat->lru_lock, flags);mem_cgroup_uncharge_list (&pages_to_free); -free_hot_cold_page_list (&pages_to_free, cold); +free_hot_cold_page_list (&pages_to_free,0 ); }EXPORT_SYMBOL (release_pages);
@@ -837,7 +837,7 @@ void __pagevec_release(struct pagevec *pvec)lru_add_drain (); pvec->drained = true; } -release_pages (pvec->pages,pagevec_count (pvec),0 ); +release_pages (pvec->pages,pagevec_count (pvec));pagevec_reinit (pvec); }EXPORT_SYMBOL (__pagevec_release);
mm/swap_state.c +1 -1
@@ -322,7 +322,7 @@ void free_pages_and_swap_cache(struct page **pages, int nr)lru_add_drain ();for (i =0 ; i < nr; i++)free_swap_cache (pagep[i]); -release_pages (pagep, nr, false); +release_pages (pagep, nr); }/*
Signature · 1 line
2.14.0
PATCH 7/8 mm, Remove cold parameter from free_hot_cold_page*
In reply to Mel GormanMost callers users of free_hot_cold_page claim the pages being released are cache hot. The exception is the page reclaim paths where it is likely that enough pages will be freed in the near future that the per-cpu lists are going to be recycled and the cache hotness information is lost. As no one really cares about the hotness of pages being released to the allocator, just ditch the parameter.
The APIs are renamed to indicate that it's no longer about hot/cold pages. It should also be less confusing as there are subtle differences between them. __free_pages drops a reference and frees a page when the refcount reaches zero. free_hot_cold_page handled pages whose refcount was already zero which is non-obvious from the name. free_unref_page should be more obvious.
No performance impact is expected as the overhead is marginal. The parameter is removed simply because it is a bit stupid to have a useless parameter copied everywhere.
--- arch/powerpc/mm/mmu_context_book3s64.c | 2 +- arch/powerpc/mm/pgtable_64.c | 2 +- arch/sparc/mm/init_64.c | 2 +- arch/tile/mm/homecache.c | 2 +- include/linux/gfp.h | 4 ++-- include/trace/events/kmem.h | 11 ++++------- mm/page_alloc.c | 29 ++++++++++++----------------- mm/rmap.c | 2 +- mm/swap.c | 4 ++-- mm/vmscan.c | 6 +++--- 10 files changed, 28 insertions(+), 36 deletions(-)
arch/powerpc/mm/mmu_context_book3s64.c +1 -1
@@ -200,7 +200,7 @@ static void destroy_pagetable_page(struct mm_struct *mm)/* We allow PTE_FRAG_NR fragments from a PTE page */ if (page_ref_sub_and_test (page,PTE_FRAG_NR - count)) {pgtable_page_dtor (page); -free_hot_cold_page (page,0 ); +free_unref_page (page); } }
arch/powerpc/mm/pgtable_64.c +1 -1
@@ -404,7 +404,7 @@ void pte_fragment_free(unsigned long *table, int kernel)if (put_page_testzero (page)) {if (!kernel)pgtable_page_dtor (page); -free_hot_cold_page (page,0 ); +free_unref_page (page); } }
arch/sparc/mm/init_64.c +1 -1
@@ -2942,7 +2942,7 @@ pgtable_t pte_alloc_one(struct mm_struct *mm,if (!page)return NULL ;if (!pgtable_page_ctor (page)) { -free_hot_cold_page (page,0 ); +free_unref_page (page);return NULL ; }return (pte_t *)page_address (page);
arch/tile/mm/homecache.c +1 -1
@@ -409,7 +409,7 @@ void __homecache_free_pages(struct page *page, unsigned int order)if (put_page_testzero (page)) {homecache_change_page_home (page, order,PAGE_HOME_HASH );if (order ==0 ) { -free_hot_cold_page (page, false); +free_unref_page (page); }else {init_page_count (page);__free_pages (page, order);
include/linux/gfp.h +2 -2
@@ -538,8 +538,8 @@ void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask);extern void __free_pages (struct page *page,unsigned int order);extern void free_pages (unsigned long addr,unsigned int order); -extern void free_hot_cold_page (struct page *page,bool cold); -extern void free_hot_cold_page_list (struct list_head *list,bool cold); +extern void free_unref_page (struct page *page); +extern void free_unref_page_list (struct list_head *list);struct page_frag_cache ;extern void __page_frag_cache_drain (struct page *page,unsigned int count);
include/trace/events/kmem.h +4 -7
@@ -171,24 +171,21 @@ TRACE_EVENT(mm_page_free,TRACE_EVENT (mm_page_free_batched, - TP_PROTO(struct page *page, int cold), + TP_PROTO(struct page *page), -TP_ARGS (page, cold), +TP_ARGS (page),TP_STRUCT__entry ( __field( unsigned long, pfn ) -__field ( int, cold ) ),TP_fast_assign ( __entry->pfn = page_to_pfn(page); - __entry->cold = cold; ), -TP_printk ("page=%p pfn=%lu order=0 cold=%d" , +TP_printk ("page=%p pfn=%lu order=0" ,pfn_to_page (__entry->pfn), - __entry->pfn, - __entry->cold) + __entry->pfn) ); TRACE_EVENT(mm_page_alloc,
mm/page_alloc.c +12 -17
@@ -2590,7 +2590,7 @@ void mark_free_pages(struct zone *zone) }#endif /* CONFIG_PM */ -static bool free_hot_cold_page_prepare (struct page *page,unsigned long pfn) +static bool free_unref_page_prepare (struct page *page,unsigned long pfn) {int migratetype;
@@ -2602,8 +2602,7 @@ static bool free_hot_cold_page_prepare(struct page *page, unsigned long pfn)return true; } -static void free_hot_cold_page_commit (struct page *page,unsigned long pfn, -bool cold) +static void free_unref_page_commit (struct page *page,unsigned long pfn) {struct zone *zone =page_zone (page);struct per_cpu_pages *pcp;
@@ -2628,10 +2627,7 @@ static void free_hot_cold_page_commit(struct page *page, unsigned long pfn, } pcp = &this_cpu_ptr (zone->pageset)->pcp; -if (!cold) -list_add (&page->lru, &pcp->lists[migratetype]); -else -list_add_tail (&page->lru, &pcp->lists[migratetype]); +list_add_tail (&page->lru, &pcp->lists[migratetype]); pcp->count++;if (pcp->count >= pcp->high) {unsigned long batch =READ_ONCE (pcp->batch);
@@ -2642,25 +2638,24 @@ static void free_hot_cold_page_commit(struct page *page, unsigned long pfn,/* * Free a 0-order page -* cold == true ? free a cold page : free a hot page */ -void free_hot_cold_page (struct page *page,bool cold) +void free_unref_page (struct page *page) {unsigned long flags;unsigned long pfn =page_to_pfn (page); -if (!free_hot_cold_page_prepare (page, pfn)) +if (!free_unref_page_prepare (page, pfn))return ;local_irq_save (flags); -free_hot_cold_page_commit (page, pfn, cold); +free_unref_page_commit (page, pfn);local_irq_restore (flags); }/* * Free a list of 0-order pages */ -void free_hot_cold_page_list (struct list_head *list,bool cold) +void free_unref_page_list (struct list_head *list) {struct page *page, *next;unsigned long flags, pfn;
@@ -2668,7 +2663,7 @@ void free_hot_cold_page_list(struct list_head *list, bool cold)/* Prepare pages for freeing */ list_for_each_entry_safe (page, next, list, lru) { pfn =page_to_pfn (page); -if (!free_hot_cold_page_prepare (page, pfn)) +if (!free_unref_page_prepare (page, pfn))list_del (&page->lru); page->private = pfn; }
@@ -2678,8 +2673,8 @@ void free_hot_cold_page_list(struct list_head *list, bool cold)unsigned long pfn = page->private; page->private =0 ; -trace_mm_page_free_batched (page, cold); -free_hot_cold_page_commit (page, pfn, cold); +trace_mm_page_free_batched (page); +free_unref_page_commit (page, pfn); }local_irq_restore (flags); }
@@ -4292,7 +4287,7 @@ void __free_pages(struct page *page, unsigned int order) {if (put_page_testzero (page)) {if (order ==0 ) -free_hot_cold_page (page, false); +free_unref_page (page);else __free_pages_ok (page, order); }
@@ -4350,7 +4345,7 @@ void __page_frag_cache_drain(struct page *page, unsigned int count)unsigned int order =compound_order (page);if (order ==0 ) -free_hot_cold_page (page, false); +free_unref_page (page);else __free_pages_ok (page, order); }
mm/rmap.c +1 -1
@@ -1318,7 +1318,7 @@ void page_remove_rmap(struct page *page, bool compound)* It would be tidy to reset the PageAnon mapping here, * but that might overwrite a racing page_add_anon_rmap * which increments mapcount after us but sets mapping -* before us: so leave the reset to free_hot_cold_page, +* before us: so leave the reset to free_unref_page, * and remember that it's only reliable while mapped. * Leaving it set also helps swapoff to reinstate ptes * faster for those pages still in swapcache.
mm/swap.c +2 -2
@@ -76,7 +76,7 @@ static void __page_cache_release(struct page *page)static void __put_single_page (struct page *page) {__page_cache_release (page); -free_hot_cold_page (page, false); +free_unref_page (page); }static void __put_compound_page (struct page *page)
@@ -817,7 +817,7 @@ void release_pages(struct page **pages, int nr)spin_unlock_irqrestore (&locked_pgdat->lru_lock, flags);mem_cgroup_uncharge_list (&pages_to_free); -free_hot_cold_page_list (&pages_to_free,0 ); +free_unref_page_list (&pages_to_free); }EXPORT_SYMBOL (release_pages);
mm/vmscan.c +3 -3
@@ -1348,7 +1348,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,mem_cgroup_uncharge_list (&free_pages);try_to_unmap_flush (); -free_hot_cold_page_list (&free_pages, true); +free_unref_page_list (&free_pages);list_splice (&ret_pages, page_list);count_vm_events (PGACTIVATE , pgactivate);
@@ -1823,7 +1823,7 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,spin_unlock_irq (&pgdat->lru_lock);mem_cgroup_uncharge_list (&page_list); -free_hot_cold_page_list (&page_list, true); +free_unref_page_list (&page_list);/* * If reclaim is isolating dirty pages under writeback, it implies
@@ -2062,7 +2062,7 @@ static void shrink_active_list(unsigned long nr_to_scan,spin_unlock_irq (&pgdat->lru_lock);mem_cgroup_uncharge_list (&l_hold); -free_hot_cold_page_list (&l_hold, true); +free_unref_page_list (&l_hold);trace_mm_vmscan_lru_shrink_active (pgdat->node_id, nr_taken, nr_activate, nr_deactivate, nr_rotated, sc->priority, file); }
Signature · 7 lines
2.14.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 8/8 mm: Remove __GFP_COLD
In reply to Mel GormanAs the page free path makes no distinction between cache hot and cold pages, there is no real useful ordering of pages in the free list that allocation requests can take advantage of. Juding from the users of __GFP_COLD, it is likely that a number of them are the result of copying other sites instead of actually measuring the impact. Remove the __GFP_COLD parameter which simplifies a number of paths in the page allocator.
This is potentially controversial but bear in mind that the size of the per-cpu pagelists versus modern cache sizes means that the whole per-cpu list can often fit in the L3 cache. Hence, there is only a potential benefit for microbenchmarks that alloc/free pages in a tight loop. It's even worse when THP is taken into account which has little or no chance of getting a cache-hot page as the per-cpu list is bypassed and the zeroing of multiple pages will thrash the cache anyway.
The truncate microbenchmarks are not shown as this patch affects the allocation path and not the free path. A page fault microbenchmark was tested but it showed no sigificant difference which is not surprising given that the __GFP_COLD branches are a miniscule percentage of the fault path.
--- drivers/net/ethernet/amazon/ena/ena_netdev.c | 2 +- drivers/net/ethernet/amd/xgbe/xgbe-desc.c | 2 +- drivers/net/ethernet/aquantia/atlantic/aq_ring.c | 3 +-- .../net/ethernet/cavium/liquidio/octeon_network.h | 2 +- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 5 ++--- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 4 ++-- drivers/net/ethernet/qlogic/qlge/qlge_main.c | 3 +-- drivers/net/ethernet/sfc/falcon/rx.c | 2 +- drivers/net/ethernet/sfc/rx.c | 2 +- drivers/net/ethernet/synopsys/dwc-xlgmac-desc.c | 2 +- drivers/net/ethernet/ti/netcp_core.c | 2 +- drivers/net/virtio_net.c | 1 - drivers/staging/lustre/lustre/mdc/mdc_request.c | 2 +- fs/cachefiles/rdwr.c | 6 ++---- include/linux/gfp.h | 5 ----- include/linux/pagemap.h | 8 +------- include/linux/skbuff.h | 2 +- include/linux/slab.h | 3 --- include/trace/events/mmflags.h | 1 - kernel/power/snapshot.c | 4 ++-- mm/filemap.c | 6 +++--- mm/page_alloc.c | 20 ++++++-------------- mm/percpu-vm.c | 2 +- net/core/skbuff.c | 4 ++-- tools/perf/builtin-kmem.c | 1 - 25 files changed, 32 insertions(+), 62 deletions(-)
drivers/net/ethernet/amazon/ena/ena_netdev.c +1 -1
@@ -517,7 +517,7 @@ static int ena_refill_rx_bufs(struct ena_ring *rx_ring, u32 num) rc =ena_alloc_rx_page (rx_ring, rx_info, - __GFP_COLD |GFP_ATOMIC | __GFP_COMP); +GFP_ATOMIC | __GFP_COMP);if (unlikely (rc <0 )) { netif_warn(rx_ring->adapter, rx_err, rx_ring->netdev, "failed to alloc buffer for rx queue %d\n",
drivers/net/ethernet/amd/xgbe/xgbe-desc.c +1 -1
@@ -295,7 +295,7 @@ static int xgbe_alloc_pages(struct xgbe_prv_data *pdata, order = alloc_order;/* Try to obtain pages, decreasing order if necessary */ - gfp =GFP_ATOMIC | __GFP_COLD | __GFP_COMP | __GFP_NOWARN; + gfp =GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN;while (order >=0 ) { pages =alloc_pages_node (node, gfp, order);if (pages)
drivers/net/ethernet/aquantia/atlantic/aq_ring.c +1 -2
@@ -304,8 +304,7 @@ int aq_ring_rx_fill(struct aq_ring_s *self) buff->flags =0U ; buff->len =AQ_CFG_RX_FRAME_MAX ; - buff->page =alloc_pages (GFP_ATOMIC | __GFP_COLD | - __GFP_COMP, pages_order); + buff->page =alloc_pages (GFP_ATOMIC | __GFP_COMP, pages_order);if (!buff->page) { err = -ENOMEM ; goto err_exit;
drivers/net/ethernet/cavium/liquidio/octeon_network.h +1 -1
@@ -195,7 +195,7 @@ static inline voidstruct sk_buff *skb;struct octeon_skb_page_info *skb_pg_info; - page =alloc_page (GFP_ATOMIC | __GFP_COLD); + page =alloc_page (GFP_ATOMIC );if (unlikely (!page))return NULL ;
drivers/net/ethernet/mellanox/mlx4/en_rx.c +2 -3
@@ -193,7 +193,7 @@ static int mlx4_en_fill_rx_buffers(struct mlx4_en_priv *priv)if (mlx4_en_prepare_rx_desc (priv, ring, ring->actual_size, -GFP_KERNEL | __GFP_COLD)) { +GFP_KERNEL )) {if (ring->actual_size <MLX4_EN_MIN_RX_SIZE ) {en_err (priv,"Failed to allocate enough rx buffers\n" );return -ENOMEM ;
@@ -552,8 +552,7 @@ static void mlx4_en_refill_rx_buffers(struct mlx4_en_priv *priv,do {if (mlx4_en_prepare_rx_desc (priv, ring, ring->prod & ring->size_mask, -GFP_ATOMIC | __GFP_COLD | - __GFP_MEMALLOC)) +GFP_ATOMIC | __GFP_MEMALLOC))break ; ring->prod++; }while (likely (--missing));
drivers/net/ethernet/netronome/nfp/nfp_net_common.c +2 -2
@@ -1183,7 +1183,7 @@ static void *nfp_net_rx_alloc_one(struct nfp_net_dp *dp, dma_addr_t *dma_addr)if (!dp->xdp_prog) frag =netdev_alloc_frag (dp->fl_bufsz);else - frag =page_address (alloc_page (GFP_KERNEL | __GFP_COLD)); + frag =page_address (alloc_page (GFP_KERNEL ));if (!frag) {nn_dp_warn (dp,"Failed to alloc receive page frag\n" );return NULL ;
@@ -1206,7 +1206,7 @@ static void *nfp_net_napi_alloc_one(struct nfp_net_dp *dp, dma_addr_t *dma_addr)if (!dp->xdp_prog) frag =napi_alloc_frag (dp->fl_bufsz);else - frag =page_address (alloc_page (GFP_ATOMIC | __GFP_COLD)); + frag =page_address (alloc_page (GFP_ATOMIC ));if (!frag) {nn_dp_warn (dp,"Failed to alloc receive page frag\n" );return NULL ;
drivers/net/ethernet/qlogic/qlge/qlge_main.c +1 -2
@@ -1092,8 +1092,7 @@ static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring, {if (!rx_ring->pg_chunk.page) {u64 map; - rx_ring->pg_chunk.page =alloc_pages (__GFP_COLD | __GFP_COMP | -GFP_ATOMIC , + rx_ring->pg_chunk.page =alloc_pages (__GFP_COMP |GFP_ATOMIC , qdev->lbq_buf_order);if (unlikely (!rx_ring->pg_chunk.page)) { netif_err(qdev, drv, qdev->ndev,
drivers/net/ethernet/sfc/falcon/rx.c +1 -1
@@ -163,7 +163,7 @@ static int ef4_init_rx_buffers(struct ef4_rx_queue *rx_queue, bool atomic) do { page = ef4_reuse_page(rx_queue); if (page == NULL) { - page = alloc_pages(__GFP_COLD | __GFP_COMP | + page = alloc_pages(__GFP_COMP | (atomic ? GFP_ATOMIC : GFP_KERNEL), efx->rx_buffer_order); if (unlikely(page == NULL))
drivers/net/ethernet/sfc/rx.c +1 -1
@@ -163,7 +163,7 @@ static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue, bool atomic) do { page = efx_reuse_page(rx_queue); if (page == NULL) { - page = alloc_pages(__GFP_COLD | __GFP_COMP | + page = alloc_pages(__GFP_COMP | (atomic ? GFP_ATOMIC : GFP_KERNEL), efx->rx_buffer_order); if (unlikely(page == NULL))
drivers/net/ethernet/synopsys/dwc-xlgmac-desc.c +1 -1
@@ -335,7 +335,7 @@ static int xlgmac_alloc_pages(struct xlgmac_pdata *pdata,dma_addr_t pages_dma;/* Try to obtain pages, decreasing order if necessary */ - gfp |= __GFP_COLD | __GFP_COMP | __GFP_NOWARN; + gfp |= __GFP_COMP | __GFP_NOWARN;while (order >=0 ) { pages =alloc_pages (gfp, order);if (pages)
drivers/net/ethernet/ti/netcp_core.c +1 -1
@@ -906,7 +906,7 @@ static int netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq) sw_data[0 ] = (u32 )bufptr; }else {/* Allocate a secondary receive queue entry */ - page =alloc_page (GFP_ATOMIC |GFP_DMA | __GFP_COLD); + page =alloc_page (GFP_ATOMIC |GFP_DMA );if (unlikely (!page)) {dev_warn_ratelimited (netcp->ndev_dev,"Secondary page alloc failed\n" ); goto fail;
drivers/net/virtio_net.c +0 -1
@@ -988,7 +988,6 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,int err;bool oom; - gfp |= __GFP_COLD; do { if (vi->mergeable_rx_bufs) err = add_recvbuf_mergeable(vi, rq, gfp);
drivers/staging/lustre/lustre/mdc/mdc_request.c +1 -1
@@ -1151,7 +1151,7 @@ static int mdc_read_page_remote(void *data, struct page *page0) }for (npages =1 ; npages < max_pages; npages++) { - page =page_cache_alloc_cold (inode->i_mapping); + page =page_cache_alloc (inode->i_mapping);if (!page)break ; page_pool[npages] = page;
fs/cachefiles/rdwr.c +2 -4
@@ -256,8 +256,7 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object, goto backing_page_already_present;if (!newpage) { - newpage =__page_cache_alloc (cachefiles_gfp | - __GFP_COLD); + newpage =__page_cache_alloc (cachefiles_gfp);if (!newpage) goto nomem_monitor; }
@@ -493,8 +492,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, goto backing_page_already_present;if (!newpage) { - newpage =__page_cache_alloc (cachefiles_gfp | - __GFP_COLD); + newpage =__page_cache_alloc (cachefiles_gfp);if (!newpage) goto nomem; }
include/linux/gfp.h +0 -5
@@ -23,7 +23,6 @@ struct vm_area_struct;#define ___GFP_HIGH 0x20u#define ___GFP_IO 0x40u#define ___GFP_FS 0x80u -#define ___GFP_COLD 0x100u#define ___GFP_NOWARN 0x200u#define ___GFP_RETRY_MAYFAIL 0x400u#define ___GFP_NOFAIL 0x800u
@@ -192,9 +191,6 @@ struct vm_area_struct;/* * Action modifiers * -* __GFP_COLD indicates that the caller does not expect to be used in the near -* future. Where possible, a cache-cold page will be returned. -* * __GFP_NOWARN suppresses allocation failure reports. * * __GFP_COMP address compound page metadata.
@@ -207,7 +203,6 @@ struct vm_area_struct;* distinguishing in the source between false positives and allocations that * cannot be supported (e.g. page tables). */ -#define __GFP_COLD ((__force gfp_t)___GFP_COLD)#define __GFP_NOWARN ((__force gfp_t)___GFP_NOWARN)#define __GFP_COMP ((__force gfp_t)___GFP_COMP)#define __GFP_ZERO ((__force gfp_t)___GFP_ZERO)
include/linux/pagemap.h +1 -7
@@ -231,15 +231,9 @@ static inline struct page *page_cache_alloc(struct address_space *x)return __page_cache_alloc (mapping_gfp_mask (x)); } -static inline struct page *page_cache_alloc_cold (struct address_space *x) -{ -return __page_cache_alloc (mapping_gfp_mask (x)|__GFP_COLD); -} -static inline gfp_t readahead_gfp_mask (struct address_space *x) { -return mapping_gfp_mask (x) | - __GFP_COLD | __GFP_NORETRY | __GFP_NOWARN; +return mapping_gfp_mask (x) | __GFP_NORETRY | __GFP_NOWARN; }typedef int filler_t (void *,struct page *);
include/linux/skbuff.h +1 -1
@@ -2675,7 +2675,7 @@ static inline struct page *__dev_alloc_pages(gfp_t gfp_mask,* 4. __GFP_MEMALLOC is ignored if __GFP_NOMEMALLOC is set due to * code in gfp_to_alloc_flags that should be enforcing this. */ - gfp_mask |= __GFP_COLD | __GFP_COMP | __GFP_MEMALLOC; + gfp_mask |= __GFP_COMP | __GFP_MEMALLOC;return alloc_pages_node (NUMA_NO_NODE , gfp_mask, order); }
include/linux/slab.h +0 -3
@@ -458,9 +458,6 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags)* Also it is possible to set different flags by OR'ing * in one or more of the following additional @flags: * -* %__GFP_COLD - Request cache-cold pages instead of -* trying to return cache-warm pages. -* * %__GFP_HIGH - This allocation has high priority and may use emergency pools. * * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail
include/trace/events/mmflags.h +0 -1
@@ -31,7 +31,6 @@ {(unsigned long)__GFP_ATOMIC, "__GFP_ATOMIC"}, \ {(unsigned long)__GFP_IO, "__GFP_IO"}, \ {(unsigned long)__GFP_FS, "__GFP_FS"}, \ - {(unsigned long)__GFP_COLD, "__GFP_COLD"}, \ {(unsigned long)__GFP_NOWARN, "__GFP_NOWARN"}, \ {(unsigned long)__GFP_RETRY_MAYFAIL, "__GFP_RETRY_MAYFAIL"}, \ {(unsigned long)__GFP_NOFAIL, "__GFP_NOFAIL"}, \
kernel/power/snapshot.c +2 -2
@@ -1882,7 +1882,7 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)*/ static inline int get_highmem_buffer (int safe_needed) { - buffer =get_image_page (GFP_ATOMIC | __GFP_COLD, safe_needed); + buffer =get_image_page (GFP_ATOMIC , safe_needed);return buffer ?0 : -ENOMEM ; }
@@ -1943,7 +1943,7 @@ static int swsusp_alloc(struct memory_bitmap *copy_bm,while (nr_pages-- >0 ) {struct page *page; - page =alloc_image_page (GFP_ATOMIC | __GFP_COLD); + page =alloc_image_page (GFP_ATOMIC );if (!page) goto err_out;memory_bm_set_bit (copy_bm,page_to_pfn (page));
mm/filemap.c +3 -3
@@ -2260,7 +2260,7 @@ static ssize_t generic_file_buffered_read(struct kiocb *iocb,* Ok, it wasn't cached, so we need to create a new * page.. */ - page =page_cache_alloc_cold (mapping); + page =page_cache_alloc (mapping);if (!page) { error = -ENOMEM ; goto out;
@@ -2372,7 +2372,7 @@ static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask)int ret; do { - page = __page_cache_alloc(gfp_mask|__GFP_COLD); + page = __page_cache_alloc(gfp_mask); if (!page) return -ENOMEM;
@@ -2776,7 +2776,7 @@ static struct page *do_read_cache_page(struct address_space *mapping, repeat: page =find_get_page (mapping, index);if (!page) { - page =__page_cache_alloc (gfp | __GFP_COLD); + page =__page_cache_alloc (gfp);if (!page)return ERR_PTR (-ENOMEM ); err =add_to_page_cache_lru (page, mapping, index, gfp);
mm/page_alloc.c +6 -14
@@ -2315,7 +2315,7 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order,*/ static int rmqueue_bulk (struct zone *zone,unsigned int order,unsigned long count,struct list_head *list, -int migratetype,bool cold) +int migratetype) {int i, alloced =0 ;
@@ -2337,10 +2337,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,* merge IO requests if the physical pages are ordered * properly. */ -if (likely (!cold)) -list_add (&page->lru, list); -else -list_add_tail (&page->lru, list); +list_add (&page->lru, list); list = &page->lru; alloced++;if (is_migrate_cma (get_pcppage_migratetype (page)))
@@ -2783,7 +2780,7 @@ static inline void zone_statistics(struct zone *preferred_zone, struct zone *z)/* Remove page from the per-cpu list, caller must protect the list */ static struct page *__rmqueue_pcplist (struct zone *zone,int migratetype, -bool cold,struct per_cpu_pages *pcp, +struct per_cpu_pages *pcp,struct list_head *list) {struct page *page;
@@ -2792,16 +2789,12 @@ static struct page *__rmqueue_pcplist(struct zone *zone, int migratetype,if (list_empty (list)) { pcp->count +=rmqueue_bulk (zone,0 , pcp->batch, list, - migratetype, cold); + migratetype);if (unlikely (list_empty (list)))return NULL ; } -if (cold) - page = list_last_entry(list, struct page, lru); -else - page = list_first_entry(list, struct page, lru); - + page = list_first_entry(list, struct page, lru);list_del (&page->lru); pcp->count--; }while (check_new_pcp (page));
@@ -2816,14 +2809,13 @@ static struct page *rmqueue_pcplist(struct zone *preferred_zone, {struct per_cpu_pages *pcp;struct list_head *list; -bool cold = ((gfp_flags & __GFP_COLD) !=0 );struct page *page;unsigned long flags;local_irq_save (flags); pcp = &this_cpu_ptr (zone->pageset)->pcp; list = &pcp->lists[migratetype]; - page =__rmqueue_pcplist (zone, migratetype, cold, pcp, list); + page =__rmqueue_pcplist (zone, migratetype, pcp, list);if (page) {__count_zid_vm_events (PGALLOC ,page_zonenum (page),1 << order);zone_statistics (preferred_zone, zone);
mm/percpu-vm.c +1 -1
@@ -81,7 +81,7 @@ static void pcpu_free_pages(struct pcpu_chunk *chunk,static int pcpu_alloc_pages (struct pcpu_chunk *chunk,struct page **pages,int page_start,int page_end) { -const gfp_t gfp =GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD; +const gfp_t gfp =GFP_KERNEL | __GFP_HIGHMEM;unsigned int cpu, tcpu;int i;
net/core/skbuff.c +2 -2
@@ -357,7 +357,7 @@ static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)*/ void *netdev_alloc_frag (unsigned int fragsz) { -return __netdev_alloc_frag (fragsz,GFP_ATOMIC | __GFP_COLD); +return __netdev_alloc_frag (fragsz,GFP_ATOMIC ); }EXPORT_SYMBOL (netdev_alloc_frag);
@@ -370,7 +370,7 @@ static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask)void *napi_alloc_frag (unsigned int fragsz) { -return __napi_alloc_frag (fragsz,GFP_ATOMIC | __GFP_COLD); +return __napi_alloc_frag (fragsz,GFP_ATOMIC ); }EXPORT_SYMBOL (napi_alloc_frag);
tools/perf/builtin-kmem.c +0 -1
@@ -640,7 +640,6 @@ static const struct { { "__GFP_ATOMIC", "_A" }, { "__GFP_IO", "I" }, { "__GFP_FS", "F" }, - { "__GFP_COLD", "CO" }, { "__GFP_NOWARN", "NWR" }, { "__GFP_RETRY_MAYFAIL", "R" }, { "__GFP_NOFAIL", "NF" },
Signature · 7 lines
2.14.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>