diff options
author | Mel Gorman <mel@csn.ul.ie> | 2011-01-13 18:45:56 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:32:33 -0500 |
commit | 3e7d344970673c5334cf7b5bb27c8c0942b06126 (patch) | |
tree | 832ecb4da5fd27efa5a503df5b96bfdee2a52ffd /mm/compaction.c | |
parent | ee64fc9354e515a79c7232cfde65c88ec627308b (diff) |
mm: vmscan: reclaim order-0 and use compaction instead of lumpy reclaim
Lumpy reclaim is disruptive. It reclaims a large number of pages and
ignores the age of the pages it reclaims. This can incur significant
stalls and potentially increase the number of major faults.
Compaction has reached the point where it is considered reasonably stable
(meaning it has passed a lot of testing) and is a potential candidate for
displacing lumpy reclaim. This patch introduces an alternative to lumpy
reclaim whe compaction is available called reclaim/compaction. The basic
operation is very simple - instead of selecting a contiguous range of
pages to reclaim, a number of order-0 pages are reclaimed and then
compaction is later by either kswapd (compact_zone_order()) or direct
compaction (__alloc_pages_direct_compact()).
[akpm@linux-foundation.org: fix build]
[akpm@linux-foundation.org: use conventional task_struct naming]
Signed-off-by: Mel Gorman <mel@csn.ul.ie>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Rik van Riel <riel@redhat.com>
Acked-by: Johannes Weiner <hannes@cmpxchg.org>
Cc: Andy Whitcroft <apw@shadowen.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/compaction.c')
-rw-r--r-- | mm/compaction.c | 89 |
1 files changed, 55 insertions, 34 deletions
diff --git a/mm/compaction.c b/mm/compaction.c index 20011a850fef..8fe917ec7c11 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
@@ -384,10 +384,62 @@ static int compact_finished(struct zone *zone, | |||
384 | return COMPACT_CONTINUE; | 384 | return COMPACT_CONTINUE; |
385 | } | 385 | } |
386 | 386 | ||
387 | /* | ||
388 | * compaction_suitable: Is this suitable to run compaction on this zone now? | ||
389 | * Returns | ||
390 | * COMPACT_SKIPPED - If there are too few free pages for compaction | ||
391 | * COMPACT_PARTIAL - If the allocation would succeed without compaction | ||
392 | * COMPACT_CONTINUE - If compaction should run now | ||
393 | */ | ||
394 | unsigned long compaction_suitable(struct zone *zone, int order) | ||
395 | { | ||
396 | int fragindex; | ||
397 | unsigned long watermark; | ||
398 | |||
399 | /* | ||
400 | * Watermarks for order-0 must be met for compaction. Note the 2UL. | ||
401 | * This is because during migration, copies of pages need to be | ||
402 | * allocated and for a short time, the footprint is higher | ||
403 | */ | ||
404 | watermark = low_wmark_pages(zone) + (2UL << order); | ||
405 | if (!zone_watermark_ok(zone, 0, watermark, 0, 0)) | ||
406 | return COMPACT_SKIPPED; | ||
407 | |||
408 | /* | ||
409 | * fragmentation index determines if allocation failures are due to | ||
410 | * low memory or external fragmentation | ||
411 | * | ||
412 | * index of -1 implies allocations might succeed dependingon watermarks | ||
413 | * index towards 0 implies failure is due to lack of memory | ||
414 | * index towards 1000 implies failure is due to fragmentation | ||
415 | * | ||
416 | * Only compact if a failure would be due to fragmentation. | ||
417 | */ | ||
418 | fragindex = fragmentation_index(zone, order); | ||
419 | if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold) | ||
420 | return COMPACT_SKIPPED; | ||
421 | |||
422 | if (fragindex == -1 && zone_watermark_ok(zone, order, watermark, 0, 0)) | ||
423 | return COMPACT_PARTIAL; | ||
424 | |||
425 | return COMPACT_CONTINUE; | ||
426 | } | ||
427 | |||
387 | static int compact_zone(struct zone *zone, struct compact_control *cc) | 428 | static int compact_zone(struct zone *zone, struct compact_control *cc) |
388 | { | 429 | { |
389 | int ret; | 430 | int ret; |
390 | 431 | ||
432 | ret = compaction_suitable(zone, cc->order); | ||
433 | switch (ret) { | ||
434 | case COMPACT_PARTIAL: | ||
435 | case COMPACT_SKIPPED: | ||
436 | /* Compaction is likely to fail */ | ||
437 | return ret; | ||
438 | case COMPACT_CONTINUE: | ||
439 | /* Fall through to compaction */ | ||
440 | ; | ||
441 | } | ||
442 | |||
391 | /* Setup to move all movable pages to the end of the zone */ | 443 | /* Setup to move all movable pages to the end of the zone */ |
392 | cc->migrate_pfn = zone->zone_start_pfn; | 444 | cc->migrate_pfn = zone->zone_start_pfn; |
393 | cc->free_pfn = cc->migrate_pfn + zone->spanned_pages; | 445 | cc->free_pfn = cc->migrate_pfn + zone->spanned_pages; |
@@ -429,7 +481,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) | |||
429 | return ret; | 481 | return ret; |
430 | } | 482 | } |
431 | 483 | ||
432 | static unsigned long compact_zone_order(struct zone *zone, | 484 | unsigned long compact_zone_order(struct zone *zone, |
433 | int order, gfp_t gfp_mask) | 485 | int order, gfp_t gfp_mask) |
434 | { | 486 | { |
435 | struct compact_control cc = { | 487 | struct compact_control cc = { |
@@ -462,7 +514,6 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist, | |||
462 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); | 514 | enum zone_type high_zoneidx = gfp_zone(gfp_mask); |
463 | int may_enter_fs = gfp_mask & __GFP_FS; | 515 | int may_enter_fs = gfp_mask & __GFP_FS; |
464 | int may_perform_io = gfp_mask & __GFP_IO; | 516 | int may_perform_io = gfp_mask & __GFP_IO; |
465 | unsigned long watermark; | ||
466 | struct zoneref *z; | 517 | struct zoneref *z; |
467 | struct zone *zone; | 518 | struct zone *zone; |
468 | int rc = COMPACT_SKIPPED; | 519 | int rc = COMPACT_SKIPPED; |
@@ -480,43 +531,13 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist, | |||
480 | /* Compact each zone in the list */ | 531 | /* Compact each zone in the list */ |
481 | for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx, | 532 | for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx, |
482 | nodemask) { | 533 | nodemask) { |
483 | int fragindex; | ||
484 | int status; | 534 | int status; |
485 | 535 | ||
486 | /* | ||
487 | * Watermarks for order-0 must be met for compaction. Note | ||
488 | * the 2UL. This is because during migration, copies of | ||
489 | * pages need to be allocated and for a short time, the | ||
490 | * footprint is higher | ||
491 | */ | ||
492 | watermark = low_wmark_pages(zone) + (2UL << order); | ||
493 | if (!zone_watermark_ok(zone, 0, watermark, 0, 0)) | ||
494 | continue; | ||
495 | |||
496 | /* | ||
497 | * fragmentation index determines if allocation failures are | ||
498 | * due to low memory or external fragmentation | ||
499 | * | ||
500 | * index of -1 implies allocations might succeed depending | ||
501 | * on watermarks | ||
502 | * index towards 0 implies failure is due to lack of memory | ||
503 | * index towards 1000 implies failure is due to fragmentation | ||
504 | * | ||
505 | * Only compact if a failure would be due to fragmentation. | ||
506 | */ | ||
507 | fragindex = fragmentation_index(zone, order); | ||
508 | if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold) | ||
509 | continue; | ||
510 | |||
511 | if (fragindex == -1 && zone_watermark_ok(zone, order, watermark, 0, 0)) { | ||
512 | rc = COMPACT_PARTIAL; | ||
513 | break; | ||
514 | } | ||
515 | |||
516 | status = compact_zone_order(zone, order, gfp_mask); | 536 | status = compact_zone_order(zone, order, gfp_mask); |
517 | rc = max(status, rc); | 537 | rc = max(status, rc); |
518 | 538 | ||
519 | if (zone_watermark_ok(zone, order, watermark, 0, 0)) | 539 | /* If a normal allocation would succeed, stop compacting */ |
540 | if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0)) | ||
520 | break; | 541 | break; |
521 | } | 542 | } |
522 | 543 | ||