linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [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