2 * This file is part of the SPL: Solaris Porting Layer.
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "splat-internal.h"
29 #define SPLAT_SUBSYSTEM_TASKQ 0x0200
30 #define SPLAT_TASKQ_NAME "taskq"
31 #define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
33 #define SPLAT_TASKQ_TEST1_ID 0x0201
34 #define SPLAT_TASKQ_TEST1_NAME "single"
35 #define SPLAT_TASKQ_TEST1_DESC "Single task queue, single task"
37 #define SPLAT_TASKQ_TEST2_ID 0x0202
38 #define SPLAT_TASKQ_TEST2_NAME "multiple"
39 #define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
41 #define SPLAT_TASKQ_TEST3_ID 0x0203
42 #define SPLAT_TASKQ_TEST3_NAME "system"
43 #define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks"
45 #define SPLAT_TASKQ_TEST4_ID 0x0204
46 #define SPLAT_TASKQ_TEST4_NAME "wait"
47 #define SPLAT_TASKQ_TEST4_DESC "Multiple task waiting"
49 typedef struct splat_taskq_arg
{
57 /* Validation Test 1 - Create a taskq, queue a task, wait until
58 * task completes, ensure task ran properly, cleanup taskq,
61 splat_taskq_test13_func(void *arg
)
63 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
66 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST1_NAME
,
67 "Taskq '%s' function '%s' setting flag\n",
68 tq_arg
->name
, sym2str(splat_taskq_test13_func
));
73 splat_taskq_test1(struct file
*file
, void *arg
)
77 splat_taskq_arg_t tq_arg
;
79 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' creating\n",
80 SPLAT_TASKQ_TEST1_NAME
);
81 if ((tq
= taskq_create(SPLAT_TASKQ_TEST1_NAME
, 1, maxclsyspri
,
82 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
83 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
84 "Taskq '%s' create failed\n",
85 SPLAT_TASKQ_TEST1_NAME
);
92 tq_arg
.name
= SPLAT_TASKQ_TEST1_NAME
;
94 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
95 "Taskq '%s' function '%s' dispatching\n",
96 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
97 if ((id
= taskq_dispatch(tq
, splat_taskq_test13_func
,
98 &tq_arg
, TQ_SLEEP
)) == 0) {
99 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
100 "Taskq '%s' function '%s' dispatch failed\n",
101 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
106 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' waiting\n",
109 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' destroying\n",
113 return (tq_arg
.flag
) ? 0 : -EINVAL
;
116 /* Validation Test 2 - Create multiple taskq's, each with multiple tasks,
117 * wait until all tasks complete, ensure all tasks ran properly and in the
118 * the correct order, cleanup taskq's
121 splat_taskq_test2_func1(void *arg
)
123 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
126 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
127 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
128 tq_arg
->name
, tq_arg
->id
,
129 sym2str(splat_taskq_test2_func1
),
130 tq_arg
->flag
* 2, tq_arg
->flag
);
135 splat_taskq_test2_func2(void *arg
)
137 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
140 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
141 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
142 tq_arg
->name
, tq_arg
->id
,
143 sym2str(splat_taskq_test2_func2
),
144 tq_arg
->flag
+ 1, tq_arg
->flag
);
148 #define TEST2_TASKQS 8
149 #define TEST2_THREADS_PER_TASKQ 4
152 splat_taskq_test2(struct file
*file
, void *arg
) {
153 taskq_t
*tq
[TEST2_TASKQS
] = { NULL
};
155 splat_taskq_arg_t tq_args
[TEST2_TASKQS
];
158 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
160 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
, "Taskq '%s/%d' "
161 "creating\n", SPLAT_TASKQ_TEST2_NAME
, i
);
162 if ((tq
[i
] = taskq_create(SPLAT_TASKQ_TEST2_NAME
,
163 TEST2_THREADS_PER_TASKQ
,
164 maxclsyspri
, 50, INT_MAX
,
165 TASKQ_PREPOPULATE
)) == NULL
) {
166 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
167 "Taskq '%s/%d' create failed\n",
168 SPLAT_TASKQ_TEST2_NAME
, i
);
175 tq_args
[i
].file
= file
;
176 tq_args
[i
].name
= SPLAT_TASKQ_TEST2_NAME
;
178 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
179 "Taskq '%s/%d' function '%s' dispatching\n",
180 tq_args
[i
].name
, tq_args
[i
].id
,
181 sym2str(splat_taskq_test2_func1
));
182 if ((id
= taskq_dispatch(
183 tq
[i
], splat_taskq_test2_func1
,
184 &tq_args
[i
], TQ_SLEEP
)) == 0) {
185 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
186 "Taskq '%s/%d' function '%s' dispatch "
187 "failed\n", tq_args
[i
].name
, tq_args
[i
].id
,
188 sym2str(splat_taskq_test2_func1
));
193 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
194 "Taskq '%s/%d' function '%s' dispatching\n",
195 tq_args
[i
].name
, tq_args
[i
].id
,
196 sym2str(splat_taskq_test2_func2
));
197 if ((id
= taskq_dispatch(
198 tq
[i
], splat_taskq_test2_func2
,
199 &tq_args
[i
], TQ_SLEEP
)) == 0) {
200 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
201 "Taskq '%s/%d' function '%s' dispatch failed\n",
202 tq_args
[i
].name
, tq_args
[i
].id
,
203 sym2str(splat_taskq_test2_func2
));
209 /* When rc is set we're effectively just doing cleanup here, so
210 * ignore new errors in that case. They just cause noise. */
211 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
213 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
214 "Taskq '%s/%d' waiting\n",
215 tq_args
[i
].name
, tq_args
[i
].id
);
217 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
218 "Taskq '%s/%d; destroying\n",
219 tq_args
[i
].name
, tq_args
[i
].id
);
220 taskq_destroy(tq
[i
]);
222 if (!rc
&& tq_args
[i
].flag
!= ((i
* 2) + 1)) {
223 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
224 "Taskq '%s/%d' processed tasks "
225 "out of order; %d != %d\n",
226 tq_args
[i
].name
, tq_args
[i
].id
,
227 tq_args
[i
].flag
, i
* 2 + 1);
230 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
231 "Taskq '%s/%d' processed tasks "
232 "in the correct order; %d == %d\n",
233 tq_args
[i
].name
, tq_args
[i
].id
,
234 tq_args
[i
].flag
, i
* 2 + 1);
242 /* Validation Test 3 - Use the global system task queue with a single
243 * task, * wait until task completes, ensure task ran properly.
246 splat_taskq_test3(struct file
*file
, void *arg
)
249 splat_taskq_arg_t tq_arg
;
254 tq_arg
.name
= SPLAT_TASKQ_TEST3_NAME
;
256 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
257 "Taskq '%s' function '%s' dispatching\n",
258 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
259 if ((id
= taskq_dispatch(system_taskq
, splat_taskq_test13_func
,
260 &tq_arg
, TQ_SLEEP
)) == 0) {
261 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
262 "Taskq '%s' function '%s' dispatch failed\n",
263 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
267 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
, "Taskq '%s' waiting\n",
269 taskq_wait(system_taskq
);
271 return (tq_arg
.flag
) ? 0 : -EINVAL
;
275 splat_taskq_test4_func(void *arg
)
277 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
280 atomic_inc(&tq_arg
->count
);
284 splat_taskq_test4(struct file
*file
, void *arg
)
287 splat_taskq_arg_t tq_arg
;
290 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' creating\n",
291 SPLAT_TASKQ_TEST4_NAME
);
292 if ((tq
= taskq_create(SPLAT_TASKQ_TEST4_NAME
, 1, maxclsyspri
,
293 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
294 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
295 "Taskq '%s' create failed\n",
296 SPLAT_TASKQ_TEST4_NAME
);
301 tq_arg
.name
= SPLAT_TASKQ_TEST4_NAME
;
303 for (i
= 1; i
<= 1024; i
*= 2) {
304 atomic_set(&tq_arg
.count
, 0);
305 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
306 "Taskq '%s' function '%s' dispatched %d times\n",
307 tq_arg
.name
, sym2str(splat_taskq_test4_func
), i
);
309 for (j
= 0; j
< i
; j
++) {
310 if ((taskq_dispatch(tq
, splat_taskq_test4_func
,
311 &tq_arg
, TQ_SLEEP
)) == 0) {
312 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
313 "Taskq '%s' function '%s' dispatch "
314 "%d failed\n", tq_arg
.name
,
315 sym2str(splat_taskq_test13_func
), j
);
321 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' "
322 "waiting for %d dispatches\n", tq_arg
.name
, i
);
324 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' "
325 "%d/%d dispatches finished\n", tq_arg
.name
,
326 atomic_read(&tq_arg
.count
), i
);
327 if (atomic_read(&tq_arg
.count
) != i
) {
334 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' destroying\n",
342 splat_taskq_init(void)
344 splat_subsystem_t
*sub
;
346 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
350 memset(sub
, 0, sizeof(*sub
));
351 strncpy(sub
->desc
.name
, SPLAT_TASKQ_NAME
, SPLAT_NAME_SIZE
);
352 strncpy(sub
->desc
.desc
, SPLAT_TASKQ_DESC
, SPLAT_DESC_SIZE
);
353 INIT_LIST_HEAD(&sub
->subsystem_list
);
354 INIT_LIST_HEAD(&sub
->test_list
);
355 spin_lock_init(&sub
->test_lock
);
356 sub
->desc
.id
= SPLAT_SUBSYSTEM_TASKQ
;
358 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST1_NAME
, SPLAT_TASKQ_TEST1_DESC
,
359 SPLAT_TASKQ_TEST1_ID
, splat_taskq_test1
);
360 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST2_NAME
, SPLAT_TASKQ_TEST2_DESC
,
361 SPLAT_TASKQ_TEST2_ID
, splat_taskq_test2
);
362 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST3_NAME
, SPLAT_TASKQ_TEST3_DESC
,
363 SPLAT_TASKQ_TEST3_ID
, splat_taskq_test3
);
364 SPLAT_TEST_INIT(sub
, SPLAT_TASKQ_TEST4_NAME
, SPLAT_TASKQ_TEST4_DESC
,
365 SPLAT_TASKQ_TEST4_ID
, splat_taskq_test4
);
371 splat_taskq_fini(splat_subsystem_t
*sub
)
374 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST4_ID
);
375 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST3_ID
);
376 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST2_ID
);
377 SPLAT_TEST_FINI(sub
, SPLAT_TASKQ_TEST1_ID
);
383 splat_taskq_id(void) {
384 return SPLAT_SUBSYSTEM_TASKQ
;