mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2025-01-13 03:30:34 +03:00
splat taskq:delay: Add test case
Add a test case for taskq_dispatch_delay() to verify it is working properly. The test dispatchs 100 tasks to a taskq with random expiration times spread over 5 seconds. As each task expires and gets executed by a worker thread it verifies that it was run at the correct time. Once all the delayed tasks have been executed we double check that all the dispatched tasks were successful. Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
parent
d9acd930b5
commit
2f35782620
@ -25,6 +25,7 @@
|
|||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
#include <sys/taskq.h>
|
#include <sys/taskq.h>
|
||||||
|
#include <sys/random.h>
|
||||||
#include <sys/kmem.h>
|
#include <sys/kmem.h>
|
||||||
#include "splat-internal.h"
|
#include "splat-internal.h"
|
||||||
|
|
||||||
@ -63,6 +64,10 @@
|
|||||||
#define SPLAT_TASKQ_TEST8_NAME "contention"
|
#define SPLAT_TASKQ_TEST8_NAME "contention"
|
||||||
#define SPLAT_TASKQ_TEST8_DESC "1 queue, 100 threads, 131072 tasks"
|
#define SPLAT_TASKQ_TEST8_DESC "1 queue, 100 threads, 131072 tasks"
|
||||||
|
|
||||||
|
#define SPLAT_TASKQ_TEST9_ID 0x0209
|
||||||
|
#define SPLAT_TASKQ_TEST9_NAME "delay"
|
||||||
|
#define SPLAT_TASKQ_TEST9_DESC "Delayed task execution"
|
||||||
|
|
||||||
#define SPLAT_TASKQ_ORDER_MAX 8
|
#define SPLAT_TASKQ_ORDER_MAX 8
|
||||||
#define SPLAT_TASKQ_DEPTH_MAX 16
|
#define SPLAT_TASKQ_DEPTH_MAX 16
|
||||||
|
|
||||||
@ -70,9 +75,10 @@
|
|||||||
typedef struct splat_taskq_arg {
|
typedef struct splat_taskq_arg {
|
||||||
int flag;
|
int flag;
|
||||||
int id;
|
int id;
|
||||||
atomic_t count;
|
atomic_t *count;
|
||||||
int order[SPLAT_TASKQ_ORDER_MAX];
|
int order[SPLAT_TASKQ_ORDER_MAX];
|
||||||
unsigned int depth;
|
unsigned int depth;
|
||||||
|
unsigned long expire;
|
||||||
taskq_t *tq;
|
taskq_t *tq;
|
||||||
taskq_ent_t *tqe;
|
taskq_ent_t *tqe;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
@ -415,8 +421,8 @@ splat_taskq_test3(struct file *file, void *arg)
|
|||||||
/*
|
/*
|
||||||
* Create a taskq and dispatch a large number of tasks to the queue.
|
* Create a taskq and dispatch a large number of tasks to the queue.
|
||||||
* Then use taskq_wait() to block until all the tasks complete, then
|
* Then use taskq_wait() to block until all the tasks complete, then
|
||||||
* cross check that all the tasks ran by checking tg_arg->count which
|
* cross check that all the tasks ran by checking the shared atomic
|
||||||
* is incremented in the task function. Finally cleanup the taskq.
|
* counter which is incremented in the task function.
|
||||||
*
|
*
|
||||||
* First we try with a large 'maxalloc' value, then we try with a small one.
|
* First we try with a large 'maxalloc' value, then we try with a small one.
|
||||||
* We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
|
* We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
|
||||||
@ -428,7 +434,7 @@ splat_taskq_test4_func(void *arg)
|
|||||||
splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
|
splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
|
||||||
ASSERT(tq_arg);
|
ASSERT(tq_arg);
|
||||||
|
|
||||||
atomic_inc(&tq_arg->count);
|
atomic_inc(tq_arg->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -439,6 +445,7 @@ splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
|
|||||||
taskqid_t id;
|
taskqid_t id;
|
||||||
splat_taskq_arg_t tq_arg;
|
splat_taskq_arg_t tq_arg;
|
||||||
taskq_ent_t *tqes;
|
taskq_ent_t *tqes;
|
||||||
|
atomic_t count;
|
||||||
int i, j, rc = 0;
|
int i, j, rc = 0;
|
||||||
|
|
||||||
tqes = kmalloc(sizeof(*tqes) * nr_tasks, GFP_KERNEL);
|
tqes = kmalloc(sizeof(*tqes) * nr_tasks, GFP_KERNEL);
|
||||||
@ -461,9 +468,10 @@ splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
|
|||||||
|
|
||||||
tq_arg.file = file;
|
tq_arg.file = file;
|
||||||
tq_arg.name = SPLAT_TASKQ_TEST4_NAME;
|
tq_arg.name = SPLAT_TASKQ_TEST4_NAME;
|
||||||
|
tq_arg.count = &count;
|
||||||
|
|
||||||
for (i = 1; i <= nr_tasks; i *= 2) {
|
for (i = 1; i <= nr_tasks; i *= 2) {
|
||||||
atomic_set(&tq_arg.count, 0);
|
atomic_set(tq_arg.count, 0);
|
||||||
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
|
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
|
||||||
"Taskq '%s' function '%s' dispatched %d times\n",
|
"Taskq '%s' function '%s' dispatched %d times\n",
|
||||||
tq_arg.name, sym2str(splat_taskq_test4_func), i);
|
tq_arg.name, sym2str(splat_taskq_test4_func), i);
|
||||||
@ -495,8 +503,8 @@ splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
|
|||||||
taskq_wait(tq);
|
taskq_wait(tq);
|
||||||
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
|
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
|
||||||
"%d/%d dispatches finished\n", tq_arg.name,
|
"%d/%d dispatches finished\n", tq_arg.name,
|
||||||
atomic_read(&tq_arg.count), i);
|
atomic_read(&count), i);
|
||||||
if (atomic_read(&tq_arg.count) != i) {
|
if (atomic_read(&count) != i) {
|
||||||
rc = -ERANGE;
|
rc = -ERANGE;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -1011,7 +1019,7 @@ splat_taskq_test8_func(void *arg)
|
|||||||
splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
|
splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
|
||||||
ASSERT(tq_arg);
|
ASSERT(tq_arg);
|
||||||
|
|
||||||
atomic_inc(&tq_arg->count);
|
atomic_inc(tq_arg->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEST8_NUM_TASKS 0x20000
|
#define TEST8_NUM_TASKS 0x20000
|
||||||
@ -1025,6 +1033,7 @@ splat_taskq_test8_common(struct file *file, void *arg, int minalloc,
|
|||||||
taskqid_t id;
|
taskqid_t id;
|
||||||
splat_taskq_arg_t tq_arg;
|
splat_taskq_arg_t tq_arg;
|
||||||
taskq_ent_t **tqes;
|
taskq_ent_t **tqes;
|
||||||
|
atomic_t count;
|
||||||
int i, j, rc = 0;
|
int i, j, rc = 0;
|
||||||
|
|
||||||
tqes = vmalloc(sizeof(*tqes) * TEST8_NUM_TASKS);
|
tqes = vmalloc(sizeof(*tqes) * TEST8_NUM_TASKS);
|
||||||
@ -1048,8 +1057,9 @@ splat_taskq_test8_common(struct file *file, void *arg, int minalloc,
|
|||||||
|
|
||||||
tq_arg.file = file;
|
tq_arg.file = file;
|
||||||
tq_arg.name = SPLAT_TASKQ_TEST8_NAME;
|
tq_arg.name = SPLAT_TASKQ_TEST8_NAME;
|
||||||
|
tq_arg.count = &count;
|
||||||
|
atomic_set(tq_arg.count, 0);
|
||||||
|
|
||||||
atomic_set(&tq_arg.count, 0);
|
|
||||||
for (i = 0; i < TEST8_NUM_TASKS; i++) {
|
for (i = 0; i < TEST8_NUM_TASKS; i++) {
|
||||||
tqes[i] = kmalloc(sizeof(taskq_ent_t), GFP_KERNEL);
|
tqes[i] = kmalloc(sizeof(taskq_ent_t), GFP_KERNEL);
|
||||||
if (tqes[i] == NULL) {
|
if (tqes[i] == NULL) {
|
||||||
@ -1079,9 +1089,9 @@ splat_taskq_test8_common(struct file *file, void *arg, int minalloc,
|
|||||||
taskq_wait(tq);
|
taskq_wait(tq);
|
||||||
splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' "
|
splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' "
|
||||||
"%d/%d dispatches finished\n", tq_arg.name,
|
"%d/%d dispatches finished\n", tq_arg.name,
|
||||||
atomic_read(&tq_arg.count), TEST8_NUM_TASKS);
|
atomic_read(tq_arg.count), TEST8_NUM_TASKS);
|
||||||
|
|
||||||
if (atomic_read(&tq_arg.count) != TEST8_NUM_TASKS)
|
if (atomic_read(tq_arg.count) != TEST8_NUM_TASKS)
|
||||||
rc = -ERANGE;
|
rc = -ERANGE;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -1106,6 +1116,95 @@ splat_taskq_test8(struct file *file, void *arg)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a taskq and dispatch a number of delayed tasks to the queue.
|
||||||
|
* For each task verify that it was run no early than requested.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
splat_taskq_test9_func(void *arg)
|
||||||
|
{
|
||||||
|
splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
|
||||||
|
ASSERT(tq_arg);
|
||||||
|
|
||||||
|
if (ddi_get_lbolt() >= tq_arg->expire)
|
||||||
|
atomic_inc(tq_arg->count);
|
||||||
|
|
||||||
|
kmem_free(tq_arg, sizeof(splat_taskq_arg_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
splat_taskq_test9(struct file *file, void *arg)
|
||||||
|
{
|
||||||
|
taskq_t *tq;
|
||||||
|
atomic_t count;
|
||||||
|
int i, rc = 0;
|
||||||
|
int minalloc = 1;
|
||||||
|
int maxalloc = 10;
|
||||||
|
int nr_tasks = 100;
|
||||||
|
|
||||||
|
splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
|
||||||
|
"Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n",
|
||||||
|
SPLAT_TASKQ_TEST9_NAME, "delay", minalloc, maxalloc, nr_tasks);
|
||||||
|
if ((tq = taskq_create(SPLAT_TASKQ_TEST9_NAME, 3, maxclsyspri,
|
||||||
|
minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
|
||||||
|
splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
|
||||||
|
"Taskq '%s' create failed\n", SPLAT_TASKQ_TEST9_NAME);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_set(&count, 0);
|
||||||
|
|
||||||
|
for (i = 1; i <= nr_tasks; i++) {
|
||||||
|
splat_taskq_arg_t *tq_arg;
|
||||||
|
taskqid_t id;
|
||||||
|
uint32_t rnd;
|
||||||
|
|
||||||
|
/* A random timeout in jiffies of at most 5 seconds */
|
||||||
|
get_random_bytes((void *)&rnd, 4);
|
||||||
|
rnd = rnd % (5 * HZ);
|
||||||
|
|
||||||
|
tq_arg = kmem_alloc(sizeof(splat_taskq_arg_t), KM_SLEEP);
|
||||||
|
tq_arg->file = file;
|
||||||
|
tq_arg->name = SPLAT_TASKQ_TEST9_NAME;
|
||||||
|
tq_arg->expire = ddi_get_lbolt() + rnd;
|
||||||
|
tq_arg->count = &count;
|
||||||
|
|
||||||
|
splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
|
||||||
|
"Taskq '%s' delay dispatch %u jiffies\n",
|
||||||
|
SPLAT_TASKQ_TEST9_NAME, rnd);
|
||||||
|
|
||||||
|
id = taskq_dispatch_delay(tq, splat_taskq_test9_func,
|
||||||
|
tq_arg, TQ_SLEEP, ddi_get_lbolt() + rnd);
|
||||||
|
|
||||||
|
if (id == 0) {
|
||||||
|
splat_vprint(file, SPLAT_TASKQ_TEST9_NAME,
|
||||||
|
"Taskq '%s' delay dispatch failed\n",
|
||||||
|
SPLAT_TASKQ_TEST9_NAME);
|
||||||
|
kmem_free(tq_arg, sizeof(splat_taskq_arg_t));
|
||||||
|
taskq_wait(tq);
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' waiting for "
|
||||||
|
"%d delay dispatches\n", SPLAT_TASKQ_TEST9_NAME, nr_tasks);
|
||||||
|
|
||||||
|
taskq_wait(tq);
|
||||||
|
if (atomic_read(&count) != nr_tasks)
|
||||||
|
rc = -ERANGE;
|
||||||
|
|
||||||
|
splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' %d/%d delay "
|
||||||
|
"dispatches finished on time\n", SPLAT_TASKQ_TEST9_NAME,
|
||||||
|
atomic_read(&count), nr_tasks);
|
||||||
|
splat_vprint(file, SPLAT_TASKQ_TEST9_NAME, "Taskq '%s' destroying\n",
|
||||||
|
SPLAT_TASKQ_TEST9_NAME);
|
||||||
|
out:
|
||||||
|
taskq_destroy(tq);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
splat_subsystem_t *
|
splat_subsystem_t *
|
||||||
splat_taskq_init(void)
|
splat_taskq_init(void)
|
||||||
{
|
{
|
||||||
@ -1139,6 +1238,8 @@ splat_taskq_init(void)
|
|||||||
SPLAT_TASKQ_TEST7_ID, splat_taskq_test7);
|
SPLAT_TASKQ_TEST7_ID, splat_taskq_test7);
|
||||||
SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST8_NAME, SPLAT_TASKQ_TEST8_DESC,
|
SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST8_NAME, SPLAT_TASKQ_TEST8_DESC,
|
||||||
SPLAT_TASKQ_TEST8_ID, splat_taskq_test8);
|
SPLAT_TASKQ_TEST8_ID, splat_taskq_test8);
|
||||||
|
SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST9_NAME, SPLAT_TASKQ_TEST9_DESC,
|
||||||
|
SPLAT_TASKQ_TEST9_ID, splat_taskq_test9);
|
||||||
|
|
||||||
return sub;
|
return sub;
|
||||||
}
|
}
|
||||||
@ -1147,6 +1248,7 @@ void
|
|||||||
splat_taskq_fini(splat_subsystem_t *sub)
|
splat_taskq_fini(splat_subsystem_t *sub)
|
||||||
{
|
{
|
||||||
ASSERT(sub);
|
ASSERT(sub);
|
||||||
|
SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST9_ID);
|
||||||
SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST8_ID);
|
SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST8_ID);
|
||||||
SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST7_ID);
|
SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST7_ID);
|
||||||
SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST6_ID);
|
SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST6_ID);
|
||||||
|
Loading…
Reference in New Issue
Block a user