Skip to contentSkip to conversation

Cmpxchg and xchg operations

PATCH In review Christoph Lameter 9 participants 49 messages Dec 14, 2010 – Dec 31, 2010

Subsystems (6)
Memory management x86 ACPI MM core +2 more subsystems
lore
Share & tools
lore
#0 lore raw

v2 cover Cmpxchg and xchg operations

Add cmpxchg and xchg operations to the cpu ops and use them for irq handling and for vm statistics.

Requires the per cpu patches for and_return cpu ops.

V1->V2:
- Determine that cmpxchg without LOCK is faster than xchg with implied lock (numbers are in the patch description).
- Drop 64 bit cpuops operations on 32 bit x86 (resulted in various nasty things such as 64 bit alignment requirements for 64 bit entities on 32 bit, sizable inline code and very complex macros)

#1 lore raw

PATCH v2 1/5 percpu: Generic this_cpu_cmpxchg() and this_cpu_xchg support

Generic code to provide new per cpu atomic features

this_cpu_cmpxchg
this_cpu_xchg

Fallback occurs to functions using interrupts disable/enable to ensure correct per cpu atomicity.

Fallback to regular cmpxchg and xchg is not possible since per cpu atomic semantics include the guarantee that the current cpus per cpu data is accessed atomically. Use of regular cmpxchg and xchg requires the determination of the address of the per cpu data before regular cmpxchg or xchg which therefore cannot be atomically included in an xchg or cmpxchg without segment override.

---
 include/linux/percpu.h |  142 ++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 135 insertions(+), 7 deletions(-)
