diff options
| -rw-r--r-- | drivers/base/node.c | 2 | ||||
| -rw-r--r-- | include/linux/mm.h | 6 | ||||
| -rw-r--r-- | include/linux/mmzone.h | 11 | ||||
| -rw-r--r-- | init/main.c | 1 | ||||
| -rw-r--r-- | mm/mempolicy.c | 2 | ||||
| -rw-r--r-- | mm/page_alloc.c | 211 |
6 files changed, 195 insertions, 38 deletions
diff --git a/drivers/base/node.c b/drivers/base/node.c index 5d4517ccc422..904b27caf697 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c | |||
| @@ -87,7 +87,7 @@ static ssize_t node_read_numastat(struct sys_device * dev, char * buf) | |||
| 87 | for (i = 0; i < MAX_NR_ZONES; i++) { | 87 | for (i = 0; i < MAX_NR_ZONES; i++) { |
| 88 | struct zone *z = &pg->node_zones[i]; | 88 | struct zone *z = &pg->node_zones[i]; |
| 89 | for (cpu = 0; cpu < NR_CPUS; cpu++) { | 89 | for (cpu = 0; cpu < NR_CPUS; cpu++) { |
| 90 | struct per_cpu_pageset *ps = &z->pageset[cpu]; | 90 | struct per_cpu_pageset *ps = zone_pcp(z,cpu); |
| 91 | numa_hit += ps->numa_hit; | 91 | numa_hit += ps->numa_hit; |
| 92 | numa_miss += ps->numa_miss; | 92 | numa_miss += ps->numa_miss; |
| 93 | numa_foreign += ps->numa_foreign; | 93 | numa_foreign += ps->numa_foreign; |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 17518fe0b311..1813b162b0a8 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
| @@ -691,6 +691,12 @@ extern void show_mem(void); | |||
| 691 | extern void si_meminfo(struct sysinfo * val); | 691 | extern void si_meminfo(struct sysinfo * val); |
| 692 | extern void si_meminfo_node(struct sysinfo *val, int nid); | 692 | extern void si_meminfo_node(struct sysinfo *val, int nid); |
| 693 | 693 | ||
| 694 | #ifdef CONFIG_NUMA | ||
| 695 | extern void setup_per_cpu_pageset(void); | ||
| 696 | #else | ||
| 697 | static inline void setup_per_cpu_pageset(void) {} | ||
| 698 | #endif | ||
| 699 | |||
| 694 | /* prio_tree.c */ | 700 | /* prio_tree.c */ |
| 695 | void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old); | 701 | void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old); |
| 696 | void vma_prio_tree_insert(struct vm_area_struct *, struct prio_tree_root *); | 702 | void vma_prio_tree_insert(struct vm_area_struct *, struct prio_tree_root *); |
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 18fed8b67943..4733d35d8223 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h | |||
| @@ -63,6 +63,12 @@ struct per_cpu_pageset { | |||
| 63 | #endif | 63 | #endif |
| 64 | } ____cacheline_aligned_in_smp; | 64 | } ____cacheline_aligned_in_smp; |
| 65 | 65 | ||
| 66 | #ifdef CONFIG_NUMA | ||
| 67 | #define zone_pcp(__z, __cpu) ((__z)->pageset[(__cpu)]) | ||
| 68 | #else | ||
| 69 | #define zone_pcp(__z, __cpu) (&(__z)->pageset[(__cpu)]) | ||
| 70 | #endif | ||
| 71 | |||
| 66 | #define ZONE_DMA 0 | 72 | #define ZONE_DMA 0 |
| 67 | #define ZONE_NORMAL 1 | 73 | #define ZONE_NORMAL 1 |
| 68 | #define ZONE_HIGHMEM 2 | 74 | #define ZONE_HIGHMEM 2 |
| @@ -122,8 +128,11 @@ struct zone { | |||
| 122 | */ | 128 | */ |
| 123 | unsigned long lowmem_reserve[MAX_NR_ZONES]; | 129 | unsigned long lowmem_reserve[MAX_NR_ZONES]; |
| 124 | 130 | ||
| 131 | #ifdef CONFIG_NUMA | ||
| 132 | struct per_cpu_pageset *pageset[NR_CPUS]; | ||
| 133 | #else | ||
| 125 | struct per_cpu_pageset pageset[NR_CPUS]; | 134 | struct per_cpu_pageset pageset[NR_CPUS]; |
| 126 | 135 | #endif | |
| 127 | /* | 136 | /* |
| 128 | * free areas of different sizes | 137 | * free areas of different sizes |
| 129 | */ | 138 | */ |
diff --git a/init/main.c b/init/main.c index 40bf367ffdf1..d324801729ba 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -490,6 +490,7 @@ asmlinkage void __init start_kernel(void) | |||
| 490 | vfs_caches_init_early(); | 490 | vfs_caches_init_early(); |
| 491 | mem_init(); | 491 | mem_init(); |
| 492 | kmem_cache_init(); | 492 | kmem_cache_init(); |
| 493 | setup_per_cpu_pageset(); | ||
| 493 | numa_policy_init(); | 494 | numa_policy_init(); |
| 494 | if (late_time_init) | 495 | if (late_time_init) |
| 495 | late_time_init(); | 496 | late_time_init(); |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 08c41da429cf..39252c732db2 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -721,7 +721,7 @@ static struct page *alloc_page_interleave(unsigned int __nocast gfp, unsigned or | |||
| 721 | zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK); | 721 | zl = NODE_DATA(nid)->node_zonelists + (gfp & GFP_ZONEMASK); |
| 722 | page = __alloc_pages(gfp, order, zl); | 722 | page = __alloc_pages(gfp, order, zl); |
| 723 | if (page && page_zone(page) == zl->zones[0]) { | 723 | if (page && page_zone(page) == zl->zones[0]) { |
| 724 | zl->zones[0]->pageset[get_cpu()].interleave_hit++; | 724 | zone_pcp(zl->zones[0],get_cpu())->interleave_hit++; |
| 725 | put_cpu(); | 725 | put_cpu(); |
| 726 | } | 726 | } |
| 727 | return page; | 727 | return page; |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 2019c1b19254..95cbd30a67b8 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -71,6 +71,11 @@ EXPORT_SYMBOL(nr_swap_pages); | |||
| 71 | struct zone *zone_table[1 << (ZONES_SHIFT + NODES_SHIFT)]; | 71 | struct zone *zone_table[1 << (ZONES_SHIFT + NODES_SHIFT)]; |
| 72 | EXPORT_SYMBOL(zone_table); | 72 | EXPORT_SYMBOL(zone_table); |
| 73 | 73 | ||
| 74 | #ifdef CONFIG_NUMA | ||
| 75 | static struct per_cpu_pageset | ||
| 76 | pageset_table[MAX_NR_ZONES*MAX_NUMNODES*NR_CPUS] __initdata; | ||
| 77 | #endif | ||
| 78 | |||
| 74 | static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; | 79 | static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; |
| 75 | int min_free_kbytes = 1024; | 80 | int min_free_kbytes = 1024; |
| 76 | 81 | ||
| @@ -520,7 +525,7 @@ static void __drain_pages(unsigned int cpu) | |||
| 520 | for_each_zone(zone) { | 525 | for_each_zone(zone) { |
| 521 | struct per_cpu_pageset *pset; | 526 | struct per_cpu_pageset *pset; |
| 522 | 527 | ||
| 523 | pset = &zone->pageset[cpu]; | 528 | pset = zone_pcp(zone, cpu); |
| 524 | for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { | 529 | for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) { |
| 525 | struct per_cpu_pages *pcp; | 530 | struct per_cpu_pages *pcp; |
| 526 | 531 | ||
| @@ -583,12 +588,12 @@ static void zone_statistics(struct zonelist *zonelist, struct zone *z) | |||
| 583 | 588 | ||
| 584 | local_irq_save(flags); | 589 | local_irq_save(flags); |
| 585 | cpu = smp_processor_id(); | 590 | cpu = smp_processor_id(); |
| 586 | p = &z->pageset[cpu]; | 591 | p = zone_pcp(z,cpu); |
| 587 | if (pg == orig) { | 592 | if (pg == orig) { |
| 588 | z->pageset[cpu].numa_hit++; | 593 | p->numa_hit++; |
| 589 | } else { | 594 | } else { |
| 590 | p->numa_miss++; | 595 | p->numa_miss++; |
| 591 | zonelist->zones[0]->pageset[cpu].numa_foreign++; | 596 | zone_pcp(zonelist->zones[0], cpu)->numa_foreign++; |
| 592 | } | 597 | } |
| 593 | if (pg == NODE_DATA(numa_node_id())) | 598 | if (pg == NODE_DATA(numa_node_id())) |
| 594 | p->local_node++; | 599 | p->local_node++; |
| @@ -615,7 +620,7 @@ static void fastcall free_hot_cold_page(struct page *page, int cold) | |||
| 615 | if (PageAnon(page)) | 620 | if (PageAnon(page)) |
| 616 | page->mapping = NULL; | 621 | page->mapping = NULL; |
| 617 | free_pages_check(__FUNCTION__, page); | 622 | free_pages_check(__FUNCTION__, page); |
| 618 | pcp = &zone->pageset[get_cpu()].pcp[cold]; | 623 | pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; |
| 619 | local_irq_save(flags); | 624 | local_irq_save(flags); |
| 620 | if (pcp->count >= pcp->high) | 625 | if (pcp->count >= pcp->high) |
| 621 | pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0); | 626 | pcp->count -= free_pages_bulk(zone, pcp->batch, &pcp->list, 0); |
| @@ -659,7 +664,7 @@ buffered_rmqueue(struct zone *zone, int order, unsigned int __nocast gfp_flags) | |||
| 659 | if (order == 0) { | 664 | if (order == 0) { |
| 660 | struct per_cpu_pages *pcp; | 665 | struct per_cpu_pages *pcp; |
| 661 | 666 | ||
| 662 | pcp = &zone->pageset[get_cpu()].pcp[cold]; | 667 | pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; |
| 663 | local_irq_save(flags); | 668 | local_irq_save(flags); |
| 664 | if (pcp->count <= pcp->low) | 669 | if (pcp->count <= pcp->low) |
| 665 | pcp->count += rmqueue_bulk(zone, 0, | 670 | pcp->count += rmqueue_bulk(zone, 0, |
| @@ -1262,7 +1267,7 @@ void show_free_areas(void) | |||
| 1262 | if (!cpu_possible(cpu)) | 1267 | if (!cpu_possible(cpu)) |
| 1263 | continue; | 1268 | continue; |
| 1264 | 1269 | ||
| 1265 | pageset = zone->pageset + cpu; | 1270 | pageset = zone_pcp(zone, cpu); |
| 1266 | 1271 | ||
| 1267 | for (temperature = 0; temperature < 2; temperature++) | 1272 | for (temperature = 0; temperature < 2; temperature++) |
| 1268 | printk("cpu %d %s: low %d, high %d, batch %d\n", | 1273 | printk("cpu %d %s: low %d, high %d, batch %d\n", |
| @@ -1645,6 +1650,157 @@ void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone, | |||
| 1645 | memmap_init_zone((size), (nid), (zone), (start_pfn)) | 1650 | memmap_init_zone((size), (nid), (zone), (start_pfn)) |
| 1646 | #endif | 1651 | #endif |
| 1647 | 1652 | ||
| 1653 | static int __devinit zone_batchsize(struct zone *zone) | ||
| 1654 | { | ||
| 1655 | int batch; | ||
| 1656 | |||
| 1657 | /* | ||
| 1658 | * The per-cpu-pages pools are set to around 1000th of the | ||
| 1659 | * size of the zone. But no more than 1/4 of a meg - there's | ||
| 1660 | * no point in going beyond the size of L2 cache. | ||
| 1661 | * | ||
| 1662 | * OK, so we don't know how big the cache is. So guess. | ||
| 1663 | */ | ||
| 1664 | batch = zone->present_pages / 1024; | ||
| 1665 | if (batch * PAGE_SIZE > 256 * 1024) | ||
| 1666 | batch = (256 * 1024) / PAGE_SIZE; | ||
| 1667 | batch /= 4; /* We effectively *= 4 below */ | ||
| 1668 | if (batch < 1) | ||
| 1669 | batch = 1; | ||
| 1670 | |||
