2 * lib/test_parman.c - Test module for parman
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
37 #include <linux/kernel.h>
38 #include <linux/module.h>
39 #include <linux/slab.h>
40 #include <linux/bitops.h>
41 #include <linux/err.h>
42 #include <linux/random.h>
43 #include <linux/parman.h>
45 #define TEST_PARMAN_PRIO_SHIFT 7 /* defines number of prios for testing */
46 #define TEST_PARMAN_PRIO_COUNT BIT(TEST_PARMAN_PRIO_SHIFT)
47 #define TEST_PARMAN_PRIO_MASK (TEST_PARMAN_PRIO_COUNT - 1)
49 #define TEST_PARMAN_ITEM_SHIFT 13 /* defines a total number
50 * of items for testing
52 #define TEST_PARMAN_ITEM_COUNT BIT(TEST_PARMAN_ITEM_SHIFT)
53 #define TEST_PARMAN_ITEM_MASK (TEST_PARMAN_ITEM_COUNT - 1)
55 #define TEST_PARMAN_BASE_SHIFT 8
56 #define TEST_PARMAN_BASE_COUNT BIT(TEST_PARMAN_BASE_SHIFT)
57 #define TEST_PARMAN_RESIZE_STEP_SHIFT 7
58 #define TEST_PARMAN_RESIZE_STEP_COUNT BIT(TEST_PARMAN_RESIZE_STEP_SHIFT)
60 #define TEST_PARMAN_BULK_MAX_SHIFT (2 + TEST_PARMAN_RESIZE_STEP_SHIFT)
61 #define TEST_PARMAN_BULK_MAX_COUNT BIT(TEST_PARMAN_BULK_MAX_SHIFT)
62 #define TEST_PARMAN_BULK_MAX_MASK (TEST_PARMAN_BULK_MAX_COUNT - 1)
64 #define TEST_PARMAN_RUN_BUDGET (TEST_PARMAN_ITEM_COUNT * 256)
66 struct test_parman_prio
{
67 struct parman_prio parman_prio
;
68 unsigned long priority
;
71 struct test_parman_item
{
72 struct parman_item parman_item
;
73 struct test_parman_prio
*prio
;
78 struct parman
*parman
;
79 struct test_parman_item
**prio_array
;
80 unsigned long prio_array_limit
;
81 struct test_parman_prio prios
[TEST_PARMAN_PRIO_COUNT
];
82 struct test_parman_item items
[TEST_PARMAN_ITEM_COUNT
];
84 unsigned long run_budget
;
85 unsigned long bulk_budget
;
87 unsigned int used_items
;
90 #define ITEM_PTRS_SIZE(count) (sizeof(struct test_parman_item *) * (count))
92 static int test_parman_resize(void *priv
, unsigned long new_count
)
94 struct test_parman
*test_parman
= priv
;
95 struct test_parman_item
**prio_array
;
96 unsigned long old_count
;
98 prio_array
= krealloc(test_parman
->prio_array
,
99 ITEM_PTRS_SIZE(new_count
), GFP_KERNEL
);
104 old_count
= test_parman
->prio_array_limit
;
105 if (new_count
> old_count
)
106 memset(&prio_array
[old_count
], 0,
107 ITEM_PTRS_SIZE(new_count
- old_count
));
108 test_parman
->prio_array
= prio_array
;
109 test_parman
->prio_array_limit
= new_count
;
113 static void test_parman_move(void *priv
, unsigned long from_index
,
114 unsigned long to_index
, unsigned long count
)
116 struct test_parman
*test_parman
= priv
;
117 struct test_parman_item
**prio_array
= test_parman
->prio_array
;
119 memmove(&prio_array
[to_index
], &prio_array
[from_index
],
120 ITEM_PTRS_SIZE(count
));
121 memset(&prio_array
[from_index
], 0, ITEM_PTRS_SIZE(count
));
124 static const struct parman_ops test_parman_lsort_ops
= {
125 .base_count
= TEST_PARMAN_BASE_COUNT
,
126 .resize_step
= TEST_PARMAN_RESIZE_STEP_COUNT
,
127 .resize
= test_parman_resize
,
128 .move
= test_parman_move
,
129 .algo
= PARMAN_ALGO_TYPE_LSORT
,
132 static void test_parman_rnd_init(struct test_parman
*test_parman
)
134 prandom_seed_state(&test_parman
->rnd
, 3141592653589793238ULL);
137 static u32
test_parman_rnd_get(struct test_parman
*test_parman
)
139 return prandom_u32_state(&test_parman
->rnd
);
142 static unsigned long test_parman_priority_gen(struct test_parman
*test_parman
)
144 unsigned long priority
;
148 priority
= test_parman_rnd_get(test_parman
);
152 for (i
= 0; i
< TEST_PARMAN_PRIO_COUNT
; i
++) {
153 struct test_parman_prio
*prio
= &test_parman
->prios
[i
];
155 if (prio
->priority
== 0)
157 if (prio
->priority
== priority
)
163 static void test_parman_prios_init(struct test_parman
*test_parman
)
167 for (i
= 0; i
< TEST_PARMAN_PRIO_COUNT
; i
++) {
168 struct test_parman_prio
*prio
= &test_parman
->prios
[i
];
170 /* Assign random uniqueue priority to each prio structure */
171 prio
->priority
= test_parman_priority_gen(test_parman
);
172 parman_prio_init(test_parman
->parman
, &prio
->parman_prio
,
177 static void test_parman_prios_fini(struct test_parman
*test_parman
)
181 for (i
= 0; i
< TEST_PARMAN_PRIO_COUNT
; i
++) {
182 struct test_parman_prio
*prio
= &test_parman
->prios
[i
];
184 parman_prio_fini(&prio
->parman_prio
);
188 static void test_parman_items_init(struct test_parman
*test_parman
)
192 for (i
= 0; i
< TEST_PARMAN_ITEM_COUNT
; i
++) {
193 struct test_parman_item
*item
= &test_parman
->items
[i
];
194 unsigned int prio_index
= test_parman_rnd_get(test_parman
) &
195 TEST_PARMAN_PRIO_MASK
;
197 /* Assign random prio to each item structure */
198 item
->prio
= &test_parman
->prios
[prio_index
];
202 static void test_parman_items_fini(struct test_parman
*test_parman
)
206 for (i
= 0; i
< TEST_PARMAN_ITEM_COUNT
; i
++) {
207 struct test_parman_item
*item
= &test_parman
->items
[i
];
211 parman_item_remove(test_parman
->parman
,
212 &item
->prio
->parman_prio
,
217 static struct test_parman
*test_parman_create(const struct parman_ops
*ops
)
219 struct test_parman
*test_parman
;
222 test_parman
= kzalloc(sizeof(*test_parman
), GFP_KERNEL
);
224 return ERR_PTR(-ENOMEM
);
225 err
= test_parman_resize(test_parman
, TEST_PARMAN_BASE_COUNT
);
228 test_parman
->parman
= parman_create(ops
, test_parman
);
229 if (!test_parman
->parman
) {
231 goto err_parman_create
;
233 test_parman_rnd_init(test_parman
);
234 test_parman_prios_init(test_parman
);
235 test_parman_items_init(test_parman
);
236 test_parman
->run_budget
= TEST_PARMAN_RUN_BUDGET
;
240 test_parman_resize(test_parman
, 0);
246 static void test_parman_destroy(struct test_parman
*test_parman
)
248 test_parman_items_fini(test_parman
);
249 test_parman_prios_fini(test_parman
);
250 parman_destroy(test_parman
->parman
);
251 test_parman_resize(test_parman
, 0);
255 static bool test_parman_run_check_budgets(struct test_parman
*test_parman
)
257 if (test_parman
->run_budget
-- == 0)
259 if (test_parman
->bulk_budget
-- != 0)
262 test_parman
->bulk_budget
= test_parman_rnd_get(test_parman
) &
263 TEST_PARMAN_BULK_MAX_MASK
;
264 test_parman
->bulk_noop
= test_parman_rnd_get(test_parman
) & 1;
268 static int test_parman_run(struct test_parman
*test_parman
)
270 unsigned int i
= test_parman_rnd_get(test_parman
);
273 while (test_parman_run_check_budgets(test_parman
)) {
274 unsigned int item_index
= i
++ & TEST_PARMAN_ITEM_MASK
;
275 struct test_parman_item
*item
= &test_parman
->items
[item_index
];
277 if (test_parman
->bulk_noop
)
281 err
= parman_item_add(test_parman
->parman
,
282 &item
->prio
->parman_prio
,
286 test_parman
->prio_array
[item
->parman_item
.index
] = item
;
287 test_parman
->used_items
++;
289 test_parman
->prio_array
[item
->parman_item
.index
] = NULL
;
290 parman_item_remove(test_parman
->parman
,
291 &item
->prio
->parman_prio
,
293 test_parman
->used_items
--;
295 item
->used
= !item
->used
;
300 static int test_parman_check_array(struct test_parman
*test_parman
,
303 unsigned int last_unused_items
= 0;
304 unsigned long last_priority
= 0;
305 unsigned int used_items
= 0;
308 if (test_parman
->prio_array_limit
< TEST_PARMAN_BASE_COUNT
) {
309 pr_err("Array limit is lower than the base count (%lu < %lu)\n",
310 test_parman
->prio_array_limit
, TEST_PARMAN_BASE_COUNT
);
314 for (i
= 0; i
< test_parman
->prio_array_limit
; i
++) {
315 struct test_parman_item
*item
= test_parman
->prio_array
[i
];
321 if (last_unused_items
&& !gaps_allowed
) {
322 pr_err("Gap found in array even though they are forbidden\n");
326 last_unused_items
= 0;
329 if (item
->prio
->priority
< last_priority
) {
330 pr_err("Item belongs under higher priority then the last one (current: %lu, previous: %lu)\n",
331 item
->prio
->priority
, last_priority
);
334 last_priority
= item
->prio
->priority
;
336 if (item
->parman_item
.index
!= i
) {
337 pr_err("Item has different index in compare to where it actually is (%lu != %d)\n",
338 item
->parman_item
.index
, i
);
343 if (used_items
!= test_parman
->used_items
) {
344 pr_err("Number of used items in array does not match (%u != %u)\n",
345 used_items
, test_parman
->used_items
);
349 if (last_unused_items
>= TEST_PARMAN_RESIZE_STEP_COUNT
) {
350 pr_err("Number of unused item at the end of array is bigger than resize step (%u >= %lu)\n",
351 last_unused_items
, TEST_PARMAN_RESIZE_STEP_COUNT
);
355 pr_info("Priority array check successful\n");
360 static int test_parman_lsort(void)
362 struct test_parman
*test_parman
;
365 test_parman
= test_parman_create(&test_parman_lsort_ops
);
366 if (IS_ERR(test_parman
))
367 return PTR_ERR(test_parman
);
369 err
= test_parman_run(test_parman
);
373 err
= test_parman_check_array(test_parman
, false);
377 test_parman_destroy(test_parman
);
381 static int __init
test_parman_init(void)
383 return test_parman_lsort();
386 static void __exit
test_parman_exit(void)
390 module_init(test_parman_init
);
391 module_exit(test_parman_exit
);
393 MODULE_LICENSE("Dual BSD/GPL");
394 MODULE_AUTHOR("Jiri Pirko <jiri@mellanox.com>");
395 MODULE_DESCRIPTION("Test module for parman");