xref: /OK3568_Linux_fs/kernel/lib/test_vmalloc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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