[3.12 2/3] vmstat: create fold_diff
Subsystems (3)
Both functions that update global counters use the same mechanism.
Create a function that contains the common code.
mm/vmstat.c +11 -7
@@ -414,6 +414,15 @@ void dec_zone_page_state(struct page *paEXPORT_SYMBOL (dec_zone_page_state);#endif +static inline void fold_diff (int *diff) +{ +int i; + +for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++) +if (diff[i]) +atomic_long_add (diff[i], &vm_stat[i]); +} +/* * Update the zone counters for the current cpu. *
@@ -483,10 +492,7 @@ static void refresh_cpu_vm_stats(int cpudrain_zone_pages (zone, &p->pcp);#endif } - -for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++) -if (global_diff[i]) -atomic_long_add (global_diff[i], &vm_stat[i]); +fold_diff (global_diff); }/*
@@ -516,9 +522,7 @@ void cpu_vm_stats_fold(int cpu) } } -for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++) -if (global_diff[i]) -atomic_long_add (global_diff[i], &vm_stat[i]); +fold_diff (global_diff); }/*
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
[3.12 1/3] vmstat: Create separate function to fold per cpu diffs into glocal counters.
In reply to a message not in the archiveIt is better to have a separate folding function because refresh_cpu_vm_stats() also does other things like expire pages in the page allocator caches.
If we have a separate function then refresh_cpu_vm_stats() is only called from the local cpu which allows additional optimizations.
The folding function is only called when a cpu is being downed and therefore no other processor will be accessing the counters. Also simplifies synchronization.
include/linux/vmstat.h +1 -1
@@ -198,7 +198,7 @@ extern void __inc_zone_state(struct zoneextern void dec_zone_state (struct zone *,enum zone_stat_item );extern void __dec_zone_state (struct zone *,enum zone_stat_item ); -void refresh_cpu_vm_stats (int ); +void cpu_vm_stats_fold (int );void refresh_zone_stat_thresholds (void );void drain_zonestat (struct zone *zone,struct per_cpu_pageset *);
mm/page_alloc.c +1 -1
@@ -5361,7 +5361,7 @@ static int page_alloc_cpu_notify(struct* This is only okay since the processor is dead and cannot * race with what we are doing. */ -refresh_cpu_vm_stats (cpu); +cpu_vm_stats_fold (cpu); }return NOTIFY_OK ; }
mm/vmstat.c +34 -6
@@ -415,11 +415,7 @@ EXPORT_SYMBOL(dec_zone_page_state);#endif /* -* Update the zone counters for one cpu. -* -* The cpu specified must be either the current cpu or a processor that -* is not online. If it is the current cpu then the execution thread must -* be pinned to the current cpu. +* Update the zone counters for the current cpu. * * Note that refresh_cpu_vm_stats strives to only access * node local memory. The per cpu pagesets on remote zones are placed
@@ -432,7 +428,7 @@ EXPORT_SYMBOL(dec_zone_page_state);* with the global counters. These could cause remote node cache line * bouncing and will have to be only done when necessary. */ -void refresh_cpu_vm_stats (int cpu) +static void refresh_cpu_vm_stats (int cpu) {struct zone *zone;int i;
@@ -489,6 +485,38 @@ void refresh_cpu_vm_stats(int cpu) }for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++) +if (global_diff[i]) +atomic_long_add (global_diff[i], &vm_stat[i]); +} + +/* +* Fold the data for an offline cpu into the global array. +* There cannot be any access by the offline cpu and therefore +* synchronization is simplified. +*/ +void cpu_vm_stats_fold (int cpu) +{ +struct zone *zone; +int i; +int global_diff[NR_VM_ZONE_STAT_ITEMS ] = {0 , }; + +for_each_populated_zone (zone) { +struct per_cpu_pageset *p; + + p =per_cpu_ptr (zone->pageset, cpu); + +for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++) +if (p->vm_stat_diff[i]) { +int v; + + v = p->vm_stat_diff[i]; + p->vm_stat_diff[i] =0 ; +atomic_long_add (v, &zone->vm_stat[i]); + global_diff[i] += v; + } + } + +for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++)if (global_diff[i])atomic_long_add (global_diff[i], &vm_stat[i]); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
[3.12 3/3] vmstat: Use this_cpu to avoid irqon/off sequence in refresh_cpu_vm_stats
In reply to a message not in the archiveDisabling interrupts repeatedly can be avoided in the inner loop if we use a this_cpu operation.
mm/vmstat.c +16 -19
@@ -437,33 +437,29 @@ static inline void fold_diff(int *diff)* with the global counters. These could cause remote node cache line * bouncing and will have to be only done when necessary. */ -static void refresh_cpu_vm_stats (int cpu) +static void refresh_cpu_vm_stats (void ) {struct zone *zone;int i;int global_diff[NR_VM_ZONE_STAT_ITEMS ] = {0 , };for_each_populated_zone (zone) { -struct per_cpu_pageset *p; +struct per_cpu_pageset __percpu *p = zone->pageset; - p =per_cpu_ptr (zone->pageset, cpu); +for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++) { +int v; -for (i =0 ; i <NR_VM_ZONE_STAT_ITEMS ; i++) -if (p->vm_stat_diff[i]) { -unsigned long flags; -int v; + v =this_cpu_xchg (p->vm_stat_diff[i],0 ); +if (v) { -local_irq_save (flags); - v = p->vm_stat_diff[i]; - p->vm_stat_diff[i] =0 ; -local_irq_restore (flags);atomic_long_add (v, &zone->vm_stat[i]); global_diff[i] += v;#ifdef CONFIG_NUMA /* 3 seconds idle till flush */ - p->expire =3 ; +__this_cpu_write (p->expire,3 );#endif } + }cond_resched ();#ifdef CONFIG_NUMA /*
@@ -473,23 +469,24 @@ static void refresh_cpu_vm_stats(int cpu* Check if there are pages remaining in this pageset * if not then there is nothing to expire. */ -if (!p->expire || !p->pcp.count) +if (!__this_cpu_read (p->expire) || + !__this_cpu_read (p->pcp.count))continue ;/* * We never drain zones local to this processor. */ if (zone_to_nid (zone) ==numa_node_id ()) { - p->expire =0 ; +__this_cpu_write (p->expire,0 );continue ; } - p->expire--; -if (p->expire) + +if (__this_cpu_dec_return (p->expire))continue ; -if (p->pcp.count) -drain_zone_pages (zone, &p->pcp); +if (__this_cpu_read (p->pcp.count)) +drain_zone_pages (zone,__this_cpu_ptr (&p->pcp));#endif }fold_diff (global_diff);
@@ -1209,7 +1206,7 @@ int sysctl_stat_interval __read_mostly =static void vmstat_update (struct work_struct *w) { -refresh_cpu_vm_stats (smp_processor_id ()); +refresh_cpu_vm_stats ();schedule_delayed_work (&__get_cpu_var (vmstat_work),round_jiffies_relative (sysctl_stat_interval)); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>