2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * You should have received a copy of the GNU General Public License along
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) Task Queue Tests.
29 #include <sys/random.h>
30 #include <sys/taskq.h>
32 #include <sys/timer.h>
33 #include <linux/delay.h>
34 #include "splat-internal.h"
36 #define SPLAT_TASKQ_NAME "taskq"
37 #define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
39 #define SPLAT_TASKQ_TEST1_ID 0x0201
40 #define SPLAT_TASKQ_TEST1_NAME "single"
41 #define SPLAT_TASKQ_TEST1_DESC "Single task queue, single task"
43 #define SPLAT_TASKQ_TEST2_ID 0x0202
44 #define SPLAT_TASKQ_TEST2_NAME "multiple"
45 #define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
47 #define SPLAT_TASKQ_TEST3_ID 0x0203
48 #define SPLAT_TASKQ_TEST3_NAME "system"
49 #define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks"
51 #define SPLAT_TASKQ_TEST4_ID 0x0204
52 #define SPLAT_TASKQ_TEST4_NAME "wait"
53 #define SPLAT_TASKQ_TEST4_DESC "Multiple task waiting"
55 #define SPLAT_TASKQ_TEST5_ID 0x0205
56 #define SPLAT_TASKQ_TEST5_NAME "order"
57 #define SPLAT_TASKQ_TEST5_DESC "Correct task ordering"
59 #define SPLAT_TASKQ_TEST6_ID 0x0206
60 #define SPLAT_TASKQ_TEST6_NAME "front"
61 #define SPLAT_TASKQ_TEST6_DESC "Correct ordering with TQ_FRONT flag"
63 #define SPLAT_TASKQ_TEST7_ID 0x0207
64 #define SPLAT_TASKQ_TEST7_NAME "recurse"
65 #define SPLAT_TASKQ_TEST7_DESC "Single task queue, recursive dispatch"
67 #define SPLAT_TASKQ_TEST8_ID 0x0208
68 #define SPLAT_TASKQ_TEST8_NAME "contention"
69 #define SPLAT_TASKQ_TEST8_DESC "1 queue, 100 threads, 131072 tasks"
71 #define SPLAT_TASKQ_TEST9_ID 0x0209
72 #define SPLAT_TASKQ_TEST9_NAME "delay"
73 #define SPLAT_TASKQ_TEST9_DESC "Delayed task execution"
75 #define SPLAT_TASKQ_TEST10_ID 0x020a
76 #define SPLAT_TASKQ_TEST10_NAME "cancel"
77 #define SPLAT_TASKQ_TEST10_DESC "Cancel task execution"
79 #define SPLAT_TASKQ_TEST11_ID 0x020b
80 #define SPLAT_TASKQ_TEST11_NAME "dynamic"
81 #define SPLAT_TASKQ_TEST11_DESC "Dynamic task queue thread creation"
83 #define SPLAT_TASKQ_ORDER_MAX 8
84 #define SPLAT_TASKQ_DEPTH_MAX 16
87 typedef struct splat_taskq_arg
{
91 int order
[SPLAT_TASKQ_ORDER_MAX
];
101 typedef struct splat_taskq_id
{
103 splat_taskq_arg_t
*arg
;
107 * Create a taskq, queue a task, wait until task completes, ensure
108 * task ran properly, cleanup taskq.
111 splat_taskq_test13_func(void *arg
)
113 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
116 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST1_NAME
,
117 "Taskq '%s' function '%s' setting flag\n",
118 tq_arg
->name
, sym2str(splat_taskq_test13_func
));
123 splat_taskq_test1_impl(struct file
*file
, void *arg
, boolean_t prealloc
)
127 splat_taskq_arg_t tq_arg
;
130 tqe
= kmem_alloc(sizeof (taskq_ent_t
), KM_SLEEP
);
133 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
134 "Taskq '%s' creating (%s dispatch)\n",
135 SPLAT_TASKQ_TEST1_NAME
,
136 prealloc
? "prealloc" : "dynamic");
137 if ((tq
= taskq_create(SPLAT_TASKQ_TEST1_NAME
, 1, defclsyspri
,
138 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
139 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
140 "Taskq '%s' create failed\n",
141 SPLAT_TASKQ_TEST1_NAME
);
142 kmem_free(tqe
, sizeof (taskq_ent_t
));
149 tq_arg
.name
= SPLAT_TASKQ_TEST1_NAME
;
151 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
152 "Taskq '%s' function '%s' dispatching\n",
153 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
155 taskq_dispatch_ent(tq
, splat_taskq_test13_func
,
156 &tq_arg
, TQ_SLEEP
, tqe
);
159 id
= taskq_dispatch(tq
, splat_taskq_test13_func
,
163 if (id
== TASKQID_INVALID
) {
164 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
,
165 "Taskq '%s' function '%s' dispatch failed\n",
166 tq_arg
.name
, sym2str(splat_taskq_test13_func
));
167 kmem_free(tqe
, sizeof (taskq_ent_t
));
172 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' waiting\n",
175 splat_vprint(file
, SPLAT_TASKQ_TEST1_NAME
, "Taskq '%s' destroying\n",
178 kmem_free(tqe
, sizeof (taskq_ent_t
));
181 return (tq_arg
.flag
) ? 0 : -EINVAL
;
185 splat_taskq_test1(struct file
*file
, void *arg
)
189 rc
= splat_taskq_test1_impl(file
, arg
, B_FALSE
);
193 rc
= splat_taskq_test1_impl(file
, arg
, B_TRUE
);
199 * Create multiple taskq's, each with multiple tasks, wait until
200 * all tasks complete, ensure all tasks ran properly and in the
201 * correct order. Run order must be the same as the order submitted
202 * because we only have 1 thread per taskq. Finally cleanup the taskq.
205 splat_taskq_test2_func1(void *arg
)
207 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
210 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
211 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
212 tq_arg
->name
, tq_arg
->id
,
213 sym2str(splat_taskq_test2_func1
),
214 tq_arg
->flag
* 2, tq_arg
->flag
);
219 splat_taskq_test2_func2(void *arg
)
221 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
224 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST2_NAME
,
225 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
226 tq_arg
->name
, tq_arg
->id
,
227 sym2str(splat_taskq_test2_func2
),
228 tq_arg
->flag
+ 1, tq_arg
->flag
);
232 #define TEST2_TASKQS 8
233 #define TEST2_THREADS_PER_TASKQ 1
236 splat_taskq_test2_impl(struct file
*file
, void *arg
, boolean_t prealloc
) {
237 taskq_t
*tq
[TEST2_TASKQS
] = { NULL
};
239 splat_taskq_arg_t
*tq_args
[TEST2_TASKQS
] = { NULL
};
240 taskq_ent_t
*func1_tqes
= NULL
;
241 taskq_ent_t
*func2_tqes
= NULL
;
244 func1_tqes
= kmalloc(sizeof(*func1_tqes
) * TEST2_TASKQS
, GFP_KERNEL
);
245 if (func1_tqes
== NULL
) {
250 func2_tqes
= kmalloc(sizeof(*func2_tqes
) * TEST2_TASKQS
, GFP_KERNEL
);
251 if (func2_tqes
== NULL
) {
256 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
257 taskq_init_ent(&func1_tqes
[i
]);
258 taskq_init_ent(&func2_tqes
[i
]);
260 tq_args
[i
] = kmalloc(sizeof (splat_taskq_arg_t
), GFP_KERNEL
);
261 if (tq_args
[i
] == NULL
) {
266 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
267 "Taskq '%s/%d' creating (%s dispatch)\n",
268 SPLAT_TASKQ_TEST2_NAME
, i
,
269 prealloc
? "prealloc" : "dynamic");
270 if ((tq
[i
] = taskq_create(SPLAT_TASKQ_TEST2_NAME
,
271 TEST2_THREADS_PER_TASKQ
,
272 defclsyspri
, 50, INT_MAX
,
273 TASKQ_PREPOPULATE
)) == NULL
) {
274 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
275 "Taskq '%s/%d' create failed\n",
276 SPLAT_TASKQ_TEST2_NAME
, i
);
281 tq_args
[i
]->flag
= i
;
283 tq_args
[i
]->file
= file
;
284 tq_args
[i
]->name
= SPLAT_TASKQ_TEST2_NAME
;
286 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
287 "Taskq '%s/%d' function '%s' dispatching\n",
288 tq_args
[i
]->name
, tq_args
[i
]->id
,
289 sym2str(splat_taskq_test2_func1
));
291 taskq_dispatch_ent(tq
[i
], splat_taskq_test2_func1
,
292 tq_args
[i
], TQ_SLEEP
, &func1_tqes
[i
]);
293 id
= func1_tqes
[i
].tqent_id
;
295 id
= taskq_dispatch(tq
[i
], splat_taskq_test2_func1
,
296 tq_args
[i
], TQ_SLEEP
);
299 if (id
== TASKQID_INVALID
) {
300 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
301 "Taskq '%s/%d' function '%s' dispatch "
302 "failed\n", tq_args
[i
]->name
, tq_args
[i
]->id
,
303 sym2str(splat_taskq_test2_func1
));
308 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
309 "Taskq '%s/%d' function '%s' dispatching\n",
310 tq_args
[i
]->name
, tq_args
[i
]->id
,
311 sym2str(splat_taskq_test2_func2
));
313 taskq_dispatch_ent(tq
[i
], splat_taskq_test2_func2
,
314 tq_args
[i
], TQ_SLEEP
, &func2_tqes
[i
]);
315 id
= func2_tqes
[i
].tqent_id
;
317 id
= taskq_dispatch(tq
[i
], splat_taskq_test2_func2
,
318 tq_args
[i
], TQ_SLEEP
);
321 if (id
== TASKQID_INVALID
) {
322 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
, "Taskq "
323 "'%s/%d' function '%s' dispatch failed\n",
324 tq_args
[i
]->name
, tq_args
[i
]->id
,
325 sym2str(splat_taskq_test2_func2
));
331 /* When rc is set we're effectively just doing cleanup here, so
332 * ignore new errors in that case. They just cause noise. */
333 for (i
= 0; i
< TEST2_TASKQS
; i
++) {
334 if (tq_args
[i
] == NULL
)
338 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
339 "Taskq '%s/%d' waiting\n",
340 tq_args
[i
]->name
, tq_args
[i
]->id
);
342 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
343 "Taskq '%s/%d; destroying\n",
344 tq_args
[i
]->name
, tq_args
[i
]->id
);
346 taskq_destroy(tq
[i
]);
348 if (!rc
&& tq_args
[i
]->flag
!= ((i
* 2) + 1)) {
349 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
350 "Taskq '%s/%d' processed tasks "
351 "out of order; %d != %d\n",
352 tq_args
[i
]->name
, tq_args
[i
]->id
,
353 tq_args
[i
]->flag
, i
* 2 + 1);
356 splat_vprint(file
, SPLAT_TASKQ_TEST2_NAME
,
357 "Taskq '%s/%d' processed tasks "
358 "in the correct order; %d == %d\n",
359 tq_args
[i
]->name
, tq_args
[i
]->id
,
360 tq_args
[i
]->flag
, i
* 2 + 1);
377 splat_taskq_test2(struct file
*file
, void *arg
) {
380 rc
= splat_taskq_test2_impl(file
, arg
, B_FALSE
);
384 rc
= splat_taskq_test2_impl(file
, arg
, B_TRUE
);
390 * Use the global system task queue with a single task, wait until task
391 * completes, ensure task ran properly.
394 splat_taskq_test3_impl(struct file
*file
, void *arg
, boolean_t prealloc
)
397 splat_taskq_arg_t
*tq_arg
;
401 tq_arg
= kmem_alloc(sizeof (splat_taskq_arg_t
), KM_SLEEP
);
402 tqe
= kmem_alloc(sizeof (taskq_ent_t
), KM_SLEEP
);
408 tq_arg
->name
= SPLAT_TASKQ_TEST3_NAME
;
410 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
411 "Taskq '%s' function '%s' %s dispatch\n",
412 tq_arg
->name
, sym2str(splat_taskq_test13_func
),
413 prealloc
? "prealloc" : "dynamic");
415 taskq_dispatch_ent(system_taskq
, splat_taskq_test13_func
,
416 tq_arg
, TQ_SLEEP
, tqe
);
419 id
= taskq_dispatch(system_taskq
, splat_taskq_test13_func
,
423 if (id
== TASKQID_INVALID
) {
424 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
,
425 "Taskq '%s' function '%s' dispatch failed\n",
426 tq_arg
->name
, sym2str(splat_taskq_test13_func
));
427 kmem_free(tqe
, sizeof (taskq_ent_t
));
428 kmem_free(tq_arg
, sizeof (splat_taskq_arg_t
));
432 splat_vprint(file
, SPLAT_TASKQ_TEST3_NAME
, "Taskq '%s' waiting\n",
434 taskq_wait(system_taskq
);
436 error
= (tq_arg
->flag
) ? 0 : -EINVAL
;
438 kmem_free(tqe
, sizeof (taskq_ent_t
));
439 kmem_free(tq_arg
, sizeof (splat_taskq_arg_t
));
445 splat_taskq_test3(struct file
*file
, void *arg
)
449 rc
= splat_taskq_test3_impl(file
, arg
, B_FALSE
);
453 rc
= splat_taskq_test3_impl(file
, arg
, B_TRUE
);
459 * Create a taskq and dispatch a large number of tasks to the queue.
460 * Then use taskq_wait() to block until all the tasks complete, then
461 * cross check that all the tasks ran by checking the shared atomic
462 * counter which is incremented in the task function.
464 * First we try with a large 'maxalloc' value, then we try with a small one.
465 * We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
466 * if the number of pending tasks is above maxalloc.
469 splat_taskq_test4_func(void *arg
)
471 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
474 atomic_inc(tq_arg
->count
);
478 splat_taskq_test4_common(struct file
*file
, void *arg
, int minalloc
,
479 int maxalloc
, int nr_tasks
, boolean_t prealloc
)
483 splat_taskq_arg_t tq_arg
;
488 tqes
= kmalloc(sizeof(*tqes
) * nr_tasks
, GFP_KERNEL
);
492 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
493 "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
494 SPLAT_TASKQ_TEST4_NAME
,
495 prealloc
? "prealloc" : "dynamic",
496 minalloc
, maxalloc
, nr_tasks
);
497 if ((tq
= taskq_create(SPLAT_TASKQ_TEST4_NAME
, 1, defclsyspri
,
498 minalloc
, maxalloc
, TASKQ_PREPOPULATE
)) == NULL
) {
499 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
500 "Taskq '%s' create failed\n",
501 SPLAT_TASKQ_TEST4_NAME
);
507 tq_arg
.name
= SPLAT_TASKQ_TEST4_NAME
;
508 tq_arg
.count
= &count
;
510 for (i
= 1; i
<= nr_tasks
; i
*= 2) {
511 atomic_set(tq_arg
.count
, 0);
512 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
513 "Taskq '%s' function '%s' dispatched %d times\n",
514 tq_arg
.name
, sym2str(splat_taskq_test4_func
), i
);
516 for (j
= 0; j
< i
; j
++) {
517 taskq_init_ent(&tqes
[j
]);
520 taskq_dispatch_ent(tq
, splat_taskq_test4_func
,
521 &tq_arg
, TQ_SLEEP
, &tqes
[j
]);
522 id
= tqes
[j
].tqent_id
;
524 id
= taskq_dispatch(tq
, splat_taskq_test4_func
,
528 if (id
== TASKQID_INVALID
) {
529 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
,
530 "Taskq '%s' function '%s' dispatch "
531 "%d failed\n", tq_arg
.name
,
532 sym2str(splat_taskq_test4_func
), j
);
538 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' "
539 "waiting for %d dispatches\n", tq_arg
.name
, i
);
541 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' "
542 "%d/%d dispatches finished\n", tq_arg
.name
,
543 atomic_read(&count
), i
);
544 if (atomic_read(&count
) != i
) {
551 splat_vprint(file
, SPLAT_TASKQ_TEST4_NAME
, "Taskq '%s' destroying\n",
562 splat_taskq_test4_impl(struct file
*file
, void *arg
, boolean_t prealloc
)
566 rc
= splat_taskq_test4_common(file
, arg
, 50, INT_MAX
, 1024, prealloc
);
570 rc
= splat_taskq_test4_common(file
, arg
, 1, 1, 32, prealloc
);
576 splat_taskq_test4(struct file
*file
, void *arg
)
580 rc
= splat_taskq_test4_impl(file
, arg
, B_FALSE
);
584 rc
= splat_taskq_test4_impl(file
, arg
, B_TRUE
);
590 * Create a taskq and dispatch a specific sequence of tasks carefully
591 * crafted to validate the order in which tasks are processed. When
592 * there are multiple worker threads each thread will process the
593 * next pending task as soon as it completes its current task. This
594 * means that tasks do not strictly complete in order in which they
595 * were dispatched (increasing task id). This is fine but we need to
596 * verify taskq_wait_outstanding() blocks until the passed task id and
597 * all lower task ids complete. We do this by dispatching the following
598 * specific sequence of tasks each of which block for N time units.
599 * We then use taskq_wait_outstanding() to unblock at specific task id and
600 * verify the only the expected task ids have completed and in the
601 * correct order. The two cases of interest are:
603 * 1) Task ids larger than the waited for task id can run and
604 * complete as long as there is an available worker thread.
605 * 2) All task ids lower than the waited one must complete before
606 * unblocking even if the waited task id itself has completed.
608 * The following table shows each task id and how they will be
609 * scheduled. Each rows represent one time unit and each column
610 * one of the three worker threads. The places taskq_wait_outstanding()
611 * must unblock for a specific id are identified as well as the
612 * task ids which must have completed and their order.
614 * +-----+ <--- taskq_wait_outstanding(tq, 8) unblocks
615 * | | Required Completion Order: 1,2,4,5,3,8,6,7
620 * | | +-----+ <--- taskq_wait_outstanding(tq, 3) unblocks
621 * | | 7 | | Required Completion Order: 1,2,4,5,3
630 * +-----+-----+-----+
634 splat_taskq_test5_func(void *arg
)
636 splat_taskq_id_t
*tq_id
= (splat_taskq_id_t
*)arg
;
637 splat_taskq_arg_t
*tq_arg
= tq_id
->arg
;
640 /* Delays determined by above table */
642 default: factor
= 0; break;
643 case 1: case 8: factor
= 1; break;
644 case 2: case 4: case 5: factor
= 2; break;
645 case 6: case 7: factor
= 4; break;
646 case 3: factor
= 5; break;
649 msleep(factor
* 100);
650 splat_vprint(tq_arg
->file
, tq_arg
->name
,
651 "Taskqid %d complete for taskq '%s'\n",
652 tq_id
->id
, tq_arg
->name
);
654 spin_lock(&tq_arg
->lock
);
655 tq_arg
->order
[tq_arg
->flag
] = tq_id
->id
;
657 spin_unlock(&tq_arg
->lock
);
661 splat_taskq_test_order(splat_taskq_arg_t
*tq_arg
, int *order
)
665 for (i
= 0; i
< SPLAT_TASKQ_ORDER_MAX
; i
++) {
666 if (tq_arg
->order
[i
] != order
[i
]) {
667 splat_vprint(tq_arg
->file
, tq_arg
->name
,
668 "Taskq '%s' incorrect completion "
669 "order\n", tq_arg
->name
);
670 splat_vprint(tq_arg
->file
, tq_arg
->name
,
671 "%s", "Expected { ");
673 for (j
= 0; j
< SPLAT_TASKQ_ORDER_MAX
; j
++)
674 splat_print(tq_arg
->file
, "%d ", order
[j
]);
676 splat_print(tq_arg
->file
, "%s", "}\n");
677 splat_vprint(tq_arg
->file
, tq_arg
->name
,
680 for (j
= 0; j
< SPLAT_TASKQ_ORDER_MAX
; j
++)
681 splat_print(tq_arg
->file
, "%d ",
684 splat_print(tq_arg
->file
, "%s", "}\n");
689 splat_vprint(tq_arg
->file
, tq_arg
->name
,
690 "Taskq '%s' validated correct completion order\n",
697 splat_taskq_test5_impl(struct file
*file
, void *arg
, boolean_t prealloc
)
701 splat_taskq_id_t tq_id
[SPLAT_TASKQ_ORDER_MAX
];
702 splat_taskq_arg_t tq_arg
;
703 int order1
[SPLAT_TASKQ_ORDER_MAX
] = { 1,2,4,5,3,0,0,0 };
704 int order2
[SPLAT_TASKQ_ORDER_MAX
] = { 1,2,4,5,3,8,6,7 };
708 tqes
= kmem_alloc(sizeof(*tqes
) * SPLAT_TASKQ_ORDER_MAX
, KM_SLEEP
);
709 memset(tqes
, 0, sizeof(*tqes
) * SPLAT_TASKQ_ORDER_MAX
);
711 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
712 "Taskq '%s' creating (%s dispatch)\n",
713 SPLAT_TASKQ_TEST5_NAME
,
714 prealloc
? "prealloc" : "dynamic");
715 if ((tq
= taskq_create(SPLAT_TASKQ_TEST5_NAME
, 3, defclsyspri
,
716 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
717 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
718 "Taskq '%s' create failed\n",
719 SPLAT_TASKQ_TEST5_NAME
);
724 memset(&tq_arg
.order
, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX
);
725 spin_lock_init(&tq_arg
.lock
);
727 tq_arg
.name
= SPLAT_TASKQ_TEST5_NAME
;
729 for (i
= 0; i
< SPLAT_TASKQ_ORDER_MAX
; i
++) {
730 taskq_init_ent(&tqes
[i
]);
733 tq_id
[i
].arg
= &tq_arg
;
736 taskq_dispatch_ent(tq
, splat_taskq_test5_func
,
737 &tq_id
[i
], TQ_SLEEP
, &tqes
[i
]);
738 id
= tqes
[i
].tqent_id
;
740 id
= taskq_dispatch(tq
, splat_taskq_test5_func
,
741 &tq_id
[i
], TQ_SLEEP
);
744 if (id
== TASKQID_INVALID
) {
745 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
746 "Taskq '%s' function '%s' dispatch failed\n",
747 tq_arg
.name
, sym2str(splat_taskq_test5_func
));
752 if (tq_id
[i
].id
!= id
) {
753 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
754 "Taskq '%s' expected taskqid %d got %d\n",
755 tq_arg
.name
, (int)tq_id
[i
].id
, (int)id
);
761 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
, "Taskq '%s' "
762 "waiting for taskqid %d completion\n", tq_arg
.name
, 3);
763 taskq_wait_outstanding(tq
, 3);
764 if ((rc
= splat_taskq_test_order(&tq_arg
, order1
)))
767 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
, "Taskq '%s' "
768 "waiting for taskqid %d completion\n", tq_arg
.name
, 8);
769 taskq_wait_outstanding(tq
, 8);
770 rc
= splat_taskq_test_order(&tq_arg
, order2
);
773 splat_vprint(file
, SPLAT_TASKQ_TEST5_NAME
,
774 "Taskq '%s' destroying\n", tq_arg
.name
);
777 kmem_free(tqes
, sizeof(*tqes
) * SPLAT_TASKQ_ORDER_MAX
);
783 splat_taskq_test5(struct file
*file
, void *arg
)
787 rc
= splat_taskq_test5_impl(file
, arg
, B_FALSE
);
791 rc
= splat_taskq_test5_impl(file
, arg
, B_TRUE
);
797 * Create a single task queue with three threads. Dispatch 8 tasks,
798 * setting TQ_FRONT on only the last three. Sleep after
799 * dispatching tasks 1-3 to ensure they will run and hold the threads
800 * busy while we dispatch the remaining tasks. Verify that tasks 6-8
801 * run before task 4-5.
803 * The following table shows each task id and how they will be
804 * scheduled. Each rows represent one time unit and each column
805 * one of the three worker threads.
807 * NB: The Horizontal Line is the LAST Time unit consumed by the Task,
808 * and must be included in the factor calculation.
827 * 0 +-----+-----+-----+
831 splat_taskq_test6_func(void *arg
)
833 /* Delays determined by above table */
834 static const int factor
[SPLAT_TASKQ_ORDER_MAX
+1] = {0,3,5,7,6,6,5,6,6};
836 splat_taskq_id_t
*tq_id
= (splat_taskq_id_t
*)arg
;
837 splat_taskq_arg_t
*tq_arg
= tq_id
->arg
;
839 splat_vprint(tq_arg
->file
, tq_arg
->name
,
840 "Taskqid %d starting for taskq '%s'\n",
841 tq_id
->id
, tq_arg
->name
);
843 if (tq_id
->id
< SPLAT_TASKQ_ORDER_MAX
+1) {
844 msleep(factor
[tq_id
->id
] * 50);
847 spin_lock(&tq_arg
->lock
);
848 tq_arg
->order
[tq_arg
->flag
] = tq_id
->id
;
850 spin_unlock(&tq_arg
->lock
);
852 splat_vprint(tq_arg
->file
, tq_arg
->name
,
853 "Taskqid %d complete for taskq '%s'\n",
854 tq_id
->id
, tq_arg
->name
);
858 splat_taskq_test6_impl(struct file
*file
, void *arg
, boolean_t prealloc
)
862 splat_taskq_id_t tq_id
[SPLAT_TASKQ_ORDER_MAX
];
863 splat_taskq_arg_t tq_arg
;
864 int order
[SPLAT_TASKQ_ORDER_MAX
] = { 1,2,3,6,7,8,4,5 };
869 tqes
= kmem_alloc(sizeof(*tqes
) * SPLAT_TASKQ_ORDER_MAX
, KM_SLEEP
);
870 memset(tqes
, 0, sizeof(*tqes
) * SPLAT_TASKQ_ORDER_MAX
);
872 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
873 "Taskq '%s' creating (%s dispatch)\n",
874 SPLAT_TASKQ_TEST6_NAME
,
875 prealloc
? "prealloc" : "dynamic");
876 if ((tq
= taskq_create(SPLAT_TASKQ_TEST6_NAME
, 3, defclsyspri
,
877 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
878 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
879 "Taskq '%s' create failed\n",
880 SPLAT_TASKQ_TEST6_NAME
);
885 memset(&tq_arg
.order
, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX
);
886 spin_lock_init(&tq_arg
.lock
);
888 tq_arg
.name
= SPLAT_TASKQ_TEST6_NAME
;
890 for (i
= 0; i
< SPLAT_TASKQ_ORDER_MAX
; i
++) {
891 taskq_init_ent(&tqes
[i
]);
894 tq_id
[i
].arg
= &tq_arg
;
900 taskq_dispatch_ent(tq
, splat_taskq_test6_func
,
901 &tq_id
[i
], tflags
, &tqes
[i
]);
902 id
= tqes
[i
].tqent_id
;
904 id
= taskq_dispatch(tq
, splat_taskq_test6_func
,
908 if (id
== TASKQID_INVALID
) {
909 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
910 "Taskq '%s' function '%s' dispatch failed\n",
911 tq_arg
.name
, sym2str(splat_taskq_test6_func
));
916 if (tq_id
[i
].id
!= id
) {
917 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
918 "Taskq '%s' expected taskqid %d got %d\n",
919 tq_arg
.name
, (int)tq_id
[i
].id
, (int)id
);
923 /* Sleep to let tasks 1-3 start executing. */
928 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
, "Taskq '%s' "
929 "waiting for taskqid %d completion\n", tq_arg
.name
,
930 SPLAT_TASKQ_ORDER_MAX
);
931 taskq_wait_outstanding(tq
, SPLAT_TASKQ_ORDER_MAX
);
932 rc
= splat_taskq_test_order(&tq_arg
, order
);
935 splat_vprint(file
, SPLAT_TASKQ_TEST6_NAME
,
936 "Taskq '%s' destroying\n", tq_arg
.name
);
939 kmem_free(tqes
, sizeof(*tqes
) * SPLAT_TASKQ_ORDER_MAX
);
945 splat_taskq_test6(struct file
*file
, void *arg
)
949 rc
= splat_taskq_test6_impl(file
, arg
, B_FALSE
);
953 rc
= splat_taskq_test6_impl(file
, arg
, B_TRUE
);
959 splat_taskq_test7_func(void *arg
)
961 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
966 if (tq_arg
->depth
>= SPLAT_TASKQ_DEPTH_MAX
)
971 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST7_NAME
,
972 "Taskq '%s' function '%s' dispatching (depth = %u)\n",
973 tq_arg
->name
, sym2str(splat_taskq_test7_func
),
977 VERIFY(taskq_empty_ent(tq_arg
->tqe
));
978 taskq_dispatch_ent(tq_arg
->tq
, splat_taskq_test7_func
,
979 tq_arg
, TQ_SLEEP
, tq_arg
->tqe
);
980 id
= tq_arg
->tqe
->tqent_id
;
982 id
= taskq_dispatch(tq_arg
->tq
, splat_taskq_test7_func
,
986 if (id
== TASKQID_INVALID
) {
987 splat_vprint(tq_arg
->file
, SPLAT_TASKQ_TEST7_NAME
,
988 "Taskq '%s' function '%s' dispatch failed "
989 "(depth = %u)\n", tq_arg
->name
,
990 sym2str(splat_taskq_test7_func
), tq_arg
->depth
);
991 tq_arg
->flag
= -EINVAL
;
997 splat_taskq_test7_impl(struct file
*file
, void *arg
, boolean_t prealloc
)
1000 splat_taskq_arg_t
*tq_arg
;
1004 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
1005 "Taskq '%s' creating (%s dispatch)\n",
1006 SPLAT_TASKQ_TEST7_NAME
,
1007 prealloc
? "prealloc" : "dynamic");
1008 if ((tq
= taskq_create(SPLAT_TASKQ_TEST7_NAME
, 1, defclsyspri
,
1009 50, INT_MAX
, TASKQ_PREPOPULATE
)) == NULL
) {
1010 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
1011 "Taskq '%s' create failed\n",
1012 SPLAT_TASKQ_TEST7_NAME
);
1016 tq_arg
= kmem_alloc(sizeof (splat_taskq_arg_t
), KM_SLEEP
);
1017 tqe
= kmem_alloc(sizeof (taskq_ent_t
), KM_SLEEP
);
1022 tq_arg
->file
= file
;
1023 tq_arg
->name
= SPLAT_TASKQ_TEST7_NAME
;
1027 taskq_init_ent(tqe
);
1033 splat_taskq_test7_func(tq_arg
);
1035 if (tq_arg
->flag
== 0) {
1036 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
1037 "Taskq '%s' waiting\n", tq_arg
->name
);
1038 taskq_wait_outstanding(tq
, SPLAT_TASKQ_DEPTH_MAX
);
1041 error
= (tq_arg
->depth
== SPLAT_TASKQ_DEPTH_MAX
? 0 : -EINVAL
);
1043 splat_vprint(file
, SPLAT_TASKQ_TEST7_NAME
,
1044 "Taskq '%s' destroying\n", tq_arg
->name
);
1046 kmem_free(tqe
, sizeof (taskq_ent_t
));
1047 kmem_free(tq_arg
, sizeof (splat_taskq_arg_t
));
1055 splat_taskq_test7(struct file
*file
, void *arg
)
1059 rc
= splat_taskq_test7_impl(file
, arg
, B_FALSE
);
1063 rc
= splat_taskq_test7_impl(file
, arg
, B_TRUE
);
1069 splat_taskq_throughput_func(void *arg
)
1071 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
1074 atomic_inc(tq_arg
->count
);
1078 splat_taskq_throughput(struct file
*file
, void *arg
, const char *name
,
1079 int nthreads
, int minalloc
, int maxalloc
, int flags
, int tasks
,
1080 struct timespec
*delta
)
1084 splat_taskq_arg_t tq_arg
;
1087 struct timespec start
, stop
;
1090 tqes
= vmalloc(sizeof (*tqes
) * tasks
);
1094 memset(tqes
, 0, sizeof (*tqes
) * tasks
);
1096 splat_vprint(file
, name
, "Taskq '%s' creating (%d/%d/%d/%d)\n",
1097 name
, nthreads
, minalloc
, maxalloc
, tasks
);
1098 if ((tq
= taskq_create(name
, nthreads
, defclsyspri
,
1099 minalloc
, maxalloc
, flags
)) == NULL
) {
1100 splat_vprint(file
, name
, "Taskq '%s' create failed\n", name
);
1107 tq_arg
.count
= &count
;
1108 atomic_set(tq_arg
.count
, 0);
1110 getnstimeofday(&start
);
1112 for (i
= 0; i
< tasks
; i
++) {
1113 tqes
[i
] = kmalloc(sizeof (taskq_ent_t
), GFP_KERNEL
);
1114 if (tqes
[i
] == NULL
) {
1119 taskq_init_ent(tqes
[i
]);
1120 taskq_dispatch_ent(tq
, splat_taskq_throughput_func
,
1121 &tq_arg
, TQ_SLEEP
, tqes
[i
]);
1122 id
= tqes
[i
]->tqent_id
;
1124 if (id
== TASKQID_INVALID
) {
1125 splat_vprint(file
, name
, "Taskq '%s' function '%s' "
1126 "dispatch %d failed\n", tq_arg
.name
,
1127 sym2str(splat_taskq_throughput_func
), i
);
1133 splat_vprint(file
, name
, "Taskq '%s' waiting for %d dispatches\n",
1134 tq_arg
.name
, tasks
);
1138 if (delta
!= NULL
) {
1139 getnstimeofday(&stop
);
1140 *delta
= timespec_sub(stop
, start
);
1143 splat_vprint(file
, name
, "Taskq '%s' %d/%d dispatches finished\n",
1144 tq_arg
.name
, atomic_read(tq_arg
.count
), tasks
);
1146 if (atomic_read(tq_arg
.count
) != tasks
)
1150 splat_vprint(file
, name
, "Taskq '%s' destroying\n", tq_arg
.name
);
1153 for (j
= 0; j
< tasks
&& tqes
[j
] != NULL
; j
++)
1162 * Create a taskq with 100 threads and dispatch a huge number of trivial
1163 * tasks to generate contention on tq->tq_lock. This test should always
1164 * pass. The purpose is to provide a benchmark for measuring the
1165 * effectiveness of taskq optimizations.
1167 #define TEST8_NUM_TASKS 0x20000
1168 #define TEST8_THREADS_PER_TASKQ 100
1171 splat_taskq_test8(struct file
*file
, void *arg
)
1173 return (splat_taskq_throughput(file
, arg
,
1174 SPLAT_TASKQ_TEST8_NAME
, TEST8_THREADS_PER_TASKQ
,
1175 1, INT_MAX
, TASKQ_PREPOPULATE
, TEST8_NUM_TASKS
, NULL
));
1179 * Create a taskq and dispatch a number of delayed tasks to the queue.
1180 * For each task verify that it was run no early than requested.
1183 splat_taskq_test9_func(void *arg
)
1185 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
1188 if (ddi_time_after_eq(ddi_get_lbolt(), tq_arg
->expire
))
1189 atomic_inc(tq_arg
->count
);
1191 kmem_free(tq_arg
, sizeof(splat_taskq_arg_t
));
1195 splat_taskq_test9(struct file
*file
, void *arg
)
1204 splat_vprint(file
, SPLAT_TASKQ_TEST9_NAME
,
1205 "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
1206 SPLAT_TASKQ_TEST9_NAME
, "delay", minalloc
, maxalloc
, nr_tasks
);
1207 if ((tq
= taskq_create(SPLAT_TASKQ_TEST9_NAME
, 3, defclsyspri
,
1208 minalloc
, maxalloc
, TASKQ_PREPOPULATE
)) == NULL
) {
1209 splat_vprint(file
, SPLAT_TASKQ_TEST9_NAME
,
1210 "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST9_NAME
);
1214 atomic_set(&count
, 0);
1216 for (i
= 1; i
<= nr_tasks
; i
++) {
1217 splat_taskq_arg_t
*tq_arg
;
1221 /* A random timeout in jiffies of at most 5 seconds */
1222 get_random_bytes((void *)&rnd
, 4);
1223 rnd
= rnd
% (5 * HZ
);
1225 tq_arg
= kmem_alloc(sizeof(splat_taskq_arg_t
), KM_SLEEP
);
1226 tq_arg
->file
= file
;
1227 tq_arg
->name
= SPLAT_TASKQ_TEST9_NAME
;
1228 tq_arg
->expire
= ddi_get_lbolt() + rnd
;
1229 tq_arg
->count
= &count
;
1231 splat_vprint(file
, SPLAT_TASKQ_TEST9_NAME
,
1232 "Taskq '%s' delay dispatch %u jiffies\n",
1233 SPLAT_TASKQ_TEST9_NAME
, rnd
);
1235 id
= taskq_dispatch_delay(tq
, splat_taskq_test9_func
,
1236 tq_arg
, TQ_SLEEP
, ddi_get_lbolt() + rnd
);
1238 if (id
== TASKQID_INVALID
) {
1239 splat_vprint(file
, SPLAT_TASKQ_TEST9_NAME
,
1240 "Taskq '%s' delay dispatch failed\n",
1241 SPLAT_TASKQ_TEST9_NAME
);
1242 kmem_free(tq_arg
, sizeof(splat_taskq_arg_t
));
1249 splat_vprint(file
, SPLAT_TASKQ_TEST9_NAME
, "Taskq '%s' waiting for "
1250 "%d delay dispatches\n", SPLAT_TASKQ_TEST9_NAME
, nr_tasks
);
1253 if (atomic_read(&count
) != nr_tasks
)
1256 splat_vprint(file
, SPLAT_TASKQ_TEST9_NAME
, "Taskq '%s' %d/%d delay "
1257 "dispatches finished on time\n", SPLAT_TASKQ_TEST9_NAME
,
1258 atomic_read(&count
), nr_tasks
);
1259 splat_vprint(file
, SPLAT_TASKQ_TEST9_NAME
, "Taskq '%s' destroying\n",
1260 SPLAT_TASKQ_TEST9_NAME
);
1268 * Create a taskq and dispatch then cancel tasks in the queue.
1271 splat_taskq_test10_func(void *arg
)
1273 splat_taskq_arg_t
*tq_arg
= (splat_taskq_arg_t
*)arg
;
1276 if (ddi_time_after_eq(ddi_get_lbolt(), tq_arg
->expire
))
1277 atomic_inc(tq_arg
->count
);
1279 /* Randomly sleep to further perturb the system */
1280 get_random_bytes((void *)&rnd
, 1);
1281 msleep(1 + (rnd
% 9));
1285 splat_taskq_test10(struct file
*file
, void *arg
)
1288 splat_taskq_arg_t
**tqas
;
1297 clock_t start
, cancel
;
1299 tqas
= vmalloc(sizeof(*tqas
) * nr_tasks
);
1302 memset(tqas
, 0, sizeof(*tqas
) * nr_tasks
);
1304 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
,
1305 "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
1306 SPLAT_TASKQ_TEST10_NAME
, "delay", minalloc
, maxalloc
, nr_tasks
);
1307 if ((tq
= taskq_create(SPLAT_TASKQ_TEST10_NAME
, 3, defclsyspri
,
1308 minalloc
, maxalloc
, TASKQ_PREPOPULATE
)) == NULL
) {
1309 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
,
1310 "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST10_NAME
);
1315 atomic_set(&count
, 0);
1317 for (i
= 0; i
< nr_tasks
; i
++) {
1318 splat_taskq_arg_t
*tq_arg
;
1321 /* A random timeout in jiffies of at most 5 seconds */
1322 get_random_bytes((void *)&rnd
, 4);
1323 rnd
= rnd
% (5 * HZ
);
1325 tq_arg
= kmem_alloc(sizeof(splat_taskq_arg_t
), KM_SLEEP
);
1326 tq_arg
->file
= file
;
1327 tq_arg
->name
= SPLAT_TASKQ_TEST10_NAME
;
1328 tq_arg
->count
= &count
;
1332 * Dispatch every 1/3 one immediately to mix it up, the cancel
1333 * code is inherently racy and we want to try and provoke any
1334 * subtle concurrently issues.
1337 tq_arg
->expire
= ddi_get_lbolt();
1338 tq_arg
->id
= taskq_dispatch(tq
, splat_taskq_test10_func
,
1341 tq_arg
->expire
= ddi_get_lbolt() + rnd
;
1342 tq_arg
->id
= taskq_dispatch_delay(tq
,
1343 splat_taskq_test10_func
,
1344 tq_arg
, TQ_SLEEP
, ddi_get_lbolt() + rnd
);
1347 if (tq_arg
->id
== TASKQID_INVALID
) {
1348 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
,
1349 "Taskq '%s' dispatch failed\n",
1350 SPLAT_TASKQ_TEST10_NAME
);
1351 kmem_free(tq_arg
, sizeof(splat_taskq_arg_t
));
1356 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
,
1357 "Taskq '%s' dispatch %lu in %lu jiffies\n",
1358 SPLAT_TASKQ_TEST10_NAME
, (unsigned long)tq_arg
->id
,
1359 !(i
% 3) ? 0 : tq_arg
->expire
- ddi_get_lbolt());
1364 * Start randomly canceling tasks for the duration of the test. We
1365 * happen to know the valid task id's will be in the range 1..nr_tasks
1366 * because the taskq is private and was just created. However, we
1367 * have no idea of a particular task has already executed or not.
1369 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
, "Taskq '%s' randomly "
1370 "canceling task ids\n", SPLAT_TASKQ_TEST10_NAME
);
1372 start
= ddi_get_lbolt();
1375 while (ddi_time_before(ddi_get_lbolt(), start
+ 5 * HZ
)) {
1380 cancel
= ddi_get_lbolt();
1381 get_random_bytes((void *)&rnd
, 4);
1382 id
= 1 + (rnd
% nr_tasks
);
1383 rc
= taskq_cancel_id(tq
, id
);
1386 * Keep track of the results of the random cancels.
1390 } else if (rc
== ENOENT
) {
1392 } else if (rc
== EBUSY
) {
1400 * Verify we never get blocked to long in taskq_cancel_id().
1401 * The worst case is 10ms if we happen to cancel the task
1402 * which is currently executing. We allow a factor of 2x.
1404 if (ddi_get_lbolt() - cancel
> HZ
/ 50) {
1405 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
,
1406 "Taskq '%s' cancel for %lu took %lu\n",
1407 SPLAT_TASKQ_TEST10_NAME
, (unsigned long)id
,
1408 ddi_get_lbolt() - cancel
);
1413 get_random_bytes((void *)&rnd
, 4);
1414 msleep(1 + (rnd
% 100));
1421 * Cross check the results of taskq_cancel_id() with the number of
1422 * times the dispatched function actually ran successfully.
1424 if ((rc
== 0) && (nr_tasks
- canceled
!= atomic_read(&count
)))
1427 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
, "Taskq '%s' %d attempts, "
1428 "%d canceled, %d completed, %d blocked, %d/%d tasks run\n",
1429 SPLAT_TASKQ_TEST10_NAME
, i
, canceled
, completed
, blocked
,
1430 atomic_read(&count
), nr_tasks
);
1431 splat_vprint(file
, SPLAT_TASKQ_TEST10_NAME
, "Taskq '%s' destroying %d\n",
1432 SPLAT_TASKQ_TEST10_NAME
, rc
);
1436 for (j
= 0; j
< nr_tasks
&& tqas
[j
] != NULL
; j
++)
1437 kmem_free(tqas
[j
], sizeof(splat_taskq_arg_t
));
1444 * Create a dynamic taskq with 100 threads and dispatch a huge number of
1445 * trivial tasks. This will cause the taskq to grow quickly to its max
1446 * thread count. This test should always pass. The purpose is to provide
1447 * a benchmark for measuring the performance of dynamic taskqs.
1449 #define TEST11_NUM_TASKS 100000
1450 #define TEST11_THREADS_PER_TASKQ 100
1453 splat_taskq_test11(struct file
*file
, void *arg
)
1455 struct timespec normal
, dynamic
;
1458 error
= splat_taskq_throughput(file
, arg
, SPLAT_TASKQ_TEST11_NAME
,
1459 TEST11_THREADS_PER_TASKQ
, 1, INT_MAX
,
1460 TASKQ_PREPOPULATE
, TEST11_NUM_TASKS
, &normal
);
1464 error
= splat_taskq_throughput(file
, arg
, SPLAT_TASKQ_TEST11_NAME
,
1465 TEST11_THREADS_PER_TASKQ
, 1, INT_MAX
,
1466 TASKQ_PREPOPULATE
| TASKQ_DYNAMIC
, TEST11_NUM_TASKS
, &dynamic
);
1470 splat_vprint(file
, SPLAT_TASKQ_TEST11_NAME
,
1471 "Timing taskq_wait(): normal=%ld.%09lds, dynamic=%ld.%09lds\n",
1472 normal
.tv_sec
, normal
.tv_nsec
,
1473 dynamic
.tv_sec
, dynamic
.tv_nsec
);
1475 /* A 10x increase in runtime is used to indicate a core problem. */
1476 if (((int64_t)dynamic
.tv_sec
* NANOSEC
+ (int64_t)dynamic
.tv_nsec
) >
1477 (((int64_t)normal
.tv_sec
* NANOSEC
+ (int64_t)normal
.tv_nsec
) * 10))
1484 splat_taskq_init(void)
1486 splat_subsystem_t
*sub
;
1488 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
1492 memset(sub
, 0, sizeof(*sub
));
1493 strncpy(sub
->desc
.name
, SPLAT_TASKQ_NAME
, SPLAT_NAME_SIZE
);
1494 strncpy(sub
->desc
.desc
, SPLAT_TASKQ_DESC
, SPLAT_DESC_SIZE
);
1495 INIT_LIST_HEAD(&sub
->subsystem_list
);
1496 INIT_LIST_HEAD(&sub
->test_list
);
1497 spin_lock_init(&sub
->test_lock
);
1498 sub
->desc
.id
= SPLAT_SUBSYSTEM_TASKQ
;
1500 splat_test_init(sub
, SPLAT_TASKQ_TEST1_NAME
, SPLAT_TASKQ_TEST1_DESC
,
1501 SPLAT_TASKQ_TEST1_ID
, splat_taskq_test1
);
1502 splat_test_init(sub
, SPLAT_TASKQ_TEST2_NAME
, SPLAT_TASKQ_TEST2_DESC
,
1503 SPLAT_TASKQ_TEST2_ID
, splat_taskq_test2
);
1504 splat_test_init(sub
, SPLAT_TASKQ_TEST3_NAME
, SPLAT_TASKQ_TEST3_DESC
,
1505 SPLAT_TASKQ_TEST3_ID
, splat_taskq_test3
);
1506 splat_test_init(sub
, SPLAT_TASKQ_TEST4_NAME
, SPLAT_TASKQ_TEST4_DESC
,
1507 SPLAT_TASKQ_TEST4_ID
, splat_taskq_test4
);
1508 splat_test_init(sub
, SPLAT_TASKQ_TEST5_NAME
, SPLAT_TASKQ_TEST5_DESC
,
1509 SPLAT_TASKQ_TEST5_ID
, splat_taskq_test5
);
1510 splat_test_init(sub
, SPLAT_TASKQ_TEST6_NAME
, SPLAT_TASKQ_TEST6_DESC
,
1511 SPLAT_TASKQ_TEST6_ID
, splat_taskq_test6
);
1512 splat_test_init(sub
, SPLAT_TASKQ_TEST7_NAME
, SPLAT_TASKQ_TEST7_DESC
,
1513 SPLAT_TASKQ_TEST7_ID
, splat_taskq_test7
);
1514 splat_test_init(sub
, SPLAT_TASKQ_TEST8_NAME
, SPLAT_TASKQ_TEST8_DESC
,
1515 SPLAT_TASKQ_TEST8_ID
, splat_taskq_test8
);
1516 splat_test_init(sub
, SPLAT_TASKQ_TEST9_NAME
, SPLAT_TASKQ_TEST9_DESC
,
1517 SPLAT_TASKQ_TEST9_ID
, splat_taskq_test9
);
1518 splat_test_init(sub
, SPLAT_TASKQ_TEST10_NAME
, SPLAT_TASKQ_TEST10_DESC
,
1519 SPLAT_TASKQ_TEST10_ID
, splat_taskq_test10
);
1520 splat_test_init(sub
, SPLAT_TASKQ_TEST11_NAME
, SPLAT_TASKQ_TEST11_DESC
,
1521 SPLAT_TASKQ_TEST11_ID
, splat_taskq_test11
);
1527 splat_taskq_fini(splat_subsystem_t
*sub
)
1530 splat_test_fini(sub
, SPLAT_TASKQ_TEST11_ID
);
1531 splat_test_fini(sub
, SPLAT_TASKQ_TEST10_ID
);
1532 splat_test_fini(sub
, SPLAT_TASKQ_TEST9_ID
);
1533 splat_test_fini(sub
, SPLAT_TASKQ_TEST8_ID
);
1534 splat_test_fini(sub
, SPLAT_TASKQ_TEST7_ID
);
1535 splat_test_fini(sub
, SPLAT_TASKQ_TEST6_ID
);
1536 splat_test_fini(sub
, SPLAT_TASKQ_TEST5_ID
);
1537 splat_test_fini(sub
, SPLAT_TASKQ_TEST4_ID
);
1538 splat_test_fini(sub
, SPLAT_TASKQ_TEST3_ID
);
1539 splat_test_fini(sub
, SPLAT_TASKQ_TEST2_ID
);
1540 splat_test_fini(sub
, SPLAT_TASKQ_TEST1_ID
);
1546 splat_taskq_id(void) {
1547 return SPLAT_SUBSYSTEM_TASKQ
;