xref: /linux/lib/percpu_test.c (revision 09c434b8)
1*09c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2623fd807SGreg Thelen #include <linux/module.h>
3623fd807SGreg Thelen 
4623fd807SGreg Thelen /* validate @native and @pcp counter values match @expected */
5623fd807SGreg Thelen #define CHECK(native, pcp, expected)                                    \
6623fd807SGreg Thelen 	do {                                                            \
7623fd807SGreg Thelen 		WARN((native) != (expected),                            \
8623fd807SGreg Thelen 		     "raw %ld (0x%lx) != expected %lld (0x%llx)",	\
9623fd807SGreg Thelen 		     (native), (native),				\
10623fd807SGreg Thelen 		     (long long)(expected), (long long)(expected));	\
11623fd807SGreg Thelen 		WARN(__this_cpu_read(pcp) != (expected),                \
12623fd807SGreg Thelen 		     "pcp %ld (0x%lx) != expected %lld (0x%llx)",	\
13623fd807SGreg Thelen 		     __this_cpu_read(pcp), __this_cpu_read(pcp),	\
14623fd807SGreg Thelen 		     (long long)(expected), (long long)(expected));	\
15623fd807SGreg Thelen 	} while (0)
16623fd807SGreg Thelen 
17623fd807SGreg Thelen static DEFINE_PER_CPU(long, long_counter);
18623fd807SGreg Thelen static DEFINE_PER_CPU(unsigned long, ulong_counter);
19623fd807SGreg Thelen 
percpu_test_init(void)20623fd807SGreg Thelen static int __init percpu_test_init(void)
21623fd807SGreg Thelen {
22623fd807SGreg Thelen 	/*
23623fd807SGreg Thelen 	 * volatile prevents compiler from optimizing it uses, otherwise the
24623fd807SGreg Thelen 	 * +ul_one/-ul_one below would replace with inc/dec instructions.
25623fd807SGreg Thelen 	 */
26623fd807SGreg Thelen 	volatile unsigned int ui_one = 1;
27623fd807SGreg Thelen 	long l = 0;
28623fd807SGreg Thelen 	unsigned long ul = 0;
29623fd807SGreg Thelen 
30623fd807SGreg Thelen 	pr_info("percpu test start\n");
31623fd807SGreg Thelen 
32623fd807SGreg Thelen 	preempt_disable();
33623fd807SGreg Thelen 
34623fd807SGreg Thelen 	l += -1;
35623fd807SGreg Thelen 	__this_cpu_add(long_counter, -1);
36623fd807SGreg Thelen 	CHECK(l, long_counter, -1);
37623fd807SGreg Thelen 
38623fd807SGreg Thelen 	l += 1;
39623fd807SGreg Thelen 	__this_cpu_add(long_counter, 1);
40623fd807SGreg Thelen 	CHECK(l, long_counter, 0);
41623fd807SGreg Thelen 
42623fd807SGreg Thelen 	ul = 0;
43623fd807SGreg Thelen 	__this_cpu_write(ulong_counter, 0);
44623fd807SGreg Thelen 
45623fd807SGreg Thelen 	ul += 1UL;
46623fd807SGreg Thelen 	__this_cpu_add(ulong_counter, 1UL);
47623fd807SGreg Thelen 	CHECK(ul, ulong_counter, 1);
48623fd807SGreg Thelen 
49623fd807SGreg Thelen 	ul += -1UL;
50623fd807SGreg Thelen 	__this_cpu_add(ulong_counter, -1UL);
51623fd807SGreg Thelen 	CHECK(ul, ulong_counter, 0);
52623fd807SGreg Thelen 
53623fd807SGreg Thelen 	ul += -(unsigned long)1;
54623fd807SGreg Thelen 	__this_cpu_add(ulong_counter, -(unsigned long)1);
55623fd807SGreg Thelen 	CHECK(ul, ulong_counter, -1);
56623fd807SGreg Thelen 
57623fd807SGreg Thelen 	ul = 0;
58623fd807SGreg Thelen 	__this_cpu_write(ulong_counter, 0);
59623fd807SGreg Thelen 
60623fd807SGreg Thelen 	ul -= 1;
61623fd807SGreg Thelen 	__this_cpu_dec(ulong_counter);
62623fd807SGreg Thelen 	CHECK(ul, ulong_counter, -1);
63623fd807SGreg Thelen 	CHECK(ul, ulong_counter, ULONG_MAX);
64623fd807SGreg Thelen 
65623fd807SGreg Thelen 	l += -ui_one;
66623fd807SGreg Thelen 	__this_cpu_add(long_counter, -ui_one);
67623fd807SGreg Thelen 	CHECK(l, long_counter, 0xffffffff);
68623fd807SGreg Thelen 
69623fd807SGreg Thelen 	l += ui_one;
70623fd807SGreg Thelen 	__this_cpu_add(long_counter, ui_one);
71623fd807SGreg Thelen 	CHECK(l, long_counter, (long)0x100000000LL);
72623fd807SGreg Thelen 
73623fd807SGreg Thelen 
74623fd807SGreg Thelen 	l = 0;
75623fd807SGreg Thelen 	__this_cpu_write(long_counter, 0);
76623fd807SGreg Thelen 
77623fd807SGreg Thelen 	l -= ui_one;
78623fd807SGreg Thelen 	__this_cpu_sub(long_counter, ui_one);
79623fd807SGreg Thelen 	CHECK(l, long_counter, -1);
80623fd807SGreg Thelen 
81623fd807SGreg Thelen 	l = 0;
82623fd807SGreg Thelen 	__this_cpu_write(long_counter, 0);
83623fd807SGreg Thelen 
84623fd807SGreg Thelen 	l += ui_one;
85623fd807SGreg Thelen 	__this_cpu_add(long_counter, ui_one);
86623fd807SGreg Thelen 	CHECK(l, long_counter, 1);
87623fd807SGreg Thelen 
88623fd807SGreg Thelen 	l += -ui_one;
89623fd807SGreg Thelen 	__this_cpu_add(long_counter, -ui_one);
90623fd807SGreg Thelen 	CHECK(l, long_counter, (long)0x100000000LL);
91623fd807SGreg Thelen 
92623fd807SGreg Thelen 	l = 0;
93623fd807SGreg Thelen 	__this_cpu_write(long_counter, 0);
94623fd807SGreg Thelen 
95623fd807SGreg Thelen 	l -= ui_one;
96623fd807SGreg Thelen 	this_cpu_sub(long_counter, ui_one);
97623fd807SGreg Thelen 	CHECK(l, long_counter, -1);
98623fd807SGreg Thelen 	CHECK(l, long_counter, ULONG_MAX);
99623fd807SGreg Thelen 
100623fd807SGreg Thelen 	ul = 0;
101623fd807SGreg Thelen 	__this_cpu_write(ulong_counter, 0);
102623fd807SGreg Thelen 
103623fd807SGreg Thelen 	ul += ui_one;
104623fd807SGreg Thelen 	__this_cpu_add(ulong_counter, ui_one);
105623fd807SGreg Thelen 	CHECK(ul, ulong_counter, 1);
106623fd807SGreg Thelen 
107623fd807SGreg Thelen 	ul = 0;
108623fd807SGreg Thelen 	__this_cpu_write(ulong_counter, 0);
109623fd807SGreg Thelen 
110623fd807SGreg Thelen 	ul -= ui_one;
111623fd807SGreg Thelen 	__this_cpu_sub(ulong_counter, ui_one);
112623fd807SGreg Thelen 	CHECK(ul, ulong_counter, -1);
113623fd807SGreg Thelen 	CHECK(ul, ulong_counter, ULONG_MAX);
114623fd807SGreg Thelen 
115623fd807SGreg Thelen 	ul = 3;
116623fd807SGreg Thelen 	__this_cpu_write(ulong_counter, 3);
117623fd807SGreg Thelen 
118623fd807SGreg Thelen 	ul = this_cpu_sub_return(ulong_counter, ui_one);
119623fd807SGreg Thelen 	CHECK(ul, ulong_counter, 2);
120623fd807SGreg Thelen 
121623fd807SGreg Thelen 	ul = __this_cpu_sub_return(ulong_counter, ui_one);
122623fd807SGreg Thelen 	CHECK(ul, ulong_counter, 1);
123623fd807SGreg Thelen 
124623fd807SGreg Thelen 	preempt_enable();
125623fd807SGreg Thelen 
126623fd807SGreg Thelen 	pr_info("percpu test done\n");
127623fd807SGreg Thelen 	return -EAGAIN;  /* Fail will directly unload the module */
128623fd807SGreg Thelen }
129623fd807SGreg Thelen 
percpu_test_exit(void)130623fd807SGreg Thelen static void __exit percpu_test_exit(void)
131623fd807SGreg Thelen {
132623fd807SGreg Thelen }
133623fd807SGreg Thelen 
134623fd807SGreg Thelen module_init(percpu_test_init)
135623fd807SGreg Thelen module_exit(percpu_test_exit)
136623fd807SGreg Thelen 
137623fd807SGreg Thelen MODULE_LICENSE("GPL");
138623fd807SGreg Thelen MODULE_AUTHOR("Greg Thelen");
139623fd807SGreg Thelen MODULE_DESCRIPTION("percpu operations test");
140