Skip to content

Commit

Permalink
spl-taskq: summary stats for all taskqs
Browse files Browse the repository at this point in the history
This adds /proc/spl/kstats/taskq/summary, which attempts to show a
useful subset of stats for all taskqs in the system.

Sponsored-by: Klara, Inc.
Sponsored-by: Syneto
Signed-off-by: Rob Norris <[email protected]>
  • Loading branch information
robn committed Jul 26, 2024
1 parent cdfda46 commit e377fc6
Showing 1 changed file with 108 additions and 0 deletions.
108 changes: 108 additions & 0 deletions module/os/linux/spl/spl-taskq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,110 @@ taskq_create_synced(const char *name, int nthreads, pri_t pri,
}
EXPORT_SYMBOL(taskq_create_synced);

static kstat_t *taskq_summary_ksp = NULL;

static int
spl_taskq_kstat_headers(char *buf, size_t size)
{
size_t n = snprintf(buf, size,
"%-20s | %-17s | %-23s | %-32s\n"
"%-20s | %-17s | %-23s | %-32s\n"
"%-20s | %-17s | %-23s | %-32s\n",
"", "threads (current)", "task on queue (current)",
"task time (µs) (last 100 tasks)",
"taskq name", "tot [act idl] max", " pend [ norm high] dly",
"avg [enq wait deq exec]",
"--------------------", "-----------------",
"-----------------------", "--------------------------------");
return (n >= size ? ENOMEM : 0);
}

static int
spl_taskq_kstat_data(char *buf, size_t size, void *data)
{
struct list_head *tql = NULL;
taskq_t *tq;
char name[21];
char threads[25];
char tasks[30];
char times[40];
size_t n;
int err = 0;

down_read(&tq_list_sem);
list_for_each_prev(tql, &tq_list) {
tq = list_entry(tql, taskq_t, tq_taskqs);

mutex_enter(tq->tq_ksp->ks_lock);
taskq_kstats_update(tq->tq_ksp, KSTAT_READ);
taskq_kstats_t *tqks = tq->tq_ksp->ks_data;

snprintf(name, sizeof (name), "%s.%d", tq->tq_name,
tq->tq_instance);
snprintf(threads, sizeof (threads), "%3llu [%3llu %3llu] %3llu",
tqks->tqks_threads_total.value.ui64,
tqks->tqks_threads_active.value.ui64,
tqks->tqks_threads_idle.value.ui64,
tqks->tqks_threads_max.value.ui64);
snprintf(tasks, sizeof (tasks), "%5llu [%5llu %5llu] %3llu",
tqks->tqks_tasks_total.value.ui64,
tqks->tqks_tasks_pending.value.ui64,
tqks->tqks_tasks_priority.value.ui64,
tqks->tqks_tasks_delayed.value.ui64);
snprintf(times, sizeof (times),
"%6llu [%4llu %6llu %4llu %6llu]",
tqks->tqks_time[TQ_TIME_TASK].tqtks_ewma_100.value.ui64,
tqks->tqks_time[TQ_TIME_ENQUEUE].tqtks_ewma_100.value.ui64,
tqks->tqks_time[TQ_TIME_WAIT].tqtks_ewma_100.value.ui64,
tqks->tqks_time[TQ_TIME_DEQUEUE].tqtks_ewma_100.value.ui64,
tqks->tqks_time[TQ_TIME_EXECUTE].tqtks_ewma_100.value.ui64);

mutex_exit(tq->tq_ksp->ks_lock);

n = snprintf(buf, size, "%-20s | %-17s | %-23s | %-32s\n",
name, threads, tasks, times);
if (n >= size) {
err = ENOMEM;
break;
}

buf = &buf[n];
size -= n;
}

up_read(&tq_list_sem);

return (err);
}

static void
spl_taskq_kstat_init(void)
{
kstat_t *ksp = kstat_create("taskq", 0, "summary", "misc",
KSTAT_TYPE_RAW, 0, KSTAT_FLAG_VIRTUAL);

if (ksp == NULL)
return;

ksp->ks_data = (void *)(uintptr_t)1;
ksp->ks_ndata = 1;
kstat_set_raw_ops(ksp, spl_taskq_kstat_headers,
spl_taskq_kstat_data, NULL);
kstat_install(ksp);

taskq_summary_ksp = ksp;
}

static void
spl_taskq_kstat_fini(void)
{
if (taskq_summary_ksp == NULL)
return;

kstat_delete(taskq_summary_ksp);
taskq_summary_ksp = NULL;
}

static unsigned int spl_taskq_kick = 0;

/*
Expand Down Expand Up @@ -1900,12 +2004,16 @@ spl_taskq_init(void)
*/
dynamic_taskq->tq_lock_class = TQ_LOCK_DYNAMIC;

spl_taskq_kstat_init();

return (0);
}

void
spl_taskq_fini(void)
{
spl_taskq_kstat_fini();

taskq_destroy(dynamic_taskq);
dynamic_taskq = NULL;

Expand Down

0 comments on commit e377fc6

Please sign in to comment.