1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun * Test module for stress and analyze performance of vmalloc allocator.
5*4882a593Smuzhiyun * (C) 2018 Uladzislau Rezki (Sony) <urezki@gmail.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <linux/init.h>
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/vmalloc.h>
11*4882a593Smuzhiyun #include <linux/random.h>
12*4882a593Smuzhiyun #include <linux/kthread.h>
13*4882a593Smuzhiyun #include <linux/moduleparam.h>
14*4882a593Smuzhiyun #include <linux/completion.h>
15*4882a593Smuzhiyun #include <linux/delay.h>
16*4882a593Smuzhiyun #include <linux/rwsem.h>
17*4882a593Smuzhiyun #include <linux/mm.h>
18*4882a593Smuzhiyun #include <linux/rcupdate.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define __param(type, name, init, msg) \
22*4882a593Smuzhiyun static type name = init; \
23*4882a593Smuzhiyun module_param(name, type, 0444); \
24*4882a593Smuzhiyun MODULE_PARM_DESC(name, msg) \
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun __param(bool, single_cpu_test, false,
27*4882a593Smuzhiyun "Use single first online CPU to run tests");
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun __param(bool, sequential_test_order, false,
30*4882a593Smuzhiyun "Use sequential stress tests order");
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun __param(int, test_repeat_count, 1,
33*4882a593Smuzhiyun "Set test repeat counter");
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun __param(int, test_loop_count, 1000000,
36*4882a593Smuzhiyun "Set test loop counter");
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun __param(int, run_test_mask, INT_MAX,
39*4882a593Smuzhiyun "Set tests specified in the mask.\n\n"
40*4882a593Smuzhiyun "\t\tid: 1, name: fix_size_alloc_test\n"
41*4882a593Smuzhiyun "\t\tid: 2, name: full_fit_alloc_test\n"
42*4882a593Smuzhiyun "\t\tid: 4, name: long_busy_list_alloc_test\n"
43*4882a593Smuzhiyun "\t\tid: 8, name: random_size_alloc_test\n"
44*4882a593Smuzhiyun "\t\tid: 16, name: fix_align_alloc_test\n"
45*4882a593Smuzhiyun "\t\tid: 32, name: random_size_align_alloc_test\n"
46*4882a593Smuzhiyun "\t\tid: 64, name: align_shift_alloc_test\n"
47*4882a593Smuzhiyun "\t\tid: 128, name: pcpu_alloc_test\n"
48*4882a593Smuzhiyun "\t\tid: 256, name: kvfree_rcu_1_arg_vmalloc_test\n"
49*4882a593Smuzhiyun "\t\tid: 512, name: kvfree_rcu_2_arg_vmalloc_test\n"
50*4882a593Smuzhiyun "\t\tid: 1024, name: kvfree_rcu_1_arg_slab_test\n"
51*4882a593Smuzhiyun "\t\tid: 2048, name: kvfree_rcu_2_arg_slab_test\n"
52*4882a593Smuzhiyun /* Add a new test case description here. */
53*4882a593Smuzhiyun );
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /*
56*4882a593Smuzhiyun * Depends on single_cpu_test parameter. If it is true, then
57*4882a593Smuzhiyun * use first online CPU to trigger a test on, otherwise go with
58*4882a593Smuzhiyun * all online CPUs.
59*4882a593Smuzhiyun */
60*4882a593Smuzhiyun static cpumask_t cpus_run_test_mask = CPU_MASK_NONE;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun * Read write semaphore for synchronization of setup
64*4882a593Smuzhiyun * phase that is done in main thread and workers.
65*4882a593Smuzhiyun */
66*4882a593Smuzhiyun static DECLARE_RWSEM(prepare_for_test_rwsem);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun /*
69*4882a593Smuzhiyun * Completion tracking for worker threads.
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun static DECLARE_COMPLETION(test_all_done_comp);
72*4882a593Smuzhiyun static atomic_t test_n_undone = ATOMIC_INIT(0);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun static inline void
test_report_one_done(void)75*4882a593Smuzhiyun test_report_one_done(void)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun if (atomic_dec_and_test(&test_n_undone))
78*4882a593Smuzhiyun complete(&test_all_done_comp);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
random_size_align_alloc_test(void)81*4882a593Smuzhiyun static int random_size_align_alloc_test(void)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun unsigned long size, align, rnd;
84*4882a593Smuzhiyun void *ptr;
85*4882a593Smuzhiyun int i;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
88*4882a593Smuzhiyun get_random_bytes(&rnd, sizeof(rnd));
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /*
91*4882a593Smuzhiyun * Maximum 1024 pages, if PAGE_SIZE is 4096.
92*4882a593Smuzhiyun */
93*4882a593Smuzhiyun align = 1 << (rnd % 23);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /*
96*4882a593Smuzhiyun * Maximum 10 pages.
97*4882a593Smuzhiyun */
98*4882a593Smuzhiyun size = ((rnd % 10) + 1) * PAGE_SIZE;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun ptr = __vmalloc_node(size, align, GFP_KERNEL | __GFP_ZERO, 0,
101*4882a593Smuzhiyun __builtin_return_address(0));
102*4882a593Smuzhiyun if (!ptr)
103*4882a593Smuzhiyun return -1;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun vfree(ptr);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun /*
112*4882a593Smuzhiyun * This test case is supposed to be failed.
113*4882a593Smuzhiyun */
align_shift_alloc_test(void)114*4882a593Smuzhiyun static int align_shift_alloc_test(void)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun unsigned long align;
117*4882a593Smuzhiyun void *ptr;
118*4882a593Smuzhiyun int i;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun for (i = 0; i < BITS_PER_LONG; i++) {
121*4882a593Smuzhiyun align = ((unsigned long) 1) << i;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun ptr = __vmalloc_node(PAGE_SIZE, align, GFP_KERNEL|__GFP_ZERO, 0,
124*4882a593Smuzhiyun __builtin_return_address(0));
125*4882a593Smuzhiyun if (!ptr)
126*4882a593Smuzhiyun return -1;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun vfree(ptr);
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun return 0;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
fix_align_alloc_test(void)134*4882a593Smuzhiyun static int fix_align_alloc_test(void)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun void *ptr;
137*4882a593Smuzhiyun int i;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
140*4882a593Smuzhiyun ptr = __vmalloc_node(5 * PAGE_SIZE, THREAD_ALIGN << 1,
141*4882a593Smuzhiyun GFP_KERNEL | __GFP_ZERO, 0,
142*4882a593Smuzhiyun __builtin_return_address(0));
143*4882a593Smuzhiyun if (!ptr)
144*4882a593Smuzhiyun return -1;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun vfree(ptr);
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
random_size_alloc_test(void)152*4882a593Smuzhiyun static int random_size_alloc_test(void)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun unsigned int n;
155*4882a593Smuzhiyun void *p;
156*4882a593Smuzhiyun int i;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
159*4882a593Smuzhiyun get_random_bytes(&n, sizeof(i));
160*4882a593Smuzhiyun n = (n % 100) + 1;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun p = vmalloc(n * PAGE_SIZE);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (!p)
165*4882a593Smuzhiyun return -1;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun *((__u8 *)p) = 1;
168*4882a593Smuzhiyun vfree(p);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
long_busy_list_alloc_test(void)174*4882a593Smuzhiyun static int long_busy_list_alloc_test(void)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun void *ptr_1, *ptr_2;
177*4882a593Smuzhiyun void **ptr;
178*4882a593Smuzhiyun int rv = -1;
179*4882a593Smuzhiyun int i;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun ptr = vmalloc(sizeof(void *) * 15000);
182*4882a593Smuzhiyun if (!ptr)
183*4882a593Smuzhiyun return rv;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun for (i = 0; i < 15000; i++)
186*4882a593Smuzhiyun ptr[i] = vmalloc(1 * PAGE_SIZE);
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
189*4882a593Smuzhiyun ptr_1 = vmalloc(100 * PAGE_SIZE);
190*4882a593Smuzhiyun if (!ptr_1)
191*4882a593Smuzhiyun goto leave;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun ptr_2 = vmalloc(1 * PAGE_SIZE);
194*4882a593Smuzhiyun if (!ptr_2) {
195*4882a593Smuzhiyun vfree(ptr_1);
196*4882a593Smuzhiyun goto leave;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun *((__u8 *)ptr_1) = 0;
200*4882a593Smuzhiyun *((__u8 *)ptr_2) = 1;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun vfree(ptr_1);
203*4882a593Smuzhiyun vfree(ptr_2);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /* Success */
207*4882a593Smuzhiyun rv = 0;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun leave:
210*4882a593Smuzhiyun for (i = 0; i < 15000; i++)
211*4882a593Smuzhiyun vfree(ptr[i]);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun vfree(ptr);
214*4882a593Smuzhiyun return rv;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
full_fit_alloc_test(void)217*4882a593Smuzhiyun static int full_fit_alloc_test(void)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun void **ptr, **junk_ptr, *tmp;
220*4882a593Smuzhiyun int junk_length;
221*4882a593Smuzhiyun int rv = -1;
222*4882a593Smuzhiyun int i;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun junk_length = fls(num_online_cpus());
225*4882a593Smuzhiyun junk_length *= (32 * 1024 * 1024 / PAGE_SIZE);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun ptr = vmalloc(sizeof(void *) * junk_length);
228*4882a593Smuzhiyun if (!ptr)
229*4882a593Smuzhiyun return rv;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun junk_ptr = vmalloc(sizeof(void *) * junk_length);
232*4882a593Smuzhiyun if (!junk_ptr) {
233*4882a593Smuzhiyun vfree(ptr);
234*4882a593Smuzhiyun return rv;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun for (i = 0; i < junk_length; i++) {
238*4882a593Smuzhiyun ptr[i] = vmalloc(1 * PAGE_SIZE);
239*4882a593Smuzhiyun junk_ptr[i] = vmalloc(1 * PAGE_SIZE);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun for (i = 0; i < junk_length; i++)
243*4882a593Smuzhiyun vfree(junk_ptr[i]);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
246*4882a593Smuzhiyun tmp = vmalloc(1 * PAGE_SIZE);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (!tmp)
249*4882a593Smuzhiyun goto error;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun *((__u8 *)tmp) = 1;
252*4882a593Smuzhiyun vfree(tmp);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /* Success */
256*4882a593Smuzhiyun rv = 0;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun error:
259*4882a593Smuzhiyun for (i = 0; i < junk_length; i++)
260*4882a593Smuzhiyun vfree(ptr[i]);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun vfree(ptr);
263*4882a593Smuzhiyun vfree(junk_ptr);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun return rv;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
fix_size_alloc_test(void)268*4882a593Smuzhiyun static int fix_size_alloc_test(void)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun void *ptr;
271*4882a593Smuzhiyun int i;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
274*4882a593Smuzhiyun ptr = vmalloc(3 * PAGE_SIZE);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (!ptr)
277*4882a593Smuzhiyun return -1;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun *((__u8 *)ptr) = 0;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun vfree(ptr);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return 0;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun static int
pcpu_alloc_test(void)288*4882a593Smuzhiyun pcpu_alloc_test(void)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun int rv = 0;
291*4882a593Smuzhiyun #ifndef CONFIG_NEED_PER_CPU_KM
292*4882a593Smuzhiyun void __percpu **pcpu;
293*4882a593Smuzhiyun size_t size, align;
294*4882a593Smuzhiyun int i;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun pcpu = vmalloc(sizeof(void __percpu *) * 35000);
297*4882a593Smuzhiyun if (!pcpu)
298*4882a593Smuzhiyun return -1;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun for (i = 0; i < 35000; i++) {
301*4882a593Smuzhiyun unsigned int r;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun get_random_bytes(&r, sizeof(i));
304*4882a593Smuzhiyun size = (r % (PAGE_SIZE / 4)) + 1;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /*
307*4882a593Smuzhiyun * Maximum PAGE_SIZE
308*4882a593Smuzhiyun */
309*4882a593Smuzhiyun get_random_bytes(&r, sizeof(i));
310*4882a593Smuzhiyun align = 1 << ((i % 11) + 1);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun pcpu[i] = __alloc_percpu(size, align);
313*4882a593Smuzhiyun if (!pcpu[i])
314*4882a593Smuzhiyun rv = -1;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun for (i = 0; i < 35000; i++)
318*4882a593Smuzhiyun free_percpu(pcpu[i]);
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun vfree(pcpu);
321*4882a593Smuzhiyun #endif
322*4882a593Smuzhiyun return rv;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun struct test_kvfree_rcu {
326*4882a593Smuzhiyun struct rcu_head rcu;
327*4882a593Smuzhiyun unsigned char array[20];
328*4882a593Smuzhiyun };
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun static int
kvfree_rcu_1_arg_vmalloc_test(void)331*4882a593Smuzhiyun kvfree_rcu_1_arg_vmalloc_test(void)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun struct test_kvfree_rcu *p;
334*4882a593Smuzhiyun int i;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
337*4882a593Smuzhiyun p = vmalloc(1 * PAGE_SIZE);
338*4882a593Smuzhiyun if (!p)
339*4882a593Smuzhiyun return -1;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun p->array[0] = 'a';
342*4882a593Smuzhiyun kvfree_rcu(p);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun return 0;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun static int
kvfree_rcu_2_arg_vmalloc_test(void)349*4882a593Smuzhiyun kvfree_rcu_2_arg_vmalloc_test(void)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct test_kvfree_rcu *p;
352*4882a593Smuzhiyun int i;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
355*4882a593Smuzhiyun p = vmalloc(1 * PAGE_SIZE);
356*4882a593Smuzhiyun if (!p)
357*4882a593Smuzhiyun return -1;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun p->array[0] = 'a';
360*4882a593Smuzhiyun kvfree_rcu(p, rcu);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun static int
kvfree_rcu_1_arg_slab_test(void)367*4882a593Smuzhiyun kvfree_rcu_1_arg_slab_test(void)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun struct test_kvfree_rcu *p;
370*4882a593Smuzhiyun int i;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
373*4882a593Smuzhiyun p = kmalloc(sizeof(*p), GFP_KERNEL);
374*4882a593Smuzhiyun if (!p)
375*4882a593Smuzhiyun return -1;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun p->array[0] = 'a';
378*4882a593Smuzhiyun kvfree_rcu(p);
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun return 0;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun static int
kvfree_rcu_2_arg_slab_test(void)385*4882a593Smuzhiyun kvfree_rcu_2_arg_slab_test(void)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun struct test_kvfree_rcu *p;
388*4882a593Smuzhiyun int i;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun for (i = 0; i < test_loop_count; i++) {
391*4882a593Smuzhiyun p = kmalloc(sizeof(*p), GFP_KERNEL);
392*4882a593Smuzhiyun if (!p)
393*4882a593Smuzhiyun return -1;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun p->array[0] = 'a';
396*4882a593Smuzhiyun kvfree_rcu(p, rcu);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun return 0;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun struct test_case_desc {
403*4882a593Smuzhiyun const char *test_name;
404*4882a593Smuzhiyun int (*test_func)(void);
405*4882a593Smuzhiyun };
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun static struct test_case_desc test_case_array[] = {
408*4882a593Smuzhiyun { "fix_size_alloc_test", fix_size_alloc_test },
409*4882a593Smuzhiyun { "full_fit_alloc_test", full_fit_alloc_test },
410*4882a593Smuzhiyun { "long_busy_list_alloc_test", long_busy_list_alloc_test },
411*4882a593Smuzhiyun { "random_size_alloc_test", random_size_alloc_test },
412*4882a593Smuzhiyun { "fix_align_alloc_test", fix_align_alloc_test },
413*4882a593Smuzhiyun { "random_size_align_alloc_test", random_size_align_alloc_test },
414*4882a593Smuzhiyun { "align_shift_alloc_test", align_shift_alloc_test },
415*4882a593Smuzhiyun { "pcpu_alloc_test", pcpu_alloc_test },
416*4882a593Smuzhiyun { "kvfree_rcu_1_arg_vmalloc_test", kvfree_rcu_1_arg_vmalloc_test },
417*4882a593Smuzhiyun { "kvfree_rcu_2_arg_vmalloc_test", kvfree_rcu_2_arg_vmalloc_test },
418*4882a593Smuzhiyun { "kvfree_rcu_1_arg_slab_test", kvfree_rcu_1_arg_slab_test },
419*4882a593Smuzhiyun { "kvfree_rcu_2_arg_slab_test", kvfree_rcu_2_arg_slab_test },
420*4882a593Smuzhiyun /* Add a new test case here. */
421*4882a593Smuzhiyun };
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun struct test_case_data {
424*4882a593Smuzhiyun int test_failed;
425*4882a593Smuzhiyun int test_passed;
426*4882a593Smuzhiyun u64 time;
427*4882a593Smuzhiyun };
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun /* Split it to get rid of: WARNING: line over 80 characters */
430*4882a593Smuzhiyun static struct test_case_data
431*4882a593Smuzhiyun per_cpu_test_data[NR_CPUS][ARRAY_SIZE(test_case_array)];
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun static struct test_driver {
434*4882a593Smuzhiyun struct task_struct *task;
435*4882a593Smuzhiyun unsigned long start;
436*4882a593Smuzhiyun unsigned long stop;
437*4882a593Smuzhiyun int cpu;
438*4882a593Smuzhiyun } per_cpu_test_driver[NR_CPUS];
439*4882a593Smuzhiyun
shuffle_array(int * arr,int n)440*4882a593Smuzhiyun static void shuffle_array(int *arr, int n)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun unsigned int rnd;
443*4882a593Smuzhiyun int i, j, x;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun for (i = n - 1; i > 0; i--) {
446*4882a593Smuzhiyun get_random_bytes(&rnd, sizeof(rnd));
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /* Cut the range. */
449*4882a593Smuzhiyun j = rnd % i;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /* Swap indexes. */
452*4882a593Smuzhiyun x = arr[i];
453*4882a593Smuzhiyun arr[i] = arr[j];
454*4882a593Smuzhiyun arr[j] = x;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
test_func(void * private)458*4882a593Smuzhiyun static int test_func(void *private)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun struct test_driver *t = private;
461*4882a593Smuzhiyun int random_array[ARRAY_SIZE(test_case_array)];
462*4882a593Smuzhiyun int index, i, j;
463*4882a593Smuzhiyun ktime_t kt;
464*4882a593Smuzhiyun u64 delta;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun if (set_cpus_allowed_ptr(current, cpumask_of(t->cpu)) < 0)
467*4882a593Smuzhiyun pr_err("Failed to set affinity to %d CPU\n", t->cpu);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(test_case_array); i++)
470*4882a593Smuzhiyun random_array[i] = i;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (!sequential_test_order)
473*4882a593Smuzhiyun shuffle_array(random_array, ARRAY_SIZE(test_case_array));
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /*
476*4882a593Smuzhiyun * Block until initialization is done.
477*4882a593Smuzhiyun */
478*4882a593Smuzhiyun down_read(&prepare_for_test_rwsem);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun t->start = get_cycles();
481*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(test_case_array); i++) {
482*4882a593Smuzhiyun index = random_array[i];
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun /*
485*4882a593Smuzhiyun * Skip tests if run_test_mask has been specified.
486*4882a593Smuzhiyun */
487*4882a593Smuzhiyun if (!((run_test_mask & (1 << index)) >> index))
488*4882a593Smuzhiyun continue;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun kt = ktime_get();
491*4882a593Smuzhiyun for (j = 0; j < test_repeat_count; j++) {
492*4882a593Smuzhiyun if (!test_case_array[index].test_func())
493*4882a593Smuzhiyun per_cpu_test_data[t->cpu][index].test_passed++;
494*4882a593Smuzhiyun else
495*4882a593Smuzhiyun per_cpu_test_data[t->cpu][index].test_failed++;
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun /*
499*4882a593Smuzhiyun * Take an average time that test took.
500*4882a593Smuzhiyun */
501*4882a593Smuzhiyun delta = (u64) ktime_us_delta(ktime_get(), kt);
502*4882a593Smuzhiyun do_div(delta, (u32) test_repeat_count);
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun per_cpu_test_data[t->cpu][index].time = delta;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun t->stop = get_cycles();
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun up_read(&prepare_for_test_rwsem);
509*4882a593Smuzhiyun test_report_one_done();
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun /*
512*4882a593Smuzhiyun * Wait for the kthread_stop() call.
513*4882a593Smuzhiyun */
514*4882a593Smuzhiyun while (!kthread_should_stop())
515*4882a593Smuzhiyun msleep(10);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun return 0;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun static void
init_test_configurtion(void)521*4882a593Smuzhiyun init_test_configurtion(void)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun /*
524*4882a593Smuzhiyun * Reset all data of all CPUs.
525*4882a593Smuzhiyun */
526*4882a593Smuzhiyun memset(per_cpu_test_data, 0, sizeof(per_cpu_test_data));
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun if (single_cpu_test)
529*4882a593Smuzhiyun cpumask_set_cpu(cpumask_first(cpu_online_mask),
530*4882a593Smuzhiyun &cpus_run_test_mask);
531*4882a593Smuzhiyun else
532*4882a593Smuzhiyun cpumask_and(&cpus_run_test_mask, cpu_online_mask,
533*4882a593Smuzhiyun cpu_online_mask);
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun if (test_repeat_count <= 0)
536*4882a593Smuzhiyun test_repeat_count = 1;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun if (test_loop_count <= 0)
539*4882a593Smuzhiyun test_loop_count = 1;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
do_concurrent_test(void)542*4882a593Smuzhiyun static void do_concurrent_test(void)
543*4882a593Smuzhiyun {
544*4882a593Smuzhiyun int cpu, ret;
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun /*
547*4882a593Smuzhiyun * Set some basic configurations plus sanity check.
548*4882a593Smuzhiyun */
549*4882a593Smuzhiyun init_test_configurtion();
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun /*
552*4882a593Smuzhiyun * Put on hold all workers.
553*4882a593Smuzhiyun */
554*4882a593Smuzhiyun down_write(&prepare_for_test_rwsem);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun for_each_cpu(cpu, &cpus_run_test_mask) {
557*4882a593Smuzhiyun struct test_driver *t = &per_cpu_test_driver[cpu];
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun t->cpu = cpu;
560*4882a593Smuzhiyun t->task = kthread_run(test_func, t, "vmalloc_test/%d", cpu);
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun if (!IS_ERR(t->task))
563*4882a593Smuzhiyun /* Success. */
564*4882a593Smuzhiyun atomic_inc(&test_n_undone);
565*4882a593Smuzhiyun else
566*4882a593Smuzhiyun pr_err("Failed to start kthread for %d CPU\n", cpu);
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /*
570*4882a593Smuzhiyun * Now let the workers do their job.
571*4882a593Smuzhiyun */
572*4882a593Smuzhiyun up_write(&prepare_for_test_rwsem);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun /*
575*4882a593Smuzhiyun * Sleep quiet until all workers are done with 1 second
576*4882a593Smuzhiyun * interval. Since the test can take a lot of time we
577*4882a593Smuzhiyun * can run into a stack trace of the hung task. That is
578*4882a593Smuzhiyun * why we go with completion_timeout and HZ value.
579*4882a593Smuzhiyun */
580*4882a593Smuzhiyun do {
581*4882a593Smuzhiyun ret = wait_for_completion_timeout(&test_all_done_comp, HZ);
582*4882a593Smuzhiyun } while (!ret);
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun for_each_cpu(cpu, &cpus_run_test_mask) {
585*4882a593Smuzhiyun struct test_driver *t = &per_cpu_test_driver[cpu];
586*4882a593Smuzhiyun int i;
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun if (!IS_ERR(t->task))
589*4882a593Smuzhiyun kthread_stop(t->task);
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(test_case_array); i++) {
592*4882a593Smuzhiyun if (!((run_test_mask & (1 << i)) >> i))
593*4882a593Smuzhiyun continue;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun pr_info(
596*4882a593Smuzhiyun "Summary: %s passed: %d failed: %d repeat: %d loops: %d avg: %llu usec\n",
597*4882a593Smuzhiyun test_case_array[i].test_name,
598*4882a593Smuzhiyun per_cpu_test_data[cpu][i].test_passed,
599*4882a593Smuzhiyun per_cpu_test_data[cpu][i].test_failed,
600*4882a593Smuzhiyun test_repeat_count, test_loop_count,
601*4882a593Smuzhiyun per_cpu_test_data[cpu][i].time);
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun pr_info("All test took CPU%d=%lu cycles\n",
605*4882a593Smuzhiyun cpu, t->stop - t->start);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
vmalloc_test_init(void)609*4882a593Smuzhiyun static int vmalloc_test_init(void)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun do_concurrent_test();
612*4882a593Smuzhiyun return -EAGAIN; /* Fail will directly unload the module */
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
vmalloc_test_exit(void)615*4882a593Smuzhiyun static void vmalloc_test_exit(void)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun module_init(vmalloc_test_init)
620*4882a593Smuzhiyun module_exit(vmalloc_test_exit)
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun MODULE_LICENSE("GPL");
623*4882a593Smuzhiyun MODULE_AUTHOR("Uladzislau Rezki");
624*4882a593Smuzhiyun MODULE_DESCRIPTION("vmalloc test module");
625