include/linux/percpu.h +135 -7
Index: linux-2.6/include/linux/percpu.h
===================================================================
@@ -242,21 +242,21 @@ extern void __bad_size_call_parameter(vo
 
 #define __pcpu_size_call_return2(stem, pcp, ...)			\
 ({									\
-	typeof(pcp) ret__;						\
+	typeof(pcp) pscr2_ret__;					\
 	__verify_pcpu_ptr(&(pcp));					\
 	switch(sizeof(pcp)) {						\
-	case 1: ret__ = stem##1(pcp, __VA_ARGS__);			\
+	case 1: pscr2_ret__ = stem##1(pcp, __VA_ARGS__);		\
 		break;							\
-	case 2: ret__ = stem##2(pcp, __VA_ARGS__);			\
+	case 2: pscr2_ret__ = stem##2(pcp, __VA_ARGS__);		\
 		break;							\
-	case 4: ret__ = stem##4(pcp, __VA_ARGS__);			\
+	case 4: pscr2_ret__ = stem##4(pcp, __VA_ARGS__);		\
 		break;							\
-	case 8: ret__ = stem##8(pcp, __VA_ARGS__);			\
+	case 8: pscr2_ret__ = stem##8(pcp, __VA_ARGS__);		\
 		break;							\
 	default:							\
 		__bad_size_call_parameter();break;			\
 	}								\
-	ret__;								\
+	pscr2_ret__;							\
 })
 
 #define __pcpu_size_call(stem, variable, ...)				\
@@ -322,6 +322,106 @@ do {									\
 # define this_cpu_read(pcp)	__pcpu_size_call_return(this_cpu_read_, (pcp))
 #endif
 
+#define __this_cpu_generic_xchg(pcp, nval)				\
+({	typeof(pcp) ret__;						\
+	ret__ = __this_cpu_read(pcp);					\
+	__this_cpu_write(pcp, nval);					\
+	ret__;								\
+})
+
+#ifndef __this_cpu_xchg
+# ifndef __this_cpu_xchg_1
+#  define __this_cpu_xchg_1(pcp, nval)	__this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef __this_cpu_xchg_2
+#  define __this_cpu_xchg_2(pcp, nval)	__this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef __this_cpu_xchg_4
+#  define __this_cpu_xchg_4(pcp, nval)	__this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef __this_cpu_xchg_8
+#  define __this_cpu_xchg_8(pcp, nval)	__this_cpu_generic_xchg(pcp, nval)
+# endif
+# define __this_cpu_xchg(pcp, nval)	__pcpu_size_call_return2(__this_cpu_xchg_, (pcp), nval)
+#endif
+
+#define _this_cpu_generic_xchg(pcp, nval)				\
+({	typeof(pcp) ret__;						\
+	preempt_disable();						\
+	ret__ = __this_cpu_read(pcp);					\
+	__this_cpu_write(pcp, nval);					\
+	preempt_enable();						\
+	ret__;								\
+})
+
+#ifndef this_cpu_xchg
+# ifndef this_cpu_xchg_1
+#  define this_cpu_xchg_1(pcp, nval)	_this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef this_cpu_xchg_2
+#  define this_cpu_xchg_2(pcp, nval)	_this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef this_cpu_xchg_4
+#  define this_cpu_xchg_4(pcp, nval)	_this_cpu_generic_xchg(pcp, nval)
+# endif
+# ifndef this_cpu_xchg_8
+#  define this_cpu_xchg_8(pcp, nval)	_this_cpu_generic_xchg(pcp, nval)
+# endif
+# define this_cpu_xchg(pcp, nval)	__pcpu_size_call_return2(this_cpu_xchg_, (pcp), nval)
+#endif
+
+#define _this_cpu_generic_cmpxchg(pcp, oval, nval)			\
+({	typeof(pcp) ret__;						\
+	preempt_disable();						\
+	ret__ = __this_cpu_read(pcp);					\
+	if (ret__ == (oval))						\
+		__this_cpu_write(pcp, nval);				\
+	preempt_enable();						\
+	ret__;								\
+})
+
+#ifndef this_cpu_cmpxchg
+# ifndef this_cpu_cmpxchg_1
+#  define this_cpu_cmpxchg_1(pcp, oval, nval)	_this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef this_cpu_cmpxchg_2
+#  define this_cpu_cmpxchg_2(pcp, oval, nval)	_this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef this_cpu_cmpxchg_4
+#  define this_cpu_cmpxchg_4(pcp, oval, nval)	_this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef this_cpu_cmpxchg_8
+#  define this_cpu_cmpxchg_8(pcp, oval, nval)	_this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# define this_cpu_cmpxchg(pcp, oval, nval)	__pcpu_size_call_return2(this_cpu_cmpxchg_, pcp, oval, nval)
+#endif
+
+#define __this_cpu_generic_cmpxchg(pcp, oval, nval)			\
+({									\
+	typeof(pcp) ret__;						\
+	ret__ = __this_cpu_read(pcp);					\
+	if (ret__ == (oval))						\
+		__this_cpu_write(pcp, nval);				\
+	ret__;								\
+})
+
+#ifndef __this_cpu_cmpxchg
+# ifndef __this_cpu_cmpxchg_1
+#  define __this_cpu_cmpxchg_1(pcp, oval, nval)	__this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef __this_cpu_cmpxchg_2
+#  define __this_cpu_cmpxchg_2(pcp, oval, nval)	__this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef __this_cpu_cmpxchg_4
+#  define __this_cpu_cmpxchg_4(pcp, oval, nval)	__this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef __this_cpu_cmpxchg_8
+#  define __this_cpu_cmpxchg_8(pcp, oval, nval)	__this_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# define __this_cpu_cmpxchg(pcp, oval, nval)	__pcpu_size_call_return2(\
+				__this_cpu_cmpxchg_, pcp, oval, nval)
+#endif
+
 #define _this_cpu_generic_to_op(pcp, val, op)				\
 do {									\
 	preempt_disable();						\
@@ -610,7 +710,7 @@ do {									\
  * IRQ safe versions of the per cpu RMW operations. Note that these operations
  * are *not* safe against modification of the same variable from another
  * processors (which one gets when using regular atomic operations)
- . They are guaranteed to be atomic vs. local interrupts and
+ * They are guaranteed to be atomic vs. local interrupts and
  * preemption only.
  */
 #define irqsafe_cpu_generic_to_op(pcp, val, op)				\
@@ -697,4 +797,32 @@ do {									\
 # define irqsafe_cpu_xor(pcp, val) __pcpu_size_call(irqsafe_cpu_xor_, (val))
 #endif
 
+#define irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)			\
+({									\
+	typeof(pcp) ret__;						\
+	unsigned long flags;						\
+	local_irq_save(flags);						\
+	ret__ = __this_cpu_read(pcp);					\
+	if (ret__ == (oval))						\
+		__this_cpu_write(pcp, nval);				\
+	local_irq_restore(flags);					\
+	ret__;								\
+})
+
+#ifndef irqsafe_cpu_cmpxchg
+# ifndef irqsafe_cpu_cmpxchg_1
+#  define irqsafe_cpu_cmpxchg_1(pcp, oval, nval)	irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef irqsafe_cpu_cmpxchg_2
+#  define irqsafe_cpu_cmpxchg_2(pcp, oval, nval)	irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef irqsafe_cpu_cmpxchg_4
+#  define irqsafe_cpu_cmpxchg_4(pcp, oval, nval)	irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# ifndef irqsafe_cpu_cmpxchg_8
+#  define irqsafe_cpu_cmpxchg_8(pcp, oval, nval)	irqsafe_cpu_generic_cmpxchg(pcp, oval, nval)
+# endif
+# define irqsafe_cpu_cmpxchg(pcp, oval, nval)	__pcpu_size_call_return2(irqsafe_cpu_cmpxchg_, (pcp), oval, nval)
+#endif
+
 #endif /* __LINUX_PERCPU_H */
#17 lore raw

PATCH v2 5/5 cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Christoph Lameter

Use cmpxchg instead of xchg to realize this_cpu_xchg.

xchg will cause LOCK overhead since LOCK is always implied but cmpxchg will not.

Baselines:

xchg() = 18 cycles (no segment prefix, LOCK semantics)
__this_cpu_xchg = 1 cycle

(simulated using this_cpu_read/write, two prefixes. Looks like the cpu can use loop optimization to get rid of most of the overhead)

Cycles before:

this_cpu_xchg = 37 cycles (segment prefix and LOCK (implied by xchg))

After:

this_cpu_xchg = 11 cycle (using cmpxchg without lock semantics)

---
 arch/x86/include/asm/percpu.h |   21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)
arch/x86/include/asm/percpu.h +15 -6
Index: linux-2.6/arch/x86/include/asm/percpu.h
===================================================================
@@ -213,8 +213,9 @@ do {									\
 })
 
 /*
- * Beware: xchg on x86 has an implied lock prefix. There will be the cost of
- * full lock semantics even though they are not needed.
+ * xchg is implemented using cmpxchg without a lock prefix. xchg is
+ * expensive due to the implied lock prefix. The processor cannot prefetch
+ * cachelines if xchg is used.
  */
 #define percpu_xchg_op(var, nval)					\
 ({									\
@@ -222,25 +223,33 @@ do {									\
 	typeof(var) __new = (nval);					\
 	switch (sizeof(var)) {						\
 	case 1:								\
-		asm("xchgb %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%al"			\
+		    "\n\tcmpxchgb %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "q" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 2:								\
-		asm("xchgw %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%ax"			\
+		    "\n\tcmpxchgw %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 4:								\
-		asm("xchgl %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%eax"			\
+		    "\n\tcmpxchgl %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 8:								\
-		asm("xchgq %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%rax"			\
+		    "\n\tcmpxchgq %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
#14 lore raw

PATCH v2 4/5 vmstat: User per cpu atomics to avoid interrupt disable / enable

In reply to Christoph Lameter

Currently the operations to increment vm counters must disable interrupts in order to not mess up their housekeeping of counters.

So use this_cpu_cmpxchg() to avoid the overhead. Since we can no longer count on preremption being disabled we still have some minor issues. The fetching of the counter thresholds is racy.
A threshold from another cpu may be applied if we happen to be rescheduled on another cpu. However, the following vmstat operation will then bring the counter again under the threshold limit.

The operations for __xxx_zone_state are not changed since the caller has taken care of the synchronization needs (and therefore the cycle count is even less than the optimized version for the irq disable case provided here).

The optimization using this_cpu_cmpxchg will only be used if the arch supports efficient this_cpu_ops (must have CONFIG_CMPXCHG_LOCAL set!)

The use of this_cpu_cmpxchg reduces the cycle count for the counter operations by %80 (inc_zone_page_state goes from 170 cycles to 32).

---
 mm/vmstat.c |  101 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 87 insertions(+), 14 deletions(-)
mm/vmstat.c +87 -14
Index: linux-2.6/mm/vmstat.c
===================================================================
@@ -185,20 +185,6 @@ void __mod_zone_page_state(struct zone *
 EXPORT_SYMBOL(__mod_zone_page_state);
 
 /*
- * For an unknown interrupt state
- */
-void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
-					int delta)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	__mod_zone_page_state(zone, item, delta);
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL(mod_zone_page_state);
-
-/*
  * Optimized increment and decrement functions.
  *
  * These are only for a single page and therefore can take a struct page *
@@ -265,6 +251,92 @@ void __dec_zone_page_state(struct page *
 }
 EXPORT_SYMBOL(__dec_zone_page_state);
 
+#ifdef CONFIG_CMPXCHG_LOCAL
+/*
+ * If we have cmpxchg_local support then we do not need to incur the overhead
+ * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
+ *
+ * mod_state() modifies the zone counter state through atomic per cpu
+ * operations.
+ *
+ * Overstep mode specifies how overstep should handled:
+ *     0       No overstepping
+ *     1       Overstepping half of threshold
+ *     -1      Overstepping minus half of threshold
+*/
+static inline void mod_state(struct zone *zone,
+       enum zone_stat_item item, int delta, int overstep_mode)
+{
+	struct per_cpu_pageset __percpu *pcp = zone->pageset;
+	s8 __percpu *p = pcp->vm_stat_diff + item;
+	long o, n, t, z;
+
+	do {
+		z = 0;  /* overflow to zone counters */
+
+		/*
+		 * The fetching of the stat_threshold is racy. We may apply
+		 * a counter threshold to the wrong the cpu if we get
+		 * rescheduled while executing here. However, the following
+		 * will apply the threshold again and therefore bring the
+		 * counter under the threshold.
+		 */
+		t = this_cpu_read(pcp->stat_threshold);
+
+		o = this_cpu_read(*p);
+		n = delta + o;
+
+		if (n > t || n < -t) {
+			int os = overstep_mode * (t >> 1) ;
+
+			/* Overflow must be added to zone counters */
+			z = n + os;
+			n = -os;
+		}
+	} while (this_cpu_cmpxchg(*p, o, n) != o);
+
+	if (z)
+		zone_page_state_add(z, zone, item);
+}
+
+void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
+					int delta)
+{
+	mod_state(zone, item, delta, 0);
+}
+EXPORT_SYMBOL(mod_zone_page_state);
+
+void inc_zone_state(struct zone *zone, enum zone_stat_item item)
+{
+	mod_state(zone, item, 1, 1);
+}
+
+void inc_zone_page_state(struct page *page, enum zone_stat_item item)
+{
+	mod_state(page_zone(page), item, 1, 1);
+}
+EXPORT_SYMBOL(inc_zone_page_state);
+
+void dec_zone_page_state(struct page *page, enum zone_stat_item item)
+{
+	mod_state(page_zone(page), item, -1, -1);
+}
+EXPORT_SYMBOL(dec_zone_page_state);
+#else
+/*
+ * Use interrupt disable to serialize counter updates
+ */
+void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
+					int delta)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+	__mod_zone_page_state(zone, item, delta);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(mod_zone_page_state);
+
 void inc_zone_state(struct zone *zone, enum zone_stat_item item)
 {
 	unsigned long flags;
@@ -295,6 +367,7 @@ void dec_zone_page_state(struct page *pa
 	local_irq_restore(flags);
 }
 EXPORT_SYMBOL(dec_zone_page_state);
+#endif
 
 /*
  * Update the zone counters for one cpu.
#3 lore raw

PATCH v2 2/5 x86: this_cpu_cmpxchg and this_cpu_xchg operations

In reply to Christoph Lameter

Provide support as far as the hardware capabilities of the x86 cpus allow.

Define CONFIG_CMPXCHG_LOCAL in Kconfig.cpu to allow core code to test for fast cpuops implementations.

V1->V2:
- Take out the definition for this_cpu_cmpxchg_8 and move it into a separate patch.

---
 arch/x86/Kconfig.cpu          |    3 +
 arch/x86/include/asm/percpu.h |  109 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 111 insertions(+), 1 deletion(-)
arch/x86/include/asm/percpu.h +108 -1
Index: linux-2.6/arch/x86/include/asm/percpu.h
===================================================================
@@ -212,6 +212,83 @@ do {									\
 	ret__;								\
 })
 
+/*
+ * Beware: xchg on x86 has an implied lock prefix. There will be the cost of
+ * full lock semantics even though they are not needed.
+ */
+#define percpu_xchg_op(var, nval)					\
+({									\
+	typeof(var) __ret;						\
+	typeof(var) __new = (nval);					\
+	switch (sizeof(var)) {						\
+	case 1:								\
+		asm("xchgb %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "q" (__new)				\
+			    : "memory");				\
+		break;							\
+	case 2:								\
+		asm("xchgw %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "r" (__new)				\
+			    : "memory");				\
+		break;							\
+	case 4:								\
+		asm("xchgl %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "r" (__new)				\
+			    : "memory");				\
+		break;							\
+	case 8:								\
+		asm("xchgq %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "r" (__new)				\
+			    : "memory");				\
+		break;							\
+	default: __bad_percpu_size();					\
+	}								\
+	__ret;								\
+})
+
+/*
+ * cmpxchg has no such implied lock semantics as a result it is much
+ * more efficient for cpu local operations.
+ */
+#define percpu_cmpxchg_op(var, oval, nval)				\
+({									\
+	typeof(var) __ret;						\
+	typeof(var) __old = (oval);					\
+	typeof(var) __new = (nval);					\
+	switch (sizeof(var)) {						\
+	case 1:								\
+		asm("cmpxchgb %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "q" (__new), "0" (__old)			\
+			    : "memory");				\
+		break;							\
+	case 2:								\
+		asm("cmpxchgw %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "r" (__new), "0" (__old)			\
+			    : "memory");				\
+		break;							\
+	case 4:								\
+		asm("cmpxchgl %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "r" (__new), "0" (__old)			\
+			    : "memory");				\
+		break;							\
+	case 8:								\
+		asm("cmpxchgq %2, "__percpu_arg(1)			\
+			    : "=a" (__ret), "+m" (var)			\
+			    : "r" (__new), "0" (__old)			\
+			    : "memory");				\
+		break;							\
+	default: __bad_percpu_size();					\
+	}								\
+	__ret;								\
+})
+
 #define percpu_from_op(op, var, constraint)		\
 ({							\
 	typeof(var) pfo_ret__;				\
@@ -335,6 +412,17 @@ do {									\
 #define irqsafe_cpu_xor_2(pcp, val)	percpu_to_op("xor", (pcp), val)
 #define irqsafe_cpu_xor_4(pcp, val)	percpu_to_op("xor", (pcp), val)
 
+/*
+ * Generic fallback operations for __this_cpu_xchg are okay and much faster
+ * than an xchg with forced lock semantics.
+ */
+#define this_cpu_xchg_1(pcp, nval)	percpu_xchg_op(pcp, nval)
+#define this_cpu_xchg_2(pcp, nval)	percpu_xchg_op(pcp, nval)
+#define this_cpu_xchg_4(pcp, nval)	percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_xchg_1(pcp, nval)	percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_xchg_2(pcp, nval)	percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_xchg_4(pcp, nval)	percpu_xchg_op(pcp, nval)
+
 #ifndef CONFIG_M386
 #define __this_cpu_add_return_1(pcp, val)	percpu_add_return_op(pcp, val)
 #define __this_cpu_add_return_2(pcp, val)	percpu_add_return_op(pcp, val)
@@ -342,7 +430,18 @@ do {									\
 #define this_cpu_add_return_1(pcp, val)		percpu_add_return_op(pcp, val)
 #define this_cpu_add_return_2(pcp, val)		percpu_add_return_op(pcp, val)
 #define this_cpu_add_return_4(pcp, val)		percpu_add_return_op(pcp, val)
-#endif
+
+#define __this_cpu_cmpxchg_1(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define __this_cpu_cmpxchg_2(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define __this_cpu_cmpxchg_4(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define this_cpu_cmpxchg_1(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define this_cpu_cmpxchg_2(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define this_cpu_cmpxchg_4(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_1(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_2(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_4(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#endif /* !CONFIG_M386 */
+
 /*
  * Per cpu atomic 64 bit operations are only available under 64 bit.
  * 32 bit must fall back to generic operations.
@@ -370,6 +469,14 @@ do {									\
 #define __this_cpu_add_return_8(pcp, val)	percpu_add_return_op(pcp, val)
 #define this_cpu_add_return_8(pcp, val)	percpu_add_return_op(pcp, val)
 
+#define __this_cpu_xchg_8(pcp, nval)	percpu_xchg_op(pcp, nval)
+#define this_cpu_xchg_8(pcp, nval)	percpu_xchg_op(pcp, nval)
+#define irqsafe_cpu_xchg_8(pcp, nval)	percpu_xchg_op(pcp, nval)
+
+#define __this_cpu_cmpxchg_8(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define this_cpu_cmpxchg_8(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval)	percpu_cmpxchg_op(pcp, oval, nval)
+
 #endif
 
 /* This is not atomic against other CPUs -- CPU preemption needs to be off */
arch/x86/Kconfig.cpu +3 -0
Index: linux-2.6/arch/x86/Kconfig.cpu
===================================================================
@@ -310,6 +310,9 @@ config X86_INTERNODE_CACHE_SHIFT
 config X86_CMPXCHG
 	def_bool X86_64 || (X86_32 && !M386)
 
+config CMPXCHG_LOCAL
+	def_bool X86_64 || (X86_32 && !M386)
+
 config X86_L1_CACHE_SHIFT
 	int
 	default "7" if MPENTIUM4 || MPSC
#5 lore raw

PATCH v2 3/5 irq_work: Use per cpu atomics instead of regular atomics

In reply to Christoph Lameter

The irq work queue is a per cpu object and it is sufficient for synchronization if per cpu atomics are used. Doing so simplifies the code and reduces the overhead of the code.

Before:

[email protected]$ size kernel/irq_work.o
   text	   data	    bss	    dec	    hex	filename
    451	      8	      1	    460	    1cc	kernel/irq_work.o

After:

[email protected]$ size kernel/irq_work.o 
   text	   data	    bss	    dec	    hex	filename
    438	      8	      1	    447	    1bf	kernel/irq_work.o
---
 kernel/irq_work.c |   18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)
kernel/irq_work.c +9 -9
Index: linux-2.6/kernel/irq_work.c
===================================================================
@@ -77,21 +77,21 @@ void __weak arch_irq_work_raise(void)
  */
 static void __irq_work_queue(struct irq_work *entry)
 {
-	struct irq_work **head, *next;
+	struct irq_work *next;
 
-	head = &get_cpu_var(irq_work_list);
+	preempt_disable();
 
 	do {
-		next = *head;
+		next = __this_cpu_read(irq_work_list);
 		/* Can assign non-atomic because we keep the flags set. */
 		entry->next = next_flags(next, IRQ_WORK_FLAGS);
-	} while (cmpxchg(head, next, entry) != next);
+	} while (this_cpu_cmpxchg(irq_work_list, next, entry) != next);
 
 	/* The list was empty, raise self-interrupt to start processing. */
 	if (!irq_work_next(entry))
 		arch_irq_work_raise();
 
-	put_cpu_var(irq_work_list);
+	preempt_enable();
 }
 
 /*
@@ -120,16 +120,16 @@ EXPORT_SYMBOL_GPL(irq_work_queue);
  */
 void irq_work_run(void)
 {
-	struct irq_work *list, **head;
+	struct irq_work *list;
 
-	head = &__get_cpu_var(irq_work_list);
-	if (*head == NULL)
+	if (this_cpu_read(irq_work_list) == NULL)
 		return;
 
 	BUG_ON(!in_irq());
 	BUG_ON(!irqs_disabled());
 
-	list = xchg(head, NULL);
+	list = this_cpu_xchg(irq_work_list, NULL);
+
 	while (list != NULL) {
 		struct irq_work *entry = list;
 
Acked-by on v2 5/5
#18 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Christoph Lameter
Quoted 13 lines · * Christoph Lameter ([email protected]) wrote:

Use cmpxchg instead of xchg to realize this_cpu_xchg.

xchg will cause LOCK overhead since LOCK is always implied but cmpxchg will not.

Baselines:

xchg() = 18 cycles (no segment prefix, LOCK semantics)
__this_cpu_xchg = 1 cycle

(simulated using this_cpu_read/write, two prefixes. Looks like the cpu can use loop optimization to get rid of most of the overhead)

Quoted 7 lines

Cycles before:

this_cpu_xchg = 37 cycles (segment prefix and LOCK (implied by xchg))

After:

this_cpu_xchg = 11 cycle (using cmpxchg without lock semantics)

Cool! Thanks for benchmarking these, it's really worth it.

Quoted 62 lines
---
 arch/x86/include/asm/percpu.h |   21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

Index: linux-2.6/arch/x86/include/asm/percpu.h
===================================================================

arch/x86/include/asm/percpu.h +15 -6
@@ -213,8 +213,9 @@ do {									\
 })
 
 /*
- * Beware: xchg on x86 has an implied lock prefix. There will be the cost of
- * full lock semantics even though they are not needed.
+ * xchg is implemented using cmpxchg without a lock prefix. xchg is
+ * expensive due to the implied lock prefix. The processor cannot prefetch
+ * cachelines if xchg is used.
  */
 #define percpu_xchg_op(var, nval)					\
 ({									\
@@ -222,25 +223,33 @@ do {									\
 	typeof(var) __new = (nval);					\
 	switch (sizeof(var)) {						\
 	case 1:								\
-		asm("xchgb %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%al"			\
+		    "\n\tcmpxchgb %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "q" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 2:								\
-		asm("xchgw %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%ax"			\
+		    "\n\tcmpxchgw %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 4:								\
-		asm("xchgl %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%eax"			\
+		    "\n\tcmpxchgl %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 8:								\
-		asm("xchgq %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%rax"			\
+		    "\n\tcmpxchgq %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
Signature · 4 lines
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
#19 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Christoph Lameter
Quoted 45 lines · Christoph Lameter

pièce jointe document texte brut (cpuops_xchg_with_cmpxchg) Use cmpxchg instead of xchg to realize this_cpu_xchg.

xchg will cause LOCK overhead since LOCK is always implied but cmpxchg will not.

Baselines:

xchg() = 18 cycles (no segment prefix, LOCK semantics)
__this_cpu_xchg = 1 cycle

(simulated using this_cpu_read/write, two prefixes. Looks like the cpu can use loop optimization to get rid of most of the overhead)

Cycles before:

this_cpu_xchg = 37 cycles (segment prefix and LOCK (implied by xchg))

After:

this_cpu_xchg = 11 cycle (using cmpxchg without lock semantics)

---
 arch/x86/include/asm/percpu.h |   21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

Index: linux-2.6/arch/x86/include/asm/percpu.h
===================================================================

arch/x86/include/asm/percpu.h +3 -2
@@ -213,8 +213,9 @@ do {									\
 })
 
 /*
- * Beware: xchg on x86 has an implied lock prefix. There will be the cost of
- * full lock semantics even though they are not needed.
+ * xchg is implemented using cmpxchg without a lock prefix. xchg is
+ * expensive due to the implied lock prefix. The processor cannot prefetch
+ * cachelines if xchg is used.
  */
 #define percpu_xchg_op(var, nval)					\
 ({									\

arch/x86/include/asm/percpu.h do { \ · line 228

Quoted 7 lines
arch/x86/include/asm/percpu.h +3 -1
@@ -222,25 +223,33 @@ do {									\
 	typeof(var) __new = (nval);					\
 	switch (sizeof(var)) {						\
 	case 1:								\
-		asm("xchgb %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%al"			\
+		    "\n\tcmpxchgb %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\

You should use the fact that the failed cmpxchg loads in al/ax/eax/rax the current value, so :

	"\n\tmov "__percpu_arg(1)",%%al"
	"\n1:\tcmpxchgb %2, "__percpu_arg(1)
	"\n\tjnz 1b"

(No need to reload the value again)

Quoted 31 lines
arch/x86/include/asm/percpu.h +9 -3
 			    : "=a" (__ret), "+m" (var)			\
 			    : "q" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 2:								\
-		asm("xchgw %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%ax"			\
+		    "\n\tcmpxchgw %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 4:								\
-		asm("xchgl %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%eax"			\
+		    "\n\tcmpxchgl %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 8:								\
-		asm("xchgq %2, "__percpu_arg(1)			\
+		asm("\n1:mov "__percpu_arg(1)",%%rax"			\
+		    "\n\tcmpxchgq %2, "__percpu_arg(1)			\
+		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
#20 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Quoted 8 lines · Eric Dumazet

You should use the fact that the failed cmpxchg loads in al/ax/eax/rax the current value, so :

	"\n\tmov "__percpu_arg(1)",%%al"
	"\n1:\tcmpxchgb %2, "__percpu_arg(1)
	"\n\tjnz 1b"

(No need to reload the value again)

Subject: cpuops xchg: Exploit the fact that failed cmpxchges return old value

We do not need to reload the value as pointed out by Eric. It is already in the correct register so just rerun the cmpxchg without the load.

---
 arch/x86/include/asm/percpu.h |   16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
arch/x86/include/asm/percpu.h +8 -8
Index: linux-2.6/arch/x86/include/asm/percpu.h
===================================================================
@@ -223,32 +223,32 @@ do {									\
 	typeof(var) __new = (nval);					\
 	switch (sizeof(var)) {						\
 	case 1:								\
-		asm("\n1:mov "__percpu_arg(1)",%%al"			\
-		    "\n\tcmpxchgb %2, "__percpu_arg(1)			\
+		asm("\n\tmov "__percpu_arg(1)",%%al"			\
+		    "\n1:cmpxchgb %2, "__percpu_arg(1)		\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "q" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 2:								\
-		asm("\n1:mov "__percpu_arg(1)",%%ax"			\
-		    "\n\tcmpxchgw %2, "__percpu_arg(1)			\
+		asm("\n\tmov "__percpu_arg(1)",%%ax"			\
+		    "\n1:cmpxchgw %2, "__percpu_arg(1)		\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 4:								\
-		asm("\n1:mov "__percpu_arg(1)",%%eax"			\
-		    "\n\tcmpxchgl %2, "__percpu_arg(1)			\
+		asm("\n\tmov "__percpu_arg(1)",%%eax"			\
+		    "\n1:cmpxchgl %2, "__percpu_arg(1)		\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 8:								\
-		asm("\n1:mov "__percpu_arg(1)",%%rax"			\
-		    "\n\tcmpxchgq %2, "__percpu_arg(1)			\
+		asm("\n\tmov "__percpu_arg(1)",%%rax"			\
+		    "\n1:cmpxchgq %2, "__percpu_arg(1)		\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
#21 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Quoted 6 lines · Christoph Lameter

We do not need to reload the value as pointed out by Eric. It is already in the correct register so just rerun the cmpxchg without the load.

Is it genuinely faster to do the pre-load mov, or can we drop that too?
My guess would be that yes it is, but if it happens not to be it would
be nice to reduce the code size.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#22 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Quoted 11 lines · H. Peter Anvin
Quoted 6 lines · Christoph Lameter

We do not need to reload the value as pointed out by Eric. It is already in the correct register so just rerun the cmpxchg without the load.

Is it genuinely faster to do the pre-load mov, or can we drop that too?
My guess would be that yes it is, but if it happens not to be it would
be nice to reduce the code size.

Dropping the load increases the cycle count from 11 to 16.

---
 arch/x86/include/asm/percpu.h |   12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)
arch/x86/include/asm/percpu.h +4 -8
Index: linux-2.6/arch/x86/include/asm/percpu.h
===================================================================
@@ -223,32 +223,28 @@ do {									\
 	typeof(var) __new = (nval);					\
 	switch (sizeof(var)) {						\
 	case 1:								\
-		asm("\n1:mov "__percpu_arg(1)",%%al"			\
-		    "\n\tcmpxchgb %2, "__percpu_arg(1)			\
+		asm("\n1:cmpxchgb %2, "__percpu_arg(1)			\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "q" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 2:								\
-		asm("\n1:mov "__percpu_arg(1)",%%ax"			\
-		    "\n\tcmpxchgw %2, "__percpu_arg(1)			\
+		asm("\n1:cmpxchgw %2, "__percpu_arg(1)			\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 4:								\
-		asm("\n1:mov "__percpu_arg(1)",%%eax"			\
-		    "\n\tcmpxchgl %2, "__percpu_arg(1)			\
+		asm("\n1:cmpxchgl %2, "__percpu_arg(1)			\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
 			    : "memory");				\
 		break;							\
 	case 8:								\
-		asm("\n1:mov "__percpu_arg(1)",%%rax"			\
-		    "\n\tcmpxchgq %2, "__percpu_arg(1)			\
+		asm("\n1:cmpxchgq %2, "__percpu_arg(1)			\
 		    "\n\tjnz 1b"					\
 			    : "=a" (__ret), "+m" (var)			\
 			    : "r" (__new)				\
#23 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Quoted 7 lines · Christoph Lameter
Quoted 4 lines

Is it genuinely faster to do the pre-load mov, or can we drop that too?
My guess would be that yes it is, but if it happens not to be it would
be nice to reduce the code size.

Dropping the load increases the cycle count from 11 to 16.

Great, that answers that! I'll pick up the patch hopefully today (I'm finally ramping back up on arch/x86 again after having been diverted to an internal project for a while...)

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
maintainer
#24 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Hello,

Quoted 11 lines · H. Peter Anvin
Quoted 6 lines · Christoph Lameter
Quoted 4 lines

Is it genuinely faster to do the pre-load mov, or can we drop that too?
My guess would be that yes it is, but if it happens not to be it would
be nice to reduce the code size.

Dropping the load increases the cycle count from 11 to 16.

Great, that answers that! I'll pick up the patch hopefully today (I'm finally ramping back up on arch/x86 again after having been diverted to an internal project for a while...)

How do you want to route these? All patches before this series is already in the percpu tree. I can pull the generic bits and leave out the x86 bits so that x86 tree can pull in percpu bits and then put x86 stuff on top of it. If you wanna go that way, I would drop all x86 related patches from the previous patchsets too.

Thanks.

Signature · 1 line
tejun
#25 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Quoted 9 lines · Tejun Heo
Quoted 3 lines

Great, that answers that! I'll pick up the patch hopefully today (I'm finally ramping back up on arch/x86 again after having been diverted to an internal project for a while...)

How do you want to route these? All patches before this series is already in the percpu tree. I can pull the generic bits and leave out the x86 bits so that x86 tree can pull in percpu bits and then put x86 stuff on top of it. If you wanna go that way, I would drop all x86 related patches from the previous patchsets too.

I think it is better to merge the generic pieces and x86 at the same time. Since this has worked so well with the percpu tree so far I'd say we continue that way.

Regardless of how this will be merged: It would be good if hpa would take a look at the patches we have accumulated so far.

#26 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Tejun Heo
Quoted 15 lines · Tejun Heo

Hello,

Quoted 11 lines · H. Peter Anvin
Quoted 6 lines · Christoph Lameter
Quoted 4 lines

Is it genuinely faster to do the pre-load mov, or can we drop that too?
My guess would be that yes it is, but if it happens not to be it would
be nice to reduce the code size.

Dropping the load increases the cycle count from 11 to 16.

Great, that answers that! I'll pick up the patch hopefully today (I'm finally ramping back up on arch/x86 again after having been diverted to an internal project for a while...)

Quoted 6 lines

How do you want to route these? All patches before this series is already in the percpu tree. I can pull the generic bits and leave out the x86 bits so that x86 tree can pull in percpu bits and then put x86 stuff on top of it. If you wanna go that way, I would drop all x86 related patches from the previous patchsets too.

It's probably easiest if you just add them with my Acked-by: then. Alternatively, I could pick them up so they go into -tip and the tip test machinery.

-hpa

maintainer
#27 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Hello,

Quoted 3 lines · H. Peter Anvin

It's probably easiest if you just add them with my Acked-by: then. Alternatively, I could pick them up so they go into -tip and the tip test machinery.

All patches accepted into percpu till now are in the following branch.

git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git for-next

The tree is based on v2.6.37-rc5 and v2.6.37-rc5..for-next would give 21 patches. I think most of these don't fit x86 tree but there are several which would fit there much better. d80aadf9 (x86: Replace uses of current_cpu_data with this_cpu ops) and e5195e91 (x86: Use this_cpu_inc_return for nmi counter).

As it would be beneficial to push these through -tip testing anyway, how about the following?

* If you review and ack the x86 related bits in the series, I'll regenerated and add the ACKs.

* It would be better if the two commits mentioned above get routed through x86 tree rather than percpu tree, so I'll drop the above two from percpu tree and you can pull percpu into x86 and then apply those in x86 tree.

Thanks.

Signature · 1 line
tejun
maintainer
#6 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

In reply to Christoph Lameter
Quoted 10 lines · Christoph Lameter

The irq work queue is a per cpu object and it is sufficient for synchronization if per cpu atomics are used. Doing so simplifies the code and reduces the overhead of the code.

Before:

[email protected]$ size kernel/irq_work.o
   text	   data	    bss	    dec	    hex	filename
    451	      8	      1	    460	    1cc	kernel/irq_work.o
Quoted 7 lines

After:

[email protected]$ size kernel/irq_work.o 
   text	   data	    bss	    dec	    hex	filename
    438	      8	      1	    447	    1bf	kernel/irq_work.o
Cc Peter Zijlstra <[email protected]>

Peter, can you please ack this one?

Thanks.

Signature · 1 line
tejun
reviewer Acked-by
#7 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

Quoted 17 lines · Tejun Heo
Quoted 16 lines · Christoph Lameter

The irq work queue is a per cpu object and it is sufficient for synchronization if per cpu atomics are used. Doing so simplifies the code and reduces the overhead of the code.

Before:

[email protected]$ size kernel/irq_work.o
   text	   data	    bss	    dec	    hex	filename
    451	      8	      1	    460	    1cc	kernel/irq_work.o

After:

[email protected]$ size kernel/irq_work.o 
   text	   data	    bss	    dec	    hex	filename
    438	      8	      1	    447	    1bf	kernel/irq_work.o
Quoted 6 lines
Quoted 1 line
Cc Peter Zijlstra <[email protected]>

Peter, can you please ack this one?

Thanks.

... for tis whole series.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#28 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Tejun Heo
Quoted 20 lines · Tejun Heo

Hello,

Quoted 3 lines · H. Peter Anvin

It's probably easiest if you just add them with my Acked-by: then. Alternatively, I could pick them up so they go into -tip and the tip test machinery.

All patches accepted into percpu till now are in the following branch.

git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git for-next

The tree is based on v2.6.37-rc5 and v2.6.37-rc5..for-next would give 21 patches. I think most of these don't fit x86 tree but there are several which would fit there much better. d80aadf9 (x86: Replace uses of current_cpu_data with this_cpu ops) and e5195e91 (x86: Use this_cpu_inc_return for nmi counter).

As it would be beneficial to push these through -tip testing anyway, how about the following?

Quoted 8 lines

* If you review and ack the x86 related bits in the series, I'll regenerated and add the ACKs.

* It would be better if the two commits mentioned above get routed through x86 tree rather than percpu tree, so I'll drop the above two from percpu tree and you can pull percpu into x86 and then apply those in x86 tree.

I think we can do that... let me look through the tree first officially committing. Alternatively, I can pull the patches from your tree and individually review them and add them to a tip branch, if you prefer.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
maintainer
#29 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Hello,

Quoted 3 lines · H. Peter Anvin

I think we can do that... let me look through the tree first officially committing. Alternatively, I can pull the patches from your tree and individually review them and add them to a tip branch, if you prefer.

I'd prefer percpu things going through percpu tree, if for nothing else for git history's sake, but I don't think it really matters. The series is spread all over the place anyway. As long as each maintainer is properly alerted about the changes, it should be okay. Please let me know whether you agree with the changes currently queued in percpu#for-next. I'll update the tree with your Acked-by's and freeze it.

Thanks.

Signature · 1 line
tejun
maintainer
#15 lore raw

Re: [cpuops cmpxchg V2 4/5] vmstat: User per cpu atomics to avoid interrupt disable / enable

In reply to Christoph Lameter
Quoted 15 lines · Christoph Lameter

Currently the operations to increment vm counters must disable interrupts in order to not mess up their housekeeping of counters.

So use this_cpu_cmpxchg() to avoid the overhead. Since we can no longer count on preremption being disabled we still have some minor issues. The fetching of the counter thresholds is racy.
A threshold from another cpu may be applied if we happen to be rescheduled on another cpu. However, the following vmstat operation will then bring the counter again under the threshold limit.

The operations for __xxx_zone_state are not changed since the caller has taken care of the synchronization needs (and therefore the cycle count is even less than the optimized version for the irq disable case provided here).

Quoted 8 lines

The optimization using this_cpu_cmpxchg will only be used if the arch supports efficient this_cpu_ops (must have CONFIG_CMPXCHG_LOCAL set!)

The use of this_cpu_cmpxchg reduces the cycle count for the counter operations by %80 (inc_zone_page_state goes from 170 cycles to 32).

+/*
+ * If we have cmpxchg_local support then we do not need to incur the overhead
+ * that comes with local_irq_save/restore if we use this_cpu_cmpxchg.
+ *
+ * mod_state() modifies the zone counter state through atomic per cpu
+ * operations.
+ *
+ * Overstep mode specifies how overstep should handled:

+ *     0       No overstepping
+ *     1       Overstepping half of threshold
+ *     -1      Overstepping minus half of threshold

+*/
+static inline void mod_state(struct zone *zone,
+ enum zone_stat_item item, int delta, int overstep_mode)
+{
+ struct per_cpu_pageset __percpu *pcp = zone->pageset;
+ s8 __percpu *p = pcp->vm_stat_diff + item;
+ long o, n, t, z;
+
+ do {
+ z = 0; /* overflow to zone counters */
+
+ /*
+ * The fetching of the stat_threshold is racy. We may apply
+ * a counter threshold to the wrong the cpu if we get
+ * rescheduled while executing here. However, the following
+ * will apply the threshold again and therefore bring the
+ * counter under the threshold.
+ */

What does "the following" mean here? Later executions of the function? It seems like the counter can go out of the threshold at least temporarily, which probably is okay but I think the comment can be improved a bit.

Thanks.

Signature · 1 line
tejun
maintainer
#48 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Christoph Lameter
Quoted 15 lines · Christoph Lameter

Use cmpxchg instead of xchg to realize this_cpu_xchg.

xchg will cause LOCK overhead since LOCK is always implied but cmpxchg will not.

Baselines:

xchg() = 18 cycles (no segment prefix, LOCK semantics)
__this_cpu_xchg = 1 cycle

(simulated using this_cpu_read/write, two prefixes. Looks like the cpu can use loop optimization to get rid of most of the overhead)

Cycles before:

Quoted 7 lines

this_cpu_xchg = 37 cycles (segment prefix and LOCK (implied by xchg))

After:

this_cpu_xchg = 11 cycle (using cmpxchg without lock semantics)

It's not a bad idea to keep this patch separate from the original one but as both are not applied yet, it probably is better to put this right after the original addition if you end up re-posting the series; otherwise, I'll just reorder it when I apply.

Thanks.

Signature · 1 line
tejun
#8 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

In reply to Tejun Heo
Quoted 13 lines · Tejun Heo
Quoted 12 lines · Christoph Lameter

The irq work queue is a per cpu object and it is sufficient for synchronization if per cpu atomics are used. Doing so simplifies the code and reduces the overhead of the code.

Before:

[email protected]$ size kernel/irq_work.o
   text	   data	    bss	    dec	    hex	filename
    451	      8	      1	    460	    1cc	kernel/irq_work.o

After:

Quoted 7 lines
Quoted 5 lines
[email protected]$ size kernel/irq_work.o 
   text	   data	    bss	    dec	    hex	filename
    438	      8	      1	    447	    1bf	kernel/irq_work.o
Cc Peter Zijlstra <[email protected]>

Peter, can you please ack this one?

I guess so, I don't much like the bare preempt_disable/enable there, and I'm wondering, aren't %fs prefixed insn slower than regular insn? Does it really pay to avoid this one address computation if there's multiple users in a function. %fs prefixes do take another byte, so it will also result in larger code at some point.

#16 lore raw

Re: [cpuops cmpxchg V2 4/5] vmstat: User per cpu atomics to avoid interrupt disable / enable

In reply to Tejun Heo
Quoted 8 lines · Tejun Heo
(quoted diff) +7 -0
+		/*
+		 * The fetching of the stat_threshold is racy. We may apply
+		 * a counter threshold to the wrong the cpu if we get
+		 * rescheduled while executing here. However, the following
+		 * will apply the threshold again and therefore bring the
+		 * counter under the threshold.
+		 */
Quoted 4 lines

What does "the following" mean here? Later executions of the function? It seems like the counter can go out of the threshold at least temporarily, which probably is okay but I think the comment can be improved a bit.

I meant later execution of the function. I will fix the comment.

Subject: vmstat comment fix

Clarify comments for the threshold a bit.

---
 mm/vmstat.c |    9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
mm/vmstat.c +6 -3
Index: linux-2.6/mm/vmstat.c
===================================================================
@@ -277,9 +277,12 @@ static inline void mod_state(struct zone
 		/*
 		 * The fetching of the stat_threshold is racy. We may apply
 		 * a counter threshold to the wrong the cpu if we get
-		 * rescheduled while executing here. However, the following
-		 * will apply the threshold again and therefore bring the
-		 * counter under the threshold.
+		 * rescheduled while executing here. However, the next
+		 * counter update will apply the threshold again and
+		 * therefore bring the counter under the threshold again.
+		 *
+		 * Most of the time the thresholds are the same anyways
+		 * for all cpus in a zone.
 		 */
 		t = this_cpu_read(pcp->stat_threshold);
 
#9 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

In reply to Peter Zijlstra
Quoted 20 lines · Peter Zijlstra
Quoted 19 lines · Tejun Heo
Quoted 17 lines · Christoph Lameter

The irq work queue is a per cpu object and it is sufficient for synchronization if per cpu atomics are used. Doing so simplifies the code and reduces the overhead of the code.

Before:

[email protected]$ size kernel/irq_work.o
   text	   data	    bss	    dec	    hex	filename
    451	      8	      1	    460	    1cc	kernel/irq_work.o

After:

[email protected]$ size kernel/irq_work.o
   text	   data	    bss	    dec	    hex	filename
    438	      8	      1	    447	    1bf	kernel/irq_work.o
Cc Peter Zijlstra <[email protected]>
Quoted 7 lines
Quoted 1 line

Peter, can you please ack this one?

I guess so, I don't much like the bare preempt_disable/enable there, and I'm wondering, aren't %fs prefixed insn slower than regular insn? Does it really pay to avoid this one address computation if there's multiple users in a function. %fs prefixes do take another byte, so it will also result in larger code at some point.

Prefixes are faster than explicit address calculations. A prefix allows you to integrate the per cpu address calculation into an arithmetic operation.

A prefix is one byte which is less that multiple arithmetic operations to calculate an address.

I am not sure that the preempt_disable/enable is needed. They are just there because you had a get/put_cpu there.

If the code is run from hardirq context then preempt is already disabled. We can just drop those then.

#10 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

Quoted 3 lines · Christoph Lameter

Prefixes are faster than explicit address calculations. A prefix allows you to integrate the per cpu address calculation into an arithmetic operation.

Well, depends on how often you need that address I'd think. If you'd have a per-cpu struct and need to frob lots of variables in that struct it might be cheaper to simply compute the struct address once and then use relative addresses than to prefix everything with %fs.

Quoted 2 lines

A prefix is one byte which is less that multiple arithmetic operations to calculate an address.

I thought you'd only need a single arithmetic op to calculate the address, anyway at some point those 1 byte prefixes will add up to more than the ops saved.

In the current code you add 2 bytes (although you safe one from loosing the LOCK prefix, but that could have been achieved by using cmpxchg_local() as well. These 2 bytes are probably less than the address computation for head (and not needing the head pointer again saves on register pressure) so its probably a win here.

Still, non of this is really fast-path code, so I really wonder why we're optimizing this over keeping the code obvious.

Quoted 5 lines

I am not sure that the preempt_disable/enable is needed. They are just there because you had a get/put_cpu there.

If the code is run from hardirq context then preempt is already disabled. We can just drop those then.

Afaik the current callers are all from IRQ/NMI context, but I don't want to mandate callers be from such contexts.

The problem is that we need to guarantee we raise the self-IPI on the same cpu we queued the worklet on.

#11 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

Quoted 11 lines · Peter Zijlstra
Quoted 3 lines · Christoph Lameter

Prefixes are faster than explicit address calculations. A prefix allows you to integrate the per cpu address calculation into an arithmetic operation.

Well, depends on how often you need that address I'd think. If you'd have a per-cpu struct and need to frob lots of variables in that struct it might be cheaper to simply compute the struct address once and then use relative addresses than to prefix everything with %fs.

Let's just make it clear -- current x86 CPUs generally do not have a penalty for prefixes (it might be that under very unusual pipeline conditions they do, I am not 100% sure.) In fact, we changed patching LOCK prefixes from NOP to %ds: because it made the code faster.

Some older CPUs do, but those are no longer relevant for performance decisions.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#12 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

In reply to Peter Zijlstra
Quoted 6 lines · Peter Zijlstra
Quoted 2 lines

A prefix is one byte which is less that multiple arithmetic operations to calculate an address.

I thought you'd only need a single arithmetic op to calculate the address, anyway at some point those 1 byte prefixes will add up to more than the ops saved.

Yes if you have enough of those then it may no longer be worth it. But here you only have two. And the segment address calculation is efficiently implemented in the processors.

Quoted 2 lines

Still, non of this is really fast-path code, so I really wonder why we're optimizing this over keeping the code obvious.

I was looking for usecases that already exist for cmpxchg (because the patches introduce this_cpu_cmpxchg also for other uses) and found this one here and it looked like an easy way to use the prefixed operation. Its not that high of a priority but it seems that we are saving code and cycles.

The code is cleaner IMHO. this_cpu_xx documents that the actions here only have local effects and that there is no need of serialization with other processors.

#30 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Tejun Heo

Hey, again.

Quoted 7 lines · Tejun Heo

I'd prefer percpu things going through percpu tree, if for nothing else for git history's sake, but I don't think it really matters. The series is spread all over the place anyway. As long as each maintainer is properly alerted about the changes, it should be okay. Please let me know whether you agree with the changes currently queued in percpu#for-next. I'll update the tree with your Acked-by's and freeze it.

Are you okay with the patches currently in percpu#for-next? If so, I'll regenerate patches with your acked-by and pop the two previously mentioned commits and proceed with the rest of the series.

Thank you.

Signature · 1 line
tejun
#31 lore raw

x86: Use this_cpu_has for thermal_interrupt

It is more effective to use a segment prefix instead of calculating the address of the current cpu area amd then testing flags.

---
 arch/x86/kernel/cpu/mcheck/therm_throt.c |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
arch/x86/kernel/cpu/mcheck/therm_throt.c +3 -4
Index: linux-2.6/arch/x86/kernel/cpu/mcheck/therm_throt.c
===================================================================
@@ -317,7 +317,6 @@ device_initcall(thermal_throttle_init_de
 static void intel_thermal_interrupt(void)
 {
 	__u64 msr_val;
-	struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
 
 	rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
 
@@ -326,19 +325,19 @@ static void intel_thermal_interrupt(void
 				CORE_LEVEL) != 0)
 		mce_log_therm_throt_event(CORE_THROTTLED | msr_val);
 
-	if (cpu_has(c, X86_FEATURE_PLN))
+	if (this_cpu_has(X86_FEATURE_PLN))
 		if (therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
 					POWER_LIMIT_EVENT,
 					CORE_LEVEL) != 0)
 			mce_log_therm_throt_event(CORE_POWER_LIMIT | msr_val);
 
-	if (cpu_has(c, X86_FEATURE_PTS)) {
+	if (this_cpu_has(X86_FEATURE_PTS)) {
 		rdmsrl(MSR_IA32_PACKAGE_THERM_STATUS, msr_val);
 		if (therm_throt_process(msr_val & PACKAGE_THERM_STATUS_PROCHOT,
 					THERMAL_THROTTLING_EVENT,
 					PACKAGE_LEVEL) != 0)
 			mce_log_therm_throt_event(PACKAGE_THROTTLED | msr_val);
-		if (cpu_has(c, X86_FEATURE_PLN))
+		if (this_cpu_has(X86_FEATURE_PLN))
 			if (therm_throt_process(msr_val &
 					PACKAGE_THERM_STATUS_POWER_LIMIT,
 					POWER_LIMIT_EVENT,
#37 lore raw

x86: udelay: Use this_cpu_read to avoid address calculation

In reply to Tejun Heo

The code will use a segment prefix instead of doing the lookup and calculation.

---
 arch/x86/lib/delay.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/lib/delay.c +1 -1
Index: linux-2.6/arch/x86/lib/delay.c
===================================================================
@@ -121,7 +121,7 @@ inline void __const_udelay(unsigned long
 	asm("mull %%edx"
 		:"=d" (xloops), "=&a" (d0)
 		:"1" (xloops), "0"
-		(cpu_data(raw_smp_processor_id()).loops_per_jiffy * (HZ/4)));
+		(this_cpu_read(cpu_info.loops_per_jiffy) * (HZ/4)));
 
 	__delay(++xloops);
 }
#38 lore raw

gameport: use this_cpu_read instead of lookup

In reply to Tejun Heo
---
 drivers/input/gameport/gameport.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/gameport/gameport.c +1 -1
Index: linux-2.6/drivers/input/gameport/gameport.c
===================================================================
@@ -123,7 +123,7 @@ static int gameport_measure_speed(struct
 	}
 
 	gameport_close(gameport);
-	return (cpu_data(raw_smp_processor_id()).loops_per_jiffy *
+	return (this_cpu_read(cpu_info.loops_per_jiffy) *
 		(unsigned long)HZ / (1000 / 50)) / (tx < 1 ? 1 : tx);
 
 #else
#40 lore raw

acpi throttling: Use this_cpu_has and simplify code

In reply to Tejun Heo

With the this_cpu_xx we no longer need to pass an acpi structure to the msr management code. Simplifies code and improves performance.

---
 drivers/acpi/processor_throttling.c |   32 ++++++++++----------------------
 1 file changed, 10 insertions(+), 22 deletions(-)
drivers/acpi/processor_throttling.c +10 -22
Index: linux-2.6/drivers/acpi/processor_throttling.c
===================================================================
@@ -662,20 +662,14 @@ static int acpi_processor_get_throttling
 }
 
 #ifdef CONFIG_X86
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-					u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
-	struct cpuinfo_x86 *c;
 	u64 msr_high, msr_low;
-	unsigned int cpu;
 	u64 msr = 0;
 	int ret = -1;
 
-	cpu = pr->id;
-	c = &cpu_data(cpu);
-
-	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-		!cpu_has(c, X86_FEATURE_ACPI)) {
+	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+		!this_cpu_has(X86_FEATURE_ACPI)) {
 		printk(KERN_ERR PREFIX
 			"HARDWARE addr space,NOT supported yet\n");
 	} else {
@@ -690,18 +684,13 @@ static int acpi_throttling_rdmsr(struct
 	return ret;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
-	struct cpuinfo_x86 *c;
-	unsigned int cpu;
 	int ret = -1;
 	u64 msr;
 
-	cpu = pr->id;
-	c = &cpu_data(cpu);
-
-	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-		!cpu_has(c, X86_FEATURE_ACPI)) {
+	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+		!this_cpu_has(X86_FEATURE_ACPI)) {
 		printk(KERN_ERR PREFIX
 			"HARDWARE addr space,NOT supported yet\n");
 	} else {
@@ -713,15 +702,14 @@ static int acpi_throttling_wrmsr(struct
 	return ret;
 }
 #else
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-				u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
 	printk(KERN_ERR PREFIX
 		"HARDWARE addr space,NOT supported yet\n");
 	return -1;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
 	printk(KERN_ERR PREFIX
 		"HARDWARE addr space,NOT supported yet\n");
@@ -753,7 +741,7 @@ static int acpi_read_throttling_status(s
 		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		ret = acpi_throttling_rdmsr(pr, value);
+		ret = acpi_throttling_rdmsr(value);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
@@ -786,7 +774,7 @@ static int acpi_write_throttling_state(s
 		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		ret = acpi_throttling_wrmsr(pr, value);
+		ret = acpi_throttling_wrmsr(value);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
#45 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Tejun Heo
Quoted 7 lines · Tejun Heo

Are you okay with the patches currently in percpu#for-next? If so, I'll regenerate patches with your acked-by and pop the two previously mentioned commits and proceed with the rest of the series.

Thank you.

Still looking through them (sorry.) I note that we probably do need to get Christoph's followup patches into -tip, so we need to get it all into tip; as such, even if it goes through your tree I'll need to pull it into a tip branch.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#46 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

Hello,

Quoted 10 lines · H. Peter Anvin
Quoted 4 lines · Tejun Heo

Are you okay with the patches currently in percpu#for-next? If so, I'll regenerate patches with your acked-by and pop the two previously mentioned commits and proceed with the rest of the series.

Still looking through them (sorry.) I note that we probably do need to get Christoph's followup patches into -tip, so we need to get it all into tip; as such, even if it goes through your tree I'll need to pull it into a tip branch.

Yeah, no problem. Pekka also wants to pull the essential part into the memory allocator part, so I think it would be best to keep at least the proper percpu part and x86 specific ops in percpu tree tho.

Thanks.

Signature · 1 line
tejun
reviewer Acked-by
#47 lore raw

Re: [cpuops cmpxchg V2 5/5] cpuops: Use cmpxchg for xchg to avoid lock semantics

In reply to Tejun Heo
Quoted 11 lines · Tejun Heo

Hey, again.

Quoted 7 lines · Tejun Heo

I'd prefer percpu things going through percpu tree, if for nothing else for git history's sake, but I don't think it really matters. The series is spread all over the place anyway. As long as each maintainer is properly alerted about the changes, it should be okay. Please let me know whether you agree with the changes currently queued in percpu#for-next. I'll update the tree with your Acked-by's and freeze it.

Quoted 4 lines

Are you okay with the patches currently in percpu#for-next? If so, I'll regenerate patches with your acked-by and pop the two previously mentioned commits and proceed with the rest of the series.

Just finished reviewing the patches in percpu#for-next.

Look good. Let me know when you have a baseline I can pull into a tip branch so we can build the rest of the patches on top.

-hpa

maintainer
#2 lore raw

Re: [cpuops cmpxchg V2 1/5] percpu: Generic this_cpu_cmpxchg() and this_cpu_xchg support

In reply to Christoph Lameter

Hello, Christoph.

Quoted 20 lines · Christoph Lameter

Index: linux-2.6/include/linux/percpu.h
===================================================================

include/linux/percpu.h +4 -4
@@ -242,21 +242,21 @@ extern void __bad_size_call_parameter(vo
 
 #define __pcpu_size_call_return2(stem, pcp, ...)			\
 ({									\
-	typeof(pcp) ret__;						\
+	typeof(pcp) pscr2_ret__;					\
 	__verify_pcpu_ptr(&(pcp));					\
 	switch(sizeof(pcp)) {						\
-	case 1: ret__ = stem##1(pcp, __VA_ARGS__);			\
+	case 1: pscr2_ret__ = stem##1(pcp, __VA_ARGS__);		\
 		break;							\
-	case 2: ret__ = stem##2(pcp, __VA_ARGS__);			\
+	case 2: pscr2_ret__ = stem##2(pcp, __VA_ARGS__);		\
 		break;							\
-	case 4: ret__ = stem##4(pcp, __VA_ARGS__);			\
+	case 4: pscr2_ret__ = stem##4(pcp, __VA_ARGS__);		\

include/linux/percpu.h extern void __bad_size_call_parameter(vo · line 260

Quoted 10 lines
include/linux/percpu.h +2 -2
 		break;							\
-	case 8: ret__ = stem##8(pcp, __VA_ARGS__);			\
+	case 8: pscr2_ret__ = stem##8(pcp, __VA_ARGS__);		\
 		break;							\
 	default:							\
 		__bad_size_call_parameter();break;			\
 	}								\
-	ret__;								\
+	pscr2_ret__;							\
 })

This chunk doesn't belong here. It's the change I've made while applying your earlier patch. Dropping this part.

Relocated xchg and cmpxchg ops so that they're first grouped by preemption safeness and put them after this_cpu_add_return() and friends.

Quoted 5 lines
include/linux/percpu.h +0 -0
  * IRQ safe versions of the per cpu RMW operations. Note that these operations
  * are *not* safe against modification of the same variable from another

* processors (which one gets when using regular atomic operations)
- . They are guaranteed to be atomic vs. local interrupts and
+ * They are guaranteed to be atomic vs. local interrupts and

Noted this in the patch description.

Thanks.

Signature · 1 line
tejun
maintainer
#4 lore raw

Re: [cpuops cmpxchg V2 2/5] x86: this_cpu_cmpxchg and this_cpu_xchg operations

In reply to Christoph Lameter
Quoted 11 lines · Christoph Lameter

Provide support as far as the hardware capabilities of the x86 cpus allow.

Define CONFIG_CMPXCHG_LOCAL in Kconfig.cpu to allow core code to test for fast cpuops implementations.

V1->V2:
- Take out the definition for this_cpu_cmpxchg_8 and move it into a separate patch.

I reorderd ops so that it follow the organization better. I'll soon post the updated patch. Thanks.

Signature · 1 line
tejun
maintainer
#13 lore raw

Re: [cpuops cmpxchg V2 3/5] irq_work: Use per cpu atomics instead of regular atomics

In reply to Christoph Lameter
Quoted 10 lines · Christoph Lameter

The irq work queue is a per cpu object and it is sufficient for synchronization if per cpu atomics are used. Doing so simplifies the code and reduces the overhead of the code.

Before:

[email protected]$ size kernel/irq_work.o
   text	   data	    bss	    dec	    hex	filename
    451	      8	      1	    460	    1cc	kernel/irq_work.o
Quoted 8 lines

After:

[email protected]$ size kernel/irq_work.o 
   text	   data	    bss	    dec	    hex	filename
    438	      8	      1	    447	    1bf	kernel/irq_work.o

Applied 3 and 4 to percpu#for-2.6.38.

Thank you.

Signature · 1 line
tejun
Acked-by
#32 lore raw

Re: x86: Use this_cpu_has for thermal_interrupt

In reply to Christoph Lameter
Quoted 4 lines · Christoph Lameter

It is more effective to use a segment prefix instead of calculating the address of the current cpu area amd then testing flags.

For this and the other x86 patch.

I suppose these two x86 patches and the gameport one would go through the x86 tree, right?

Thank you.

Signature · 1 line
tejun
Acked-by
#41 lore raw

Re: acpi throttling: Use this_cpu_has and simplify code

In reply to Christoph Lameter

(cc'ing ACPI ppl and quoting the whole body)

Quoted 90 lines · Christoph Lameter

With the this_cpu_xx we no longer need to pass an acpi structure to the msr management code. Simplifies code and improves performance.

---
 drivers/acpi/processor_throttling.c |   32 ++++++++++----------------------
 1 file changed, 10 insertions(+), 22 deletions(-)

Index: linux-2.6/drivers/acpi/processor_throttling.c
===================================================================

drivers/acpi/processor_throttling.c +9 -21
@@ -662,20 +662,14 @@ static int acpi_processor_get_throttling
 }
 
 #ifdef CONFIG_X86
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-					u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
-	struct cpuinfo_x86 *c;
 	u64 msr_high, msr_low;
-	unsigned int cpu;
 	u64 msr = 0;
 	int ret = -1;
 
-	cpu = pr->id;
-	c = &cpu_data(cpu);
-
-	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-		!cpu_has(c, X86_FEATURE_ACPI)) {
+	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+		!this_cpu_has(X86_FEATURE_ACPI)) {
 		printk(KERN_ERR PREFIX
 			"HARDWARE addr space,NOT supported yet\n");
 	} else {
@@ -690,18 +684,13 @@ static int acpi_throttling_rdmsr(struct
 	return ret;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
-	struct cpuinfo_x86 *c;
-	unsigned int cpu;
 	int ret = -1;
 	u64 msr;
 
-	cpu = pr->id;
-	c = &cpu_data(cpu);
-
-	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-		!cpu_has(c, X86_FEATURE_ACPI)) {
+	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+		!this_cpu_has(X86_FEATURE_ACPI)) {
 		printk(KERN_ERR PREFIX
 			"HARDWARE addr space,NOT supported yet\n");
 	} else {
@@ -713,15 +702,14 @@ static int acpi_throttling_wrmsr(struct
 	return ret;
 }
 #else
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-				u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
 	printk(KERN_ERR PREFIX
 		"HARDWARE addr space,NOT supported yet\n");
 	return -1;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
 	printk(KERN_ERR PREFIX
 		"HARDWARE addr space,NOT supported yet\n");
@@ -753,7 +741,7 @@ static int acpi_read_throttling_status(s
 		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		ret = acpi_throttling_rdmsr(pr, value);
+		ret = acpi_throttling_rdmsr(value);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",

drivers/acpi/processor_throttling.c static int acpi_write_throttling_state(s · line 780

Quoted 8 lines
drivers/acpi/processor_throttling.c +1 -1
@@ -786,7 +774,7 @@ static int acpi_write_throttling_state(s
 		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		ret = acpi_throttling_wrmsr(pr, value);
+		ret = acpi_throttling_wrmsr(value);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",

It's bothersome that these methods don't have any indication that they're bound to local CPU when they can't be called with @pr for another CPU as MSRs can only be accessed from local CPU.

In the longer run, it would be nice if there's an indication that this is only for the local CPU and maybe a WARN_ON_ONCE(). Maybe dropping @pr and using this_cpu_*() is better for performance too?

Anyways, the above doesn't make the situation any worse, so...

I think this one too fits the x86 tree better.

Thanks.

Signature · 1 line
tejun
#33 lore raw

Re: x86: Use this_cpu_has for thermal_interrupt

In reply to Tejun Heo
Quoted 4 lines · Tejun Heo
Quoted 3 lines · Christoph Lameter

It is more effective to use a segment prefix instead of calculating the address of the current cpu area amd then testing flags.

Quoted 9 lines
Quoted 1 line

For this and the other x86 patch.

I suppose these two x86 patches and the gameport one would go through the x86 tree, right?

Yes, as long as I can get a stable base to pull into -tip.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.
#42 lore raw

Re: acpi throttling: Use this_cpu_has and simplify code

In reply to Tejun Heo
Quoted 97 lines · Tejun Heo

(cc'ing ACPI ppl and quoting the whole body)

Quoted 94 lines · Christoph Lameter

With the this_cpu_xx we no longer need to pass an acpi structure to the msr management code. Simplifies code and improves performance.

---
 drivers/acpi/processor_throttling.c |   32 ++++++++++----------------------
 1 file changed, 10 insertions(+), 22 deletions(-)

Index: linux-2.6/drivers/acpi/processor_throttling.c
===================================================================

drivers/acpi/processor_throttling.c +10 -22
@@ -662,20 +662,14 @@ static int acpi_processor_get_throttling
 }
 
 #ifdef CONFIG_X86
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-					u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
-	struct cpuinfo_x86 *c;
 	u64 msr_high, msr_low;
-	unsigned int cpu;
 	u64 msr = 0;
 	int ret = -1;
 
-	cpu = pr->id;
-	c = &cpu_data(cpu);
-
-	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-		!cpu_has(c, X86_FEATURE_ACPI)) {
+	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+		!this_cpu_has(X86_FEATURE_ACPI)) {
 		printk(KERN_ERR PREFIX
 			"HARDWARE addr space,NOT supported yet\n");
 	} else {
@@ -690,18 +684,13 @@ static int acpi_throttling_rdmsr(struct
 	return ret;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
-	struct cpuinfo_x86 *c;
-	unsigned int cpu;
 	int ret = -1;
 	u64 msr;
 
-	cpu = pr->id;
-	c = &cpu_data(cpu);
-
-	if ((c->x86_vendor != X86_VENDOR_INTEL) ||
-		!cpu_has(c, X86_FEATURE_ACPI)) {
+	if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+		!this_cpu_has(X86_FEATURE_ACPI)) {
 		printk(KERN_ERR PREFIX
 			"HARDWARE addr space,NOT supported yet\n");
 	} else {
@@ -713,15 +702,14 @@ static int acpi_throttling_wrmsr(struct
 	return ret;
 }
 #else
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
-				u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
 {
 	printk(KERN_ERR PREFIX
 		"HARDWARE addr space,NOT supported yet\n");
 	return -1;
 }
 
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
 {
 	printk(KERN_ERR PREFIX
 		"HARDWARE addr space,NOT supported yet\n");
@@ -753,7 +741,7 @@ static int acpi_read_throttling_status(s
 		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		ret = acpi_throttling_rdmsr(pr, value);
+		ret = acpi_throttling_rdmsr(value);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
@@ -786,7 +774,7 @@ static int acpi_write_throttling_state(s
 		ret = 0;
 		break;
 	case ACPI_ADR_SPACE_FIXED_HARDWARE:
-		ret = acpi_throttling_wrmsr(pr, value);
+		ret = acpi_throttling_wrmsr(value);
Quoted 8 lines

drivers/acpi/processor_throttling.c static int acpi_read_throttling_status(s · line 747

Quoted 4 lines
drivers/acpi/processor_throttling.c +0 -0
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown addr space %d\n",

It's bothersome that these methods don't have any indication that they're bound to local CPU when they can't be called with @pr for another CPU as MSRs can only be accessed from local CPU.

The above function may be called under the scenario with irq disabled. In such case if the corresponding MRS is accessed by using remote method, it will complain the oops. Maybe it will be safer to firstly switch to the local CPU and then read/write the MRS register related with the throttling.

Quoted 4 lines

In the longer run, it would be nice if there's an indication that this is only for the local CPU and maybe a WARN_ON_ONCE(). Maybe dropping @pr and using this_cpu_*() is better for performance too?

It is also ok to me that drops the pr input argument of acpi_throttling_rdmsr/wrmsr as it is already switched to the local cpu.

Quoted 9 lines

Anyways, the above doesn't make the situation any worse, so...

I think this one too fits the x86 tree better.

Thanks.

reviewer
#44 lore raw

Re: acpi throttling: Use this_cpu_has and simplify code

In reply to Christoph Lameter

This patch is a valid cleanup, and I've applied it to the acpi-test tree.

The routines named *rdmsr() and *wrmsr() run on the local CPU by definition. I think that after this change to get rid of pr*, that is even more clear.

The part about checking that you are on the right processor should really be done in the caller. Yakui should send a patch for the driver to check for successful return from set_cpus_allowed_ptr() before invoking this code.

Quoted 3 lines

With the this_cpu_xx we no longer need to pass an acpi structure to the msr management code. Simplifies code and improves performance.

Simplifies, yes.
Performance -- not the focus here.
If you are running routines to throttle the clock frequency, then you have already decided that performance isn't your top priority:-)

thanks,
Len Brown, Intel Open Source Technology Center

Quoted 5 lines
---
 drivers/acpi/processor_throttling.c |   32 ++++++++++----------------------
 1 file changed, 10 insertions(+), 22 deletions(-)
#43 lore raw

Re: acpi throttling: Use this_cpu_has and simplify code

In reply to Tejun Heo
Quoted 3 lines · Tejun Heo

It's bothersome that these methods don't have any indication that they're bound to local CPU when they can't be called with @pr for another CPU as MSRs can only be accessed from local CPU.

Right.

Quoted 3 lines

In the longer run, it would be nice if there's an indication that this is only for the local CPU and maybe a WARN_ON_ONCE(). Maybe dropping @pr and using this_cpu_*() is better for performance too?

That is precisely the difficulty with many other functions that take pointers to cpu_info. If we can establish that they are called *only* with pointers to the current cpu then we can improve the function by dropping the parameter and using this_cpu ops to access the cpu_info fields.

Using this_cpu ops instead of access to a field of a struct pointed to by an array avoids an addition of pointers and replacest with a operation that essentially takes a global address with a segment prefix. It reduces register pressure and avoids the additions of pointers but it will encode the address in the instruction.

#34 lore raw

Re: x86: Use this_cpu_has for thermal_interrupt

In reply to H. Peter Anvin
Quoted 9 lines · H. Peter Anvin
Quoted 8 lines · Tejun Heo
Quoted 4 lines · Christoph Lameter

It is more effective to use a segment prefix instead of calculating the address of the current cpu area amd then testing flags.

For this and the other x86 patch.

Quoted 7 lines
Quoted 5 lines

I suppose these two x86 patches and the gameport one would go through the x86 tree, right?

Yes, as long as I can get a stable base to pull into -tip.

I suppose I should take the two x86 and the gameport patches here into percpu tree with your ACKs too. Would that be okay with you?

Thanks.

Signature · 1 line
tejun
reviewer Acked-by
#35 lore raw

Re: x86: Use this_cpu_has for thermal_interrupt

Quoted 12 lines · Tejun Heo
Quoted 11 lines · H. Peter Anvin
Quoted 10 lines · Tejun Heo
Quoted 4 lines · Christoph Lameter

It is more effective to use a segment prefix instead of calculating the address of the current cpu area amd then testing flags.

For this and the other x86 patch.

Quoted 9 lines
Quoted 5 lines
Quoted 3 lines

I suppose these two x86 patches and the gameport one would go through the x86 tree, right?

Yes, as long as I can get a stable base to pull into -tip.

I suppose I should take the two x86 and the gameport patches here into percpu tree with your ACKs too. Would that be okay with you?

Yes, please.

-hpa

Signature · 2 lines
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.