diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2007-11-21 09:02:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:54:39 -0500 |
commit | de4d1db369785c29d68915edfee0cb70e8199f4c (patch) | |
tree | 78979fc131145d4b2df3cd4721a811784126f05c | |
parent | 0c884439dbd7c895cce61c4974c8868b0f6cd4a1 (diff) |
[LIB]: Introduce struct pcounter
This just generalises what was introduced by Eric Dumazet for the struct proto
inuse field in 286ab3d46058840d68e5d7d52e316c1f7e98c59f:
[NET]: Define infrastructure to keep 'inuse' changes in an efficent SMP/NUMA way.
Please look at the comment in there to see the rationale.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/pcounter.h | 102 | ||||
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/pcounter.c | 26 |
3 files changed, 129 insertions, 0 deletions
diff --git a/include/linux/pcounter.h b/include/linux/pcounter.h new file mode 100644 index 000000000000..620aaded4e94 --- /dev/null +++ b/include/linux/pcounter.h | |||
@@ -0,0 +1,102 @@ | |||
1 | #ifndef __LINUX_PCOUNTER_H | ||
2 | #define __LINUX_PCOUNTER_H | ||
3 | |||
4 | struct pcounter { | ||
5 | #ifdef CONFIG_SMP | ||
6 | void (*add)(struct pcounter *self, int inc); | ||
7 | int (*getval)(const struct pcounter *self); | ||
8 | int *per_cpu_values; | ||
9 | #else | ||
10 | int val; | ||
11 | #endif | ||
12 | }; | ||
13 | |||
14 | /* | ||
15 | * Special macros to let pcounters use a fast version of {getvalue|add} | ||
16 | * using a static percpu variable per pcounter instead of an allocated one, | ||
17 | * saving one dereference. | ||
18 | * This might be changed if/when dynamic percpu vars become fast. | ||
19 | */ | ||
20 | #ifdef CONFIG_SMP | ||
21 | #include <linux/cpumask.h> | ||
22 | #include <linux/percpu.h> | ||
23 | |||
24 | #define DEFINE_PCOUNTER(NAME) \ | ||
25 | static DEFINE_PER_CPU(int, NAME##_pcounter_values); \ | ||
26 | static void NAME##_pcounter_add(struct pcounter *self, int inc) \ | ||
27 | { \ | ||
28 | __get_cpu_var(NAME##_pcounter_values) += inc; \ | ||
29 | } \ | ||
30 | \ | ||
31 | static int NAME##_pcounter_getval(const struct pcounter *self) \ | ||
32 | { \ | ||
33 | int res = 0, cpu; \ | ||
34 | \ | ||
35 | for_each_possible_cpu(cpu) \ | ||
36 | res += per_cpu(NAME##_pcounter_values, cpu); \ | ||
37 | return res; \ | ||
38 | } | ||
39 | |||
40 | #define PCOUNTER_MEMBER_INITIALIZER(NAME, MEMBER) \ | ||
41 | MEMBER = { \ | ||
42 | .add = NAME##_pcounter_add, \ | ||
43 | .getval = NAME##_pcounter_getval, \ | ||
44 | } | ||
45 | |||
46 | extern void pcounter_def_add(struct pcounter *self, int inc); | ||
47 | extern int pcounter_def_getval(const struct pcounter *self); | ||
48 | |||
49 | static inline int pcounter_alloc(struct pcounter *self) | ||
50 | { | ||
51 | int rc = 0; | ||
52 | if (self->add == NULL) { | ||
53 | self->per_cpu_values = alloc_percpu(int); | ||
54 | if (self->per_cpu_values != NULL) { | ||
55 | self->add = pcounter_def_add; | ||
56 | self->getval = pcounter_def_getval; | ||
57 | } else | ||
58 | rc = 1; | ||
59 | } | ||
60 | return rc; | ||
61 | } | ||
62 | |||
63 | static inline void pcounter_free(struct pcounter *self) | ||
64 | { | ||
65 | if (self->per_cpu_values != NULL) { | ||
66 | free_percpu(self->per_cpu_values); | ||
67 | self->per_cpu_values = NULL; | ||
68 | self->getval = NULL; | ||
69 | self->add = NULL; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static inline void pcounter_add(struct pcounter *self, int inc) | ||
74 | { | ||
75 | self->add(self, inc); | ||
76 | } | ||
77 | |||
78 | static inline int pcounter_getval(const struct pcounter *self) | ||
79 | { | ||
80 | return self->getval(self); | ||
81 | } | ||
82 | |||
83 | #else /* CONFIG_SMP */ | ||
84 | |||
85 | static inline void pcounter_add(struct pcounter *self, int inc) | ||
86 | { | ||
87 | self->value += inc; | ||
88 | } | ||
89 | |||
90 | static inline int pcounter_getval(const struct pcounter *self) | ||
91 | { | ||
92 | return self->val; | ||
93 | } | ||
94 | |||
95 | #define DEFINE_PCOUNTER(NAME) | ||
96 | #define PCOUNTER_MEMBER_INITIALIZER(NAME, MEMBER) | ||
97 | #define pcounter_alloc(self) 0 | ||
98 | #define pcounter_free(self) | ||
99 | |||
100 | #endif /* CONFIG_SMP */ | ||
101 | |||
102 | #endif /* __LINUX_PCOUNTER_H */ | ||
diff --git a/lib/Makefile b/lib/Makefile index 89841dc9d91c..543f2502b60a 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -61,6 +61,7 @@ obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o | |||
61 | obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o | 61 | obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o |
62 | obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o | 62 | obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o |
63 | obj-$(CONFIG_SMP) += percpu_counter.o | 63 | obj-$(CONFIG_SMP) += percpu_counter.o |
64 | obj-$(CONFIG_SMP) += pcounter.o | ||
64 | obj-$(CONFIG_AUDIT_GENERIC) += audit.o | 65 | obj-$(CONFIG_AUDIT_GENERIC) += audit.o |
65 | 66 | ||
66 | obj-$(CONFIG_SWIOTLB) += swiotlb.o | 67 | obj-$(CONFIG_SWIOTLB) += swiotlb.o |
diff --git a/lib/pcounter.c b/lib/pcounter.c new file mode 100644 index 000000000000..93feea598251 --- /dev/null +++ b/lib/pcounter.c | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * Define default pcounter functions | ||
3 | * Note that often used pcounters use dedicated functions to get a speed increase. | ||
4 | * (see DEFINE_PCOUNTER/REF_PCOUNTER_MEMBER) | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/pcounter.h> | ||
9 | #include <linux/smp.h> | ||
10 | |||
11 | void pcounter_def_add(struct pcounter *self, int inc) | ||
12 | { | ||
13 | per_cpu_ptr(self->per_cpu_values, smp_processor_id())[0] += inc; | ||
14 | } | ||
15 | |||
16 | EXPORT_SYMBOL_GPL(pcounter_def_add); | ||
17 | |||
18 | int pcounter_def_getval(const struct pcounter *self) | ||
19 | { | ||
20 | int res = 0, cpu; | ||
21 | for_each_possible_cpu(cpu) | ||
22 | res += per_cpu_ptr(self->per_cpu_values, cpu)[0]; | ||
23 | return res; | ||
24 | } | ||
25 | |||
26 | EXPORT_SYMBOL_GPL(pcounter_def_getval); | ||