summaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
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 /mm/page_alloc.c
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 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c38
1 files changed, 20 insertions, 18 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 628968c1ccf4..44c56049edf9 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5679,7 +5679,8 @@ __alloc_contig_migrate_alloc(struct page *page, unsigned long private,
5679} 5679}
5680 5680
5681/* [start, end) must belong to a single zone. */ 5681/* [start, end) must belong to a single zone. */
5682static int __alloc_contig_migrate_range(unsigned long start, unsigned long end) 5682static int __alloc_contig_migrate_range(struct compact_control *cc,
5683 unsigned long start, unsigned long end)
5683{ 5684{
5684 /* This function is based on compact_zone() from compaction.c. */ 5685 /* This function is based on compact_zone() from compaction.c. */
5685 5686
@@ -5687,25 +5688,17 @@ static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
5687 unsigned int tries = 0; 5688 unsigned int tries = 0;
5688 int ret = 0; 5689 int ret = 0;
5689 5690
5690 struct compact_control cc = {
5691 .nr_migratepages = 0,
5692 .order = -1,
5693 .zone = page_zone(pfn_to_page(start)),
5694 .sync = true,
5695 };
5696 INIT_LIST_HEAD(&cc.migratepages);
5697
5698 migrate_prep_local(); 5691 migrate_prep_local();
5699 5692
5700 while (pfn < end || !list_empty(&cc.migratepages)) { 5693 while (pfn < end || !list_empty(&cc->migratepages)) {
5701 if (fatal_signal_pending(current)) { 5694 if (fatal_signal_pending(current)) {
5702 ret = -EINTR; 5695 ret = -EINTR;
5703 break; 5696 break;
5704 } 5697 }
5705 5698
5706 if (list_empty(&cc.migratepages)) { 5699 if (list_empty(&cc->migratepages)) {
5707 cc.nr_migratepages = 0; 5700 cc->nr_migratepages = 0;
5708 pfn = isolate_migratepages_range(cc.zone, &cc, 5701 pfn = isolate_migratepages_range(cc->zone, cc,
5709 pfn, end); 5702 pfn, end);
5710 if (!pfn) { 5703 if (!pfn) {
5711 ret = -EINTR; 5704 ret = -EINTR;
@@ -5717,14 +5710,14 @@ static int __alloc_contig_migrate_range(unsigned long start, unsigned long end)
5717 break; 5710 break;
5718 } 5711 }
5719 5712
5720 reclaim_clean_pages_from_list(cc.zone, &cc.migratepages); 5713 reclaim_clean_pages_from_list(cc->zone, &cc->migratepages);
5721 5714
5722 ret = migrate_pages(&cc.migratepages, 5715 ret = migrate_pages(&cc->migratepages,
5723 __alloc_contig_migrate_alloc, 5716 __alloc_contig_migrate_alloc,
5724 0, false, MIGRATE_SYNC); 5717 0, false, MIGRATE_SYNC);
5725 } 5718 }
5726 5719
5727 putback_lru_pages(&cc.migratepages); 5720 putback_lru_pages(&cc->migratepages);
5728 return ret > 0 ? 0 : ret; 5721 return ret > 0 ? 0 : ret;
5729} 5722}
5730 5723
@@ -5803,6 +5796,15 @@ int alloc_contig_range(unsigned long start, unsigned long end,
5803 unsigned long outer_start, outer_end; 5796 unsigned long outer_start, outer_end;
5804 int ret = 0, order; 5797 int ret = 0, order;
5805 5798
5799 struct compact_control cc = {
5800 .nr_migratepages = 0,
5801 .order = -1,
5802 .zone = page_zone(pfn_to_page(start)),
5803 .sync = true,
5804 .ignore_skip_hint = true,
5805 };
5806 INIT_LIST_HEAD(&cc.migratepages);
5807
5806 /* 5808 /*
5807 * What we do here is we mark all pageblocks in range as 5809 * What we do here is we mark all pageblocks in range as
5808 * MIGRATE_ISOLATE. Because pageblock and max order pages may 5810 * MIGRATE_ISOLATE. Because pageblock and max order pages may
@@ -5832,7 +5834,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
5832 if (ret) 5834 if (ret)
5833 goto done; 5835 goto done;
5834 5836
5835 ret = __alloc_contig_migrate_range(start, end); 5837 ret = __alloc_contig_migrate_range(&cc, start, end);
5836 if (ret) 5838 if (ret)
5837 goto done; 5839 goto done;
5838 5840
@@ -5881,7 +5883,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
5881 __reclaim_pages(zone, GFP_HIGHUSER_MOVABLE, end-start); 5883 __reclaim_pages(zone, GFP_HIGHUSER_MOVABLE, end-start);
5882 5884
5883 /* Grab isolated pages from freelists. */ 5885 /* Grab isolated pages from freelists. */
5884 outer_end = isolate_freepages_range(outer_start, end); 5886 outer_end = isolate_freepages_range(&cc, outer_start, end);
5885 if (!outer_end) { 5887 if (!outer_end) {
5886 ret = -EBUSY; 5888 ret = -EBUSY;
5887 goto done; 5889 goto done;