diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-01-15 08:15:53 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-16 08:20:31 -0500 |
commit | 6dbde3530850d4d8bfc1b6bd4006d92786a2787f (patch) | |
tree | 08c6dd55e860827311b889e2ecfe3de9f51421a0 /include | |
parent | 004aa322f855a765741d9437a98dd8fe2e4f32a6 (diff) |
percpu: add optimized generic percpu accessors
It is an optimization and a cleanup, and adds the following new
generic percpu methods:
percpu_read()
percpu_write()
percpu_add()
percpu_sub()
percpu_and()
percpu_or()
percpu_xor()
and implements support for them on x86. (other architectures will fall
back to a default implementation)
The advantage is that for example to read a local percpu variable,
instead of this sequence:
return __get_cpu_var(var);
ffffffff8102ca2b: 48 8b 14 fd 80 09 74 mov -0x7e8bf680(,%rdi,8),%rdx
ffffffff8102ca32: 81
ffffffff8102ca33: 48 c7 c0 d8 59 00 00 mov $0x59d8,%rax
ffffffff8102ca3a: 48 8b 04 10 mov (%rax,%rdx,1),%rax
We can get a single instruction by using the optimized variants:
return percpu_read(var);
ffffffff8102ca3f: 65 48 8b 05 91 8f fd mov %gs:0x7efd8f91(%rip),%rax
I also cleaned up the x86-specific APIs and made the x86 code use
these new generic percpu primitives.
tj: * fixed generic percpu_sub() definition as Roel Kluin pointed out
* added percpu_and() for completeness's sake
* made generic percpu ops atomic against preemption
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/asm-generic/percpu.h | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h index b0e63c672ebd..00f45ff081a6 100644 --- a/include/asm-generic/percpu.h +++ b/include/asm-generic/percpu.h | |||
@@ -80,4 +80,56 @@ extern void setup_per_cpu_areas(void); | |||
80 | #define DECLARE_PER_CPU(type, name) extern PER_CPU_ATTRIBUTES \ | 80 | #define DECLARE_PER_CPU(type, name) extern PER_CPU_ATTRIBUTES \ |
81 | __typeof__(type) per_cpu_var(name) | 81 | __typeof__(type) per_cpu_var(name) |
82 | 82 | ||
83 | /* | ||
84 | * Optional methods for optimized non-lvalue per-cpu variable access. | ||
85 | * | ||
86 | * @var can be a percpu variable or a field of it and its size should | ||
87 | * equal char, int or long. percpu_read() evaluates to a lvalue and | ||
88 | * all others to void. | ||
89 | * | ||
90 | * These operations are guaranteed to be atomic w.r.t. preemption. | ||
91 | * The generic versions use plain get/put_cpu_var(). Archs are | ||
92 | * encouraged to implement single-instruction alternatives which don't | ||
93 | * require preemption protection. | ||
94 | */ | ||
95 | #ifndef percpu_read | ||
96 | # define percpu_read(var) \ | ||
97 | ({ \ | ||
98 | typeof(per_cpu_var(var)) __tmp_var__; \ | ||
99 | __tmp_var__ = get_cpu_var(var); \ | ||
100 | put_cpu_var(var); \ | ||
101 | __tmp_var__; \ | ||
102 | }) | ||
103 | #endif | ||
104 | |||
105 | #define __percpu_generic_to_op(var, val, op) \ | ||
106 | do { \ | ||
107 | get_cpu_var(var) op val; \ | ||
108 | put_cpu_var(var); \ | ||
109 | } while (0) | ||
110 | |||
111 | #ifndef percpu_write | ||
112 | # define percpu_write(var, val) __percpu_generic_to_op(var, (val), =) | ||
113 | #endif | ||
114 | |||
115 | #ifndef percpu_add | ||
116 | # define percpu_add(var, val) __percpu_generic_to_op(var, (val), +=) | ||
117 | #endif | ||
118 | |||
119 | #ifndef percpu_sub | ||
120 | # define percpu_sub(var, val) __percpu_generic_to_op(var, (val), -=) | ||
121 | #endif | ||
122 | |||
123 | #ifndef percpu_and | ||
124 | # define percpu_and(var, val) __percpu_generic_to_op(var, (val), &=) | ||
125 | #endif | ||
126 | |||
127 | #ifndef percpu_or | ||
128 | # define percpu_or(var, val) __percpu_generic_to_op(var, (val), |=) | ||
129 | #endif | ||
130 | |||
131 | #ifndef percpu_xor | ||
132 | # define percpu_xor(var, val) __percpu_generic_to_op(var, (val), ^=) | ||
133 | #endif | ||
134 | |||
83 | #endif /* _ASM_GENERIC_PERCPU_H_ */ | 135 | #endif /* _ASM_GENERIC_PERCPU_H_ */ |