aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorMel Gorman <mgorman@suse.de>2012-10-08 19:32:41 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 03:22:50 -0400
commitbb13ffeb9f6bfeb301443994dfbf29f91117dfb3 (patch)
tree45e0e6574c0165da9cdc993b3401fe3263e4761c /include/linux
parent753341a4b85ff337487b9959c71c529f522004f4 (diff)
mm: compaction: cache if a pageblock was scanned and no pages were isolated
When compaction was implemented it was known that scanning could potentially be excessive. The ideal was that a counter be maintained for each pageblock but maintaining this information would incur a severe penalty due to a shared writable cache line. It has reached the point where the scanning costs are a serious problem, particularly on long-lived systems where a large process starts and allocates a large number of THPs at the same time. Instead of using a shared counter, this patch adds another bit to the pageblock flags called PG_migrate_skip. If a pageblock is scanned by either migrate or free scanner and 0 pages were isolated, the pageblock is marked to be skipped in the future. When scanning, this bit is checked before any scanning takes place and the block skipped if set. The main difficulty with a patch like this is "when to ignore the cached information?" If it's ignored too often, the scanning rates will still be excessive. If the information is too stale then allocations will fail that might have otherwise succeeded. In this patch o CMA always ignores the information o If the migrate and free scanner meet then the cached information will be discarded if it's at least 5 seconds since the last time the cache was discarded o If there are a large number of allocation failures, discard the cache. The time-based heuristic is very clumsy but there are few choices for a better event. Depending solely on multiple allocation failures still allows excessive scanning when THP allocations are failing in quick succession due to memory pressure. Waiting until memory pressure is relieved would cause compaction to continually fail instead of using reclaim/compaction to try allocate the page. The time-based mechanism is clumsy but a better option is not obvious. Signed-off-by: Mel Gorman <mgorman@suse.de> Acked-by: Rik van Riel <riel@redhat.com> Cc: Richard Davies <richard@arachsys.com> Cc: Shaohua Li <shli@kernel.org> Cc: Avi Kivity <avi@redhat.com> Acked-by: Rafael Aquini <aquini@redhat.com> Cc: Fengguang Wu <fengguang.wu@intel.com> Cc: Michal Nazarewicz <mina86@mina86.com> Cc: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mmzone.h3
-rw-r--r--include/linux/pageblock-flags.h19
2 files changed, 20 insertions, 2 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 16a4cc2950a0..f85ecc9cfa1b 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -369,6 +369,9 @@ struct zone {
369 */ 369 */
370 spinlock_t lock; 370 spinlock_t lock;
371 int all_unreclaimable; /* All pages pinned */ 371 int all_unreclaimable; /* All pages pinned */
372#if defined CONFIG_COMPACTION || defined CONFIG_CMA
373 unsigned long compact_blockskip_expire;
374#endif
372#ifdef CONFIG_MEMORY_HOTPLUG 375#ifdef CONFIG_MEMORY_HOTPLUG
373 /* see spanned/present_pages for more description */ 376 /* see spanned/present_pages for more description */
374 seqlock_t span_seqlock; 377 seqlock_t span_seqlock;
diff --git a/include/linux/pageblock-flags.h b/include/linux/pageblock-flags.h
index 19ef95d293ae..eed27f4f4c3e 100644
--- a/include/linux/pageblock-flags.h
+++ b/include/linux/pageblock-flags.h
@@ -30,6 +30,9 @@ enum pageblock_bits {
30 PB_migrate, 30 PB_migrate,
31 PB_migrate_end = PB_migrate + 3 - 1, 31 PB_migrate_end = PB_migrate + 3 - 1,
32 /* 3 bits required for migrate types */ 32 /* 3 bits required for migrate types */
33#ifdef CONFIG_COMPACTION
34 PB_migrate_skip,/* If set the block is skipped by compaction */
35#endif /* CONFIG_COMPACTION */
33 NR_PAGEBLOCK_BITS 36 NR_PAGEBLOCK_BITS
34}; 37};
35 38
@@ -65,10 +68,22 @@ unsigned long get_pageblock_flags_group(struct page *page,
65void set_pageblock_flags_group(struct page *page, unsigned long flags, 68void set_pageblock_flags_group(struct page *page, unsigned long flags,
66 int start_bitidx, int end_bitidx); 69 int start_bitidx, int end_bitidx);
67 70
71#ifdef CONFIG_COMPACTION
72#define get_pageblock_skip(page) \
73 get_pageblock_flags_group(page, PB_migrate_skip, \
74 PB_migrate_skip + 1)
75#define clear_pageblock_skip(page) \
76 set_pageblock_flags_group(page, 0, PB_migrate_skip, \
77 PB_migrate_skip + 1)
78#define set_pageblock_skip(page) \
79 set_pageblock_flags_group(page, 1, PB_migrate_skip, \
80 PB_migrate_skip + 1)
81#endif /* CONFIG_COMPACTION */
82
68#define get_pageblock_flags(page) \ 83#define get_pageblock_flags(page) \
69 get_pageblock_flags_group(page, 0, NR_PAGEBLOCK_BITS-1) 84 get_pageblock_flags_group(page, 0, PB_migrate_end)
70#define set_pageblock_flags(page, flags) \ 85#define set_pageblock_flags(page, flags) \
71 set_pageblock_flags_group(page, flags, \ 86 set_pageblock_flags_group(page, flags, \
72 0, NR_PAGEBLOCK_BITS-1) 87 0, PB_migrate_end)
73 88
74#endif /* PAGEBLOCK_FLAGS_H */ 89#endif /* PAGEBLOCK_FLAGS_H */