* [3.12 2/3] vmstat: create fold_diff
[not found] <20130731173202.150701040@linux.com>
@ 2013-07-31 17:32 ` Christoph Lameter
2013-07-31 17:32 ` [3.12 1/3] vmstat: Create separate function to fold per cpu diffs into glocal counters Christoph Lameter
2013-07-31 17:42 ` [3.12 3/3] vmstat: Use this_cpu to avoid irqon/off sequence in refresh_cpu_vm_stats Christoph Lameter
2 siblings, 0 replies; 3+ messages in thread
From: Christoph Lameter @ 2013-07-31 17:32 UTC (permalink / raw)
To: akpm; +Cc: KOSAKI Motohiro, Tejun Heo, Joonsoo Kim, Alexey Dobriyan, linux-mm
Both functions that update global counters use the same mechanism.
Create a function that contains the common code.
Signed-off-by: Christoph Lameter <cl@linux.com>
Index: linux/mm/vmstat.c
===================================================================
--- linux.orig/mm/vmstat.c 2013-07-26 10:37:11.004503227 -0500
+++ linux/mm/vmstat.c 2013-07-26 10:37:11.000503146 -0500
@@ -414,6 +414,15 @@ void dec_zone_page_state(struct page *pa
EXPORT_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 cpu
drain_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 majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 3+ messages in thread
* [3.12 1/3] vmstat: Create separate function to fold per cpu diffs into glocal counters.
[not found] <20130731173202.150701040@linux.com>
2013-07-31 17:32 ` [3.12 2/3] vmstat: create fold_diff Christoph Lameter
@ 2013-07-31 17:32 ` Christoph Lameter
2013-07-31 17:42 ` [3.12 3/3] vmstat: Use this_cpu to avoid irqon/off sequence in refresh_cpu_vm_stats Christoph Lameter
2 siblings, 0 replies; 3+ messages in thread
From: Christoph Lameter @ 2013-07-31 17:32 UTC (permalink / raw)
To: akpm; +Cc: KOSAKI Motohiro, Tejun Heo, Joonsoo Kim, Alexey Dobriyan, linux-mm
It 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.
Signed-off-by: Christoph Lameter <cl@linux.com>
Index: linux/include/linux/vmstat.h
===================================================================
--- linux.orig/include/linux/vmstat.h 2013-07-26 10:36:41.547909803 -0500
+++ linux/include/linux/vmstat.h 2013-07-26 10:36:41.543909722 -0500
@@ -198,7 +198,7 @@ extern void __inc_zone_state(struct zone
extern 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 *);
Index: linux/mm/page_alloc.c
===================================================================
--- linux.orig/mm/page_alloc.c 2013-07-26 10:36:41.547909803 -0500
+++ linux/mm/page_alloc.c 2013-07-26 10:36:41.547909803 -0500
@@ -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;
}
Index: linux/mm/vmstat.c
===================================================================
--- linux.orig/mm/vmstat.c 2013-07-26 10:36:41.547909803 -0500
+++ linux/mm/vmstat.c 2013-07-26 10:36:58.328247861 -0500
@@ -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 majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 3+ messages in thread
* [3.12 3/3] vmstat: Use this_cpu to avoid irqon/off sequence in refresh_cpu_vm_stats
[not found] <20130731173202.150701040@linux.com>
2013-07-31 17:32 ` [3.12 2/3] vmstat: create fold_diff Christoph Lameter
2013-07-31 17:32 ` [3.12 1/3] vmstat: Create separate function to fold per cpu diffs into glocal counters Christoph Lameter
@ 2013-07-31 17:42 ` Christoph Lameter
2 siblings, 0 replies; 3+ messages in thread
From: Christoph Lameter @ 2013-07-31 17:42 UTC (permalink / raw)
To: akpm; +Cc: KOSAKI Motohiro, Tejun Heo, Joonsoo Kim, Alexey Dobriyan, linux-mm
Disabling interrupts repeatedly can be avoided in the inner loop if we
use a this_cpu operation.
Signed-off-by: Christoph Lameter <cl@linux.com>
Index: linux/mm/vmstat.c
===================================================================
--- linux.orig/mm/vmstat.c 2013-07-30 13:41:04.567462579 -0500
+++ linux/mm/vmstat.c 2013-07-30 13:49:17.379563161 -0500
@@ -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 majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-07-31 17:42 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20130731173202.150701040@linux.com>
2013-07-31 17:32 ` [3.12 2/3] vmstat: create fold_diff Christoph Lameter
2013-07-31 17:32 ` [3.12 1/3] vmstat: Create separate function to fold per cpu diffs into glocal counters Christoph Lameter
2013-07-31 17:42 ` [3.12 3/3] vmstat: Use this_cpu to avoid irqon/off sequence in refresh_cpu_vm_stats Christoph Lameter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox