Scale ZVC threshold to the size of a zone. Signed-off-by: Christoph Lameter Index: linux-2.6.18-rc1-mm1/mm/vmstat.c =================================================================== --- linux-2.6.18-rc1-mm1.orig/mm/vmstat.c 2006-07-10 10:33:44.369581118 -0700 +++ linux-2.6.18-rc1-mm1/mm/vmstat.c 2006-07-11 11:46:02.834904544 -0700 @@ -112,38 +112,58 @@ void vm_events_fold_cpu(int cpu) atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS]; EXPORT_SYMBOL(vm_stat); +void zap_zone_vm_stats(struct zone *zone) +{ + int cpu; + int threshold; + int mb; + + memset(zone->vm_stat, 0, sizeof(zone->vm_stat)); #ifdef CONFIG_SMP -#define STAT_THRESHOLD 32 + /* + * Increase the threshold for every 4 Megabyte of memory by one. + * The bigger the zone the more flexibility we can give us. + * + * 16MB DMA zone = 4 16*x -y = 4 + * 1GB 1024MB = 32 1024*x -y = 32 + * The minimum threshold of 4 is equal to 256 MB of memory. + * The maximum of 125 reflects 8 Gigabytes. + * + * The inaccuracy per cpu introduced to a counter is < 0.1%. + */ + mb = zone->present_pages >> (20 - PAGE_SHIFT); /* Convert to Megabyte */ + threshold = (mb - 8) / 2; + + /* + * Threshold must be between 4 and 125 + */ + threshold = max(4, min(125, threshold)); -/* - * Determine pointer to currently valid differential byte given a zone and - * the item number. - * - * Preemption must be off - */ -static inline s8 *diff_pointer(struct zone *zone, enum zone_stat_item item) -{ - return &zone_pcp(zone, smp_processor_id())->vm_stat_diff[item]; + for_each_possible_cpu(cpu) + zone_pcp(zone, cpu)->stat_threshold = threshold; +#endif } + +#ifdef CONFIG_SMP + /* * For use when we know that interrupts are disabled. */ void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item, int delta) { - s8 *p; + struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id()); + s8 *p = pcp->vm_stat_diff + item; long x; - p = diff_pointer(zone, item); x = delta + *p; - if (unlikely(x > STAT_THRESHOLD || x < -STAT_THRESHOLD)) { + if (unlikely(x > pcp->stat_threshold || x < -pcp->stat_threshold)) { zone_page_state_add(x, zone, item); x = 0; } - *p = x; } EXPORT_SYMBOL(__mod_zone_page_state); @@ -185,11 +205,12 @@ EXPORT_SYMBOL(mod_zone_page_state); */ static void __inc_zone_state(struct zone *zone, enum zone_stat_item item) { - s8 *p = diff_pointer(zone, item); + struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id()); + s8 *p = pcp->vm_stat_diff + item; (*p)++; - if (unlikely(*p > STAT_THRESHOLD)) { + if (unlikely(*p > pcp->stat_threshold)) { zone_page_state_add(*p, zone, item); *p = 0; } @@ -204,11 +225,12 @@ EXPORT_SYMBOL(__inc_zone_page_state); void __dec_zone_page_state(struct page *page, enum zone_stat_item item) { struct zone *zone = page_zone(page); - s8 *p = diff_pointer(zone, item); + struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id()); + s8 *p = pcp->vm_stat_diff + item; (*p)--; - if (unlikely(*p < -STAT_THRESHOLD)) { + if (unlikely(*p < -pcp->stat_threshold)) { zone_page_state_add(*p, zone, item); *p = 0; } @@ -239,16 +261,12 @@ EXPORT_SYMBOL(inc_zone_page_state); void dec_zone_page_state(struct page *page, enum zone_stat_item item) { unsigned long flags; - struct zone *zone; - s8 *p; + struct zone *zone = page_zone(page); + struct per_cpu_pageset *pcp = zone_pcp(zone, smp_processor_id()); + s8 *p = pcp->vm_stat_diff + item; - zone = page_zone(page); local_irq_save(flags); - p = diff_pointer(zone, item); - - (*p)--; - - if (unlikely(*p < -STAT_THRESHOLD)) { + if (unlikely(*p < -pcp->stat_threshold)) { zone_page_state_add(*p, zone, item); *p = 0; } @@ -500,6 +518,7 @@ static int zoneinfo_show(struct seq_file seq_printf(m, ")" "\n pagesets"); + seq_printf(m, "\n stat_threshold: %i", zone_pcp(zone, 0)->stat_threshold); for_each_online_cpu(i) { struct per_cpu_pageset *pageset; int j; Index: linux-2.6.18-rc1-mm1/include/linux/vmstat.h =================================================================== --- linux-2.6.18-rc1-mm1.orig/include/linux/vmstat.h 2006-07-10 10:33:44.227011832 -0700 +++ linux-2.6.18-rc1-mm1/include/linux/vmstat.h 2006-07-10 13:13:56.724188106 -0700 @@ -163,11 +163,7 @@ extern void zone_statistics(struct zonel #define add_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, __d) #define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d)) -static inline void zap_zone_vm_stats(struct zone *zone) -{ - memset(zone->vm_stat, 0, sizeof(zone->vm_stat)); -} - +extern void zap_zone_vm_stats(struct zone *zone); extern void inc_zone_state(struct zone *, enum zone_stat_item); #ifdef CONFIG_SMP Index: linux-2.6.18-rc1-mm1/include/linux/mmzone.h =================================================================== --- linux-2.6.18-rc1-mm1.orig/include/linux/mmzone.h 2006-07-10 10:33:44.150844679 -0700 +++ linux-2.6.18-rc1-mm1/include/linux/mmzone.h 2006-07-10 13:13:56.724188106 -0700 @@ -77,6 +77,7 @@ struct per_cpu_pages { struct per_cpu_pageset { struct per_cpu_pages pcp[2]; /* 0: hot. 1: cold */ #ifdef CONFIG_SMP + s8 stat_threshold; /* maximum diff before update */ s8 vm_stat_diff[NR_VM_ZONE_STAT_ITEMS]; #endif } ____cacheline_aligned_in_smp;