diff options
author | Christoph Lameter <clameter@sgi.com> | 2008-02-05 01:29:19 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:18 -0500 |
commit | 3dfa5721f12c3d5a441448086bee156887daa961 (patch) | |
tree | 8ace8c3f842f8b626b762bb9d2a9b24d8e3bd130 | |
parent | 5dc331852848a38ca00a2817e5b98a1d0561b116 (diff) |
Page allocator: get rid of the list of cold pages
We have repeatedly discussed if the cold pages still have a point. There is
one way to join the two lists: Use a single list and put the cold pages at the
end and the hot pages at the beginning. That way a single list can serve for
both types of allocations.
The discussion of the RFC for this and Mel's measurements indicate that
there may not be too much of a point left to having separate lists for
hot and cold pages (see http://marc.info/?t=119492914200001&r=1&w=2).
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: Martin Bligh <mbligh@mbligh.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/mmzone.h | 2 | ||||
-rw-r--r-- | mm/page_alloc.c | 57 | ||||
-rw-r--r-- | mm/vmstat.c | 30 |
3 files changed, 40 insertions, 49 deletions
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 4c4522a51a3b..8d8d1977736e 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
@@ -113,7 +113,7 @@ struct per_cpu_pages { | |||
113 | }; | 113 | }; |
114 | 114 | ||
115 | struct per_cpu_pageset { | 115 | struct per_cpu_pageset { |
116 | struct per_cpu_pages pcp[2]; /* 0: hot. 1: cold */ | 116 | struct per_cpu_pages pcp; |
117 | #ifdef CONFIG_NUMA | 117 | #ifdef CONFIG_NUMA |
118 | s8 expire; | 118 | s8 expire; |
119 | #endif | 119 | #endif |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5c7de8e959fc..144c0967e702 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -901,24 +901,21 @@ static void drain_pages(unsigned int cpu) | |||
901 | { | 901 | { |
902 | unsigned long flags; | 902 | unsigned long flags; |
903 | struct zone *zone; | 903 | struct zone *zone; |
904 | int i; | ||
905 | 904 | ||
906 | for_each_zone(zone) { | 905 | for_each_zone(zone) { |
907 | struct per_cpu_pageset *pset; | 906 | struct per_cpu_pageset *pset; |
907 | struct per_cpu_pages *pcp; | ||
908 | 908 | ||
909 | if (!populated_zone(zone)) | 909 | if (!populated_zone(zone)) |
910 | continue; | 910 | continue; |
911 | 911 | ||
912 | pset = zone_pcp(zone, cpu); | 912 | pset = zone_pcp(zone, cpu); |
913 | for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { | 913 | |
914 | struct per_cpu_pages *pcp; | 914 | pcp = &pset->pcp; |
915 | 915 | local_irq_save(flags); | |
916 | pcp = &pset->pcp[i]; | 916 | free_pages_bulk(zone, pcp->count, &pcp->list, 0); |
917 | local_irq_save(flags); | 917 | pcp->count = 0; |
918 | free_pages_bulk(zone, pcp->count, &pcp->list, 0); | 918 | local_irq_restore(flags); |
919 | pcp->count = 0; | ||
920 | local_irq_restore(flags); | ||
921 | } | ||
922 | } | 919 | } |
923 | } | 920 | } |
924 | 921 | ||
@@ -993,10 +990,13 @@ static void fastcall free_hot_cold_page(struct page *page, int cold) | |||
993 | arch_free_page(page, 0); | 990 | arch_free_page(page, 0); |
994 | kernel_map_pages(page, 1, 0); | 991 | kernel_map_pages(page, 1, 0); |
995 | 992 | ||
996 | pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; | 993 | pcp = &zone_pcp(zone, get_cpu())->pcp; |
997 | local_irq_save(flags); | 994 | local_irq_save(flags); |
998 | __count_vm_event(PGFREE); | 995 | __count_vm_event(PGFREE); |
999 | list_add(&page->lru, &pcp->list); | 996 | if (cold) |
997 | list_add_tail(&page->lru, &pcp->list); | ||
998 | else | ||
999 | list_add(&page->lru, &pcp->list); | ||
1000 | set_page_private(page, get_pageblock_migratetype(page)); | 1000 | set_page_private(page, get_pageblock_migratetype(page)); |
1001 | pcp->count++; | 1001 | pcp->count++; |
1002 | if (pcp->count >= pcp->high) { | 1002 | if (pcp->count >= pcp->high) { |
@@ -1054,7 +1054,7 @@ again: | |||
1054 | if (likely(order == 0)) { | 1054 | if (likely(order == 0)) { |
1055 | struct per_cpu_pages *pcp; | 1055 | struct per_cpu_pages *pcp; |
1056 | 1056 | ||
1057 | pcp = &zone_pcp(zone, cpu)->pcp[cold]; | 1057 | pcp = &zone_pcp(zone, cpu)->pcp; |
1058 | local_irq_save(flags); | 1058 | local_irq_save(flags); |
1059 | if (!pcp->count) { | 1059 | if (!pcp->count) { |
1060 | pcp->count = rmqueue_bulk(zone, 0, | 1060 | pcp->count = rmqueue_bulk(zone, 0, |
@@ -1064,9 +1064,15 @@ again: | |||
1064 | } | 1064 | } |
1065 | 1065 | ||
1066 | /* Find a page of the appropriate migrate type */ | 1066 | /* Find a page of the appropriate migrate type */ |
1067 | list_for_each_entry(page, &pcp->list, lru) | 1067 | if (cold) { |
1068 | if (page_private(page) == migratetype) | 1068 | list_for_each_entry_reverse(page, &pcp->list, lru) |
1069 | break; | 1069 | if (page_private(page) == migratetype) |
1070 | break; | ||
1071 | } else { | ||
1072 | list_for_each_entry(page, &pcp->list, lru) | ||
1073 | if (page_private(page) == migratetype) | ||
1074 | break; | ||
1075 | } | ||
1070 | 1076 | ||
1071 | /* Allocate more to the pcp list if necessary */ | 1077 | /* Allocate more to the pcp list if necessary */ |
1072 | if (unlikely(&page->lru == &pcp->list)) { | 1078 | if (unlikely(&page->lru == &pcp->list)) { |
@@ -1793,12 +1799,9 @@ void show_free_areas(void) | |||
1793 | 1799 | ||
1794 | pageset = zone_pcp(zone, cpu); | 1800 | pageset = zone_pcp(zone, cpu); |
1795 | 1801 | ||
1796 | printk("CPU %4d: Hot: hi:%5d, btch:%4d usd:%4d " | 1802 | printk("CPU %4d: hi:%5d, btch:%4d usd:%4d\n", |
1797 | "Cold: hi:%5d, btch:%4d usd:%4d\n", | 1803 | cpu, pageset->pcp.high, |
1798 | cpu, pageset->pcp[0].high, | 1804 | pageset->pcp.batch, pageset->pcp.count); |
1799 | pageset->pcp[0].batch, pageset->pcp[0].count, | ||
1800 | pageset->pcp[1].high, pageset->pcp[1].batch, | ||
1801 | pageset->pcp[1].count); | ||
1802 | } | 1805 | } |
1803 | } | 1806 | } |
1804 | 1807 | ||
@@ -2596,17 +2599,11 @@ inline void setup_pageset(struct per_cpu_pageset *p, unsigned long batch) | |||
2596 | 2599 | ||
2597 | memset(p, 0, sizeof(*p)); | 2600 | memset(p, 0, sizeof(*p)); |
2598 | 2601 | ||
2599 | pcp = &p->pcp[0]; /* hot */ | 2602 | pcp = &p->pcp; |
2600 | pcp->count = 0; | 2603 | pcp->count = 0; |
2601 | pcp->high = 6 * batch; | 2604 | pcp->high = 6 * batch; |
2602 | pcp->batch = max(1UL, 1 * batch); | 2605 | pcp->batch = max(1UL, 1 * batch); |
2603 | INIT_LIST_HEAD(&pcp->list); | 2606 | INIT_LIST_HEAD(&pcp->list); |
2604 | |||
2605 | pcp = &p->pcp[1]; /* cold*/ | ||
2606 | pcp->count = 0; | ||
2607 | pcp->high = 2 * batch; | ||
2608 | pcp->batch = max(1UL, batch/2); | ||
2609 | INIT_LIST_HEAD(&pcp->list); | ||
2610 | } | 2607 | } |
2611 | 2608 | ||
2612 | /* | 2609 | /* |
@@ -2619,7 +2616,7 @@ static void setup_pagelist_highmark(struct per_cpu_pageset *p, | |||
2619 | { | 2616 | { |
2620 | struct per_cpu_pages *pcp; | 2617 | struct per_cpu_pages *pcp; |
2621 | 2618 | ||
2622 | pcp = &p->pcp[0]; /* hot list */ | 2619 | pcp = &p->pcp; |
2623 | pcp->high = high; | 2620 | pcp->high = high; |
2624 | pcp->batch = max(1UL, high/4); | 2621 | pcp->batch = max(1UL, high/4); |
2625 | if ((high/4) > (PAGE_SHIFT * 8)) | 2622 | if ((high/4) > (PAGE_SHIFT * 8)) |
diff --git a/mm/vmstat.c b/mm/vmstat.c index 9ffc573ceb6e..888668e0b7db 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c | |||
@@ -337,7 +337,7 @@ void refresh_cpu_vm_stats(int cpu) | |||
337 | * Check if there are pages remaining in this pageset | 337 | * Check if there are pages remaining in this pageset |
338 | * if not then there is nothing to expire. | 338 | * if not then there is nothing to expire. |
339 | */ | 339 | */ |
340 | if (!p->expire || (!p->pcp[0].count && !p->pcp[1].count)) | 340 | if (!p->expire || !p->pcp.count) |
341 | continue; | 341 | continue; |
342 | 342 | ||
343 | /* | 343 | /* |
@@ -352,11 +352,8 @@ void refresh_cpu_vm_stats(int cpu) | |||
352 | if (p->expire) | 352 | if (p->expire) |
353 | continue; | 353 | continue; |
354 | 354 | ||
355 | if (p->pcp[0].count) | 355 | if (p->pcp.count) |
356 | drain_zone_pages(zone, p->pcp + 0); | 356 | drain_zone_pages(zone, &p->pcp); |
357 | |||
358 | if (p->pcp[1].count) | ||
359 | drain_zone_pages(zone, p->pcp + 1); | ||
360 | #endif | 357 | #endif |
361 | } | 358 | } |
362 | 359 | ||
@@ -693,20 +690,17 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, | |||
693 | "\n pagesets"); | 690 | "\n pagesets"); |
694 | for_each_online_cpu(i) { | 691 | for_each_online_cpu(i) { |
695 | struct per_cpu_pageset *pageset; | 692 | struct per_cpu_pageset *pageset; |
696 | int j; | ||
697 | 693 | ||
698 | pageset = zone_pcp(zone, i); | 694 | pageset = zone_pcp(zone, i); |
699 | for (j = 0; j < ARRAY_SIZE(pageset->pcp); j++) { | 695 | seq_printf(m, |
700 | seq_printf(m, | 696 | "\n cpu: %i" |
701 | "\n cpu: %i pcp: %i" | 697 | "\n count: %i" |
702 | "\n count: %i" | 698 | "\n high: %i" |
703 | "\n high: %i" | 699 | "\n batch: %i", |
704 | "\n batch: %i", | 700 | i, |
705 | i, j, | 701 | pageset->pcp.count, |
706 | pageset->pcp[j].count, | 702 | pageset->pcp.high, |
707 | pageset->pcp[j].high, | 703 | pageset->pcp.batch); |
708 | pageset->pcp[j].batch); | ||
709 | } | ||
710 | #ifdef CONFIG_SMP | 704 | #ifdef CONFIG_SMP |
711 | seq_printf(m, "\n vm stats threshold: %d", | 705 | seq_printf(m, "\n vm stats threshold: %d", |
712 | pageset->stat_threshold); | 706 | pageset->stat_threshold); |