Module Name: src
Committed By: riastradh
Date: Sun Feb 9 22:57:39 UTC 2020
Modified Files:
src/sys/kern: kern_threadpool.c
Log Message:
Switch from ad-hoc logging to dtrace probes.
To generate a diff of this commit:
cvs rdiff -u -r1.16 -r1.17 src/sys/kern/kern_threadpool.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/kern_threadpool.c
diff -u src/sys/kern/kern_threadpool.c:1.16 src/sys/kern/kern_threadpool.c:1.17
--- src/sys/kern/kern_threadpool.c:1.16 Sun Feb 9 22:57:26 2020
+++ src/sys/kern/kern_threadpool.c Sun Feb 9 22:57:39 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_threadpool.c,v 1.16 2020/02/09 22:57:26 riastradh Exp $ */
+/* $NetBSD: kern_threadpool.c,v 1.17 2020/02/09 22:57:39 riastradh Exp $ */
/*-
* Copyright (c) 2014, 2018 The NetBSD Foundation, Inc.
@@ -81,7 +81,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_threadpool.c,v 1.16 2020/02/09 22:57:26 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_threadpool.c,v 1.17 2020/02/09 22:57:39 riastradh Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -97,10 +97,82 @@ __KERNEL_RCSID(0, "$NetBSD: kern_threadp
#include <sys/pool.h>
#include <sys/proc.h>
#include <sys/queue.h>
-#include <sys/systm.h>
+#include <sys/sdt.h>
#include <sys/sysctl.h>
+#include <sys/systm.h>
#include <sys/threadpool.h>
+/* Probes */
+
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, get,
+ "pri_t"/*pri*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, get__create,
+ "pri_t"/*pri*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, get__race,
+ "pri_t"/*pri*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, put,
+ "struct threadpool *"/*pool*/, "pri_t"/*pri*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, put__destroy,
+ "struct threadpool *"/*pool*/, "pri_t"/*pri*/);
+
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, percpu__get,
+ "pri_t"/*pri*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, percpu__get__create,
+ "pri_t"/*pri*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, percpu__get__race,
+ "pri_t"/*pri*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, percpu__put,
+ "struct threadpool *"/*pool*/, "pri_t"/*pri*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, percpu__put__destroy,
+ "struct threadpool *"/*pool*/, "pri_t"/*pri*/);
+
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, create,
+ "struct cpu_info *"/*ci*/, "pri_t"/*pri*/);
+SDT_PROBE_DEFINE3(sdt, kernel, threadpool, create__success,
+ "struct cpu_info *"/*ci*/, "pri_t"/*pri*/, "struct threadpool *"/*pool*/);
+SDT_PROBE_DEFINE3(sdt, kernel, threadpool, create__failure,
+ "struct cpu_info *"/*ci*/, "pri_t"/*pri*/, "int"/*error*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, destroy,
+ "struct threadpool *"/*pool*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, destroy__wait,
+ "struct threadpool *"/*pool*/, "uint64_t"/*refcnt*/);
+
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, schedule__job,
+ "struct threadpool *"/*pool*/, "struct threadpool_job *"/*job*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, schedule__job__running,
+ "struct threadpool *"/*pool*/, "struct threadpool_job *"/*job*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, schedule__job__overseer,
+ "struct threadpool *"/*pool*/, "struct threadpool_job *"/*job*/);
+SDT_PROBE_DEFINE3(sdt, kernel, threadpool, schedule__job__thread,
+ "struct threadpool *"/*pool*/,
+ "struct threadpool_job *"/*job*/,
+ "struct lwp *"/*thread*/);
+
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, overseer__start,
+ "struct threadpool *"/*pool*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, overseer__dying,
+ "struct threadpool *"/*pool*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, overseer__spawn,
+ "struct threadpool *"/*pool*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, overseer__race,
+ "struct threadpool *"/*pool*/,
+ "struct threadpool_job *"/*job*/);
+SDT_PROBE_DEFINE3(sdt, kernel, threadpool, overseer__assign,
+ "struct threadpool *"/*pool*/,
+ "struct threadpool_job *"/*job*/,
+ "struct lwp *"/*thread*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, overseer__exit,
+ "struct threadpool *"/*pool*/);
+
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, thread__start,
+ "struct threadpool *"/*pool*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, thread__dying,
+ "struct threadpool *"/*pool*/);
+SDT_PROBE_DEFINE2(sdt, kernel, threadpool, thread__job,
+ "struct threadpool *"/*pool*/, "struct threadpool_job *"/*job*/);
+SDT_PROBE_DEFINE1(sdt, kernel, threadpool, thread__exit,
+ "struct threadpool *"/*pool*/);
+
/* Data structures */
TAILQ_HEAD(job_head, threadpool_job);
@@ -224,12 +296,6 @@ threadpool_remove_percpu(struct threadpo
LIST_REMOVE(tpp, tpp_link);
}
-#ifdef THREADPOOL_VERBOSE
-#define TP_LOG(x) printf x
-#else
-#define TP_LOG(x) /* nothing */
-#endif /* THREADPOOL_VERBOSE */
-
static int
sysctl_kern_threadpool_idle_ms(SYSCTLFN_ARGS)
{
@@ -308,6 +374,8 @@ threadpool_create(struct threadpool *con
KASSERT(threadpool_pri_is_valid(pri));
+ SDT_PROBE2(sdt, kernel, threadpool, create, ci, pri);
+
mutex_init(&pool->tp_lock, MUTEX_DEFAULT, IPL_VM);
/* XXX overseer */
TAILQ_INIT(&pool->tp_jobs);
@@ -337,6 +405,7 @@ threadpool_create(struct threadpool *con
cv_broadcast(&pool->tp_overseer.tpt_cv);
mutex_spin_exit(&pool->tp_lock);
+ SDT_PROBE3(sdt, kernel, threadpool, create__success, ci, pri, pool);
return 0;
fail0: KASSERT(error);
@@ -349,6 +418,7 @@ fail0: KASSERT(error);
KASSERT(!cv_has_waiters(&pool->tp_overseer.tpt_cv));
cv_destroy(&pool->tp_overseer.tpt_cv);
mutex_destroy(&pool->tp_lock);
+ SDT_PROBE3(sdt, kernel, threadpool, create__failure, ci, pri, error);
return error;
}
@@ -359,6 +429,8 @@ threadpool_destroy(struct threadpool *po
{
struct threadpool_thread *thread;
+ SDT_PROBE1(sdt, kernel, threadpool, destroy, pool);
+
/* Mark the pool dying and wait for threads to commit suicide. */
mutex_spin_enter(&pool->tp_lock);
KASSERT(TAILQ_EMPTY(&pool->tp_jobs));
@@ -367,8 +439,8 @@ threadpool_destroy(struct threadpool *po
TAILQ_FOREACH(thread, &pool->tp_idle_threads, tpt_entry)
cv_broadcast(&thread->tpt_cv);
while (0 < pool->tp_refcnt) {
- TP_LOG(("%s: draining %" PRIu64 " references...\n", __func__,
- pool->tp_refcnt));
+ SDT_PROBE2(sdt, kernel, threadpool, destroy__wait,
+ pool, pool->tp_refcnt);
cv_wait(&pool->tp_overseer.tpt_cv, &pool->tp_lock);
}
mutex_spin_exit(&pool->tp_lock);
@@ -413,6 +485,8 @@ threadpool_get(struct threadpool **poolp
ASSERT_SLEEPABLE();
+ SDT_PROBE1(sdt, kernel, threadpool, get, pri);
+
if (! threadpool_pri_is_valid(pri))
return EINVAL;
@@ -420,8 +494,7 @@ threadpool_get(struct threadpool **poolp
tpu = threadpool_lookup_unbound(pri);
if (tpu == NULL) {
mutex_exit(&threadpools_lock);
- TP_LOG(("%s: No pool for pri=%d, creating one.\n",
- __func__, (int)pri));
+ SDT_PROBE1(sdt, kernel, threadpool, get__create, pri);
tmp = kmem_zalloc(sizeof(*tmp), KM_SLEEP);
error = threadpool_create(&tmp->tpu_pool, NULL, pri);
if (error) {
@@ -431,11 +504,11 @@ threadpool_get(struct threadpool **poolp
mutex_enter(&threadpools_lock);
tpu = threadpool_lookup_unbound(pri);
if (tpu == NULL) {
- TP_LOG(("%s: Won the creation race for pri=%d.\n",
- __func__, (int)pri));
tpu = tmp;
tmp = NULL;
threadpool_insert_unbound(tpu);
+ } else {
+ SDT_PROBE1(sdt, kernel, threadpool, get__race, pri);
}
}
KASSERT(tpu != NULL);
@@ -459,15 +532,15 @@ threadpool_put(struct threadpool *pool,
container_of(pool, struct threadpool_unbound, tpu_pool);
ASSERT_SLEEPABLE();
-
KASSERT(threadpool_pri_is_valid(pri));
+ SDT_PROBE2(sdt, kernel, threadpool, put, pool, pri);
+
mutex_enter(&threadpools_lock);
KASSERT(tpu == threadpool_lookup_unbound(pri));
KASSERT(0 < tpu->tpu_refcnt);
if (--tpu->tpu_refcnt == 0) {
- TP_LOG(("%s: Last reference for pri=%d, destroying pool.\n",
- __func__, (int)pri));
+ SDT_PROBE2(sdt, kernel, threadpool, put__destroy, pool, pri);
threadpool_remove_unbound(tpu);
} else {
tpu = NULL;
@@ -490,6 +563,8 @@ threadpool_percpu_get(struct threadpool_
ASSERT_SLEEPABLE();
+ SDT_PROBE1(sdt, kernel, threadpool, percpu__get, pri);
+
if (! threadpool_pri_is_valid(pri))
return EINVAL;
@@ -497,8 +572,7 @@ threadpool_percpu_get(struct threadpool_
pool_percpu = threadpool_lookup_percpu(pri);
if (pool_percpu == NULL) {
mutex_exit(&threadpools_lock);
- TP_LOG(("%s: No pool for pri=%d, creating one.\n",
- __func__, (int)pri));
+ SDT_PROBE1(sdt, kernel, threadpool, percpu__get__create, pri);
error = threadpool_percpu_create(&tmp, pri);
if (error)
return error;
@@ -506,11 +580,12 @@ threadpool_percpu_get(struct threadpool_
mutex_enter(&threadpools_lock);
pool_percpu = threadpool_lookup_percpu(pri);
if (pool_percpu == NULL) {
- TP_LOG(("%s: Won the creation race for pri=%d.\n",
- __func__, (int)pri));
pool_percpu = tmp;
tmp = NULL;
threadpool_insert_percpu(pool_percpu);
+ } else {
+ SDT_PROBE1(sdt, kernel, threadpool, percpu__get__race,
+ pri);
}
}
KASSERT(pool_percpu != NULL);
@@ -533,12 +608,14 @@ threadpool_percpu_put(struct threadpool_
KASSERT(threadpool_pri_is_valid(pri));
+ SDT_PROBE2(sdt, kernel, threadpool, percpu__put, pool_percpu, pri);
+
mutex_enter(&threadpools_lock);
KASSERT(pool_percpu == threadpool_lookup_percpu(pri));
KASSERT(0 < pool_percpu->tpp_refcnt);
if (--pool_percpu->tpp_refcnt == 0) {
- TP_LOG(("%s: Last reference for pri=%d, destroying pool.\n",
- __func__, (int)pri));
+ SDT_PROBE2(sdt, kernel, threadpool, percpu__put__destroy,
+ pool_percpu, pri);
threadpool_remove_percpu(pool_percpu);
} else {
pool_percpu = NULL;
@@ -768,6 +845,8 @@ threadpool_schedule_job(struct threadpoo
KASSERT(mutex_owned(job->job_lock));
+ SDT_PROBE2(sdt, kernel, threadpool, schedule__job, pool, job);
+
/*
* If the job's already running, let it keep running. The job
* is guaranteed by the interlock not to end early -- if it had
@@ -775,8 +854,8 @@ threadpool_schedule_job(struct threadpoo
* to NULL under the interlock.
*/
if (__predict_true(job->job_thread != NULL)) {
- TP_LOG(("%s: job '%s' already runnining.\n",
- __func__, job->job_name));
+ SDT_PROBE2(sdt, kernel, threadpool, schedule__job__running,
+ pool, job);
return;
}
@@ -786,15 +865,15 @@ threadpool_schedule_job(struct threadpoo
mutex_spin_enter(&pool->tp_lock);
if (__predict_false(TAILQ_EMPTY(&pool->tp_idle_threads))) {
/* Nobody's idle. Give it to the overseer. */
- TP_LOG(("%s: giving job '%s' to overseer.\n",
- __func__, job->job_name));
+ SDT_PROBE2(sdt, kernel, threadpool, schedule__job__overseer,
+ pool, job);
job->job_thread = &pool->tp_overseer;
TAILQ_INSERT_TAIL(&pool->tp_jobs, job, job_entry);
} else {
/* Assign it to the first idle thread. */
job->job_thread = TAILQ_FIRST(&pool->tp_idle_threads);
- TP_LOG(("%s: giving job '%s' to idle thread %p.\n",
- __func__, job->job_name, job->job_thread));
+ SDT_PROBE3(sdt, kernel, threadpool, schedule__job__thread,
+ pool, job, job->job_thread->tpt_lwp);
TAILQ_REMOVE(&pool->tp_idle_threads, job->job_thread,
tpt_entry);
job->job_thread->tpt_job = job;
@@ -878,20 +957,21 @@ threadpool_overseer_thread(void *arg)
int error;
KASSERT((pool->tp_cpu == NULL) || (pool->tp_cpu == curcpu()));
+ KASSERT((pool->tp_cpu == NULL) || (curlwp->l_pflag & LP_BOUND));
/* Wait until we're initialized. */
mutex_spin_enter(&pool->tp_lock);
while (overseer->tpt_lwp == NULL)
cv_wait(&overseer->tpt_cv, &pool->tp_lock);
- TP_LOG(("%s: starting.\n", __func__));
+ SDT_PROBE1(sdt, kernel, threadpool, overseer__start, pool);
for (;;) {
/* Wait until there's a job. */
while (TAILQ_EMPTY(&pool->tp_jobs)) {
if (ISSET(pool->tp_flags, THREADPOOL_DYING)) {
- TP_LOG(("%s: THREADPOOL_DYING\n",
- __func__));
+ SDT_PROBE1(sdt, kernel, threadpool,
+ overseer__dying, pool);
break;
}
cv_wait(&overseer->tpt_cv, &pool->tp_lock);
@@ -901,8 +981,8 @@ threadpool_overseer_thread(void *arg)
/* If there are no threads, we'll have to try to start one. */
if (TAILQ_EMPTY(&pool->tp_idle_threads)) {
- TP_LOG(("%s: Got a job, need to create a thread.\n",
- __func__));
+ SDT_PROBE1(sdt, kernel, threadpool, overseer__spawn,
+ pool);
threadpool_hold(pool);
mutex_spin_exit(&pool->tp_lock);
@@ -965,8 +1045,8 @@ threadpool_overseer_thread(void *arg)
* Someone else snagged the thread
* first. We'll have to try again.
*/
- TP_LOG(("%s: '%s' lost race to use idle thread.\n",
- __func__, job->job_name));
+ SDT_PROBE2(sdt, kernel, threadpool,
+ overseer__race, pool, job);
TAILQ_INSERT_HEAD(&pool->tp_jobs, job,
job_entry);
} else {
@@ -977,8 +1057,8 @@ threadpool_overseer_thread(void *arg)
struct threadpool_thread *const thread =
TAILQ_FIRST(&pool->tp_idle_threads);
- TP_LOG(("%s: '%s' gets thread %p\n",
- __func__, job->job_name, thread));
+ SDT_PROBE2(sdt, kernel, threadpool,
+ overseer__assign, job, thread->tpt_lwp);
KASSERT(thread->tpt_job == NULL);
TAILQ_REMOVE(&pool->tp_idle_threads, thread,
tpt_entry);
@@ -996,7 +1076,7 @@ threadpool_overseer_thread(void *arg)
threadpool_rele(pool);
mutex_spin_exit(&pool->tp_lock);
- TP_LOG(("%s: exiting.\n", __func__));
+ SDT_PROBE1(sdt, kernel, threadpool, overseer__exit, pool);
kthread_exit(0);
}
@@ -1010,21 +1090,22 @@ threadpool_thread(void *arg)
struct threadpool *const pool = thread->tpt_pool;
KASSERT((pool->tp_cpu == NULL) || (pool->tp_cpu == curcpu()));
+ KASSERT((pool->tp_cpu == NULL) || (curlwp->l_pflag & LP_BOUND));
/* Wait until we're initialized and on the queue. */
mutex_spin_enter(&pool->tp_lock);
while (thread->tpt_lwp == NULL)
cv_wait(&thread->tpt_cv, &pool->tp_lock);
- TP_LOG(("%s: starting.\n", __func__));
+ SDT_PROBE1(sdt, kernel, threadpool, thread__start, pool);
KASSERT(thread->tpt_lwp == curlwp);
for (;;) {
/* Wait until we are assigned a job. */
while (thread->tpt_job == NULL) {
if (ISSET(pool->tp_flags, THREADPOOL_DYING)) {
- TP_LOG(("%s: THREADPOOL_DYING\n",
- __func__));
+ SDT_PROBE1(sdt, kernel, threadpool,
+ thread__dying, pool);
break;
}
if (cv_timedwait(&thread->tpt_cv, &pool->tp_lock,
@@ -1049,8 +1130,7 @@ threadpool_thread(void *arg)
mutex_spin_exit(&pool->tp_lock);
- TP_LOG(("%s: running job '%s' on thread %p.\n",
- __func__, job->job_name, thread));
+ SDT_PROBE2(sdt, kernel, threadpool, thread__job, pool, job);
/* Run the job. */
(*job->job_fn)(job);
@@ -1073,7 +1153,7 @@ threadpool_thread(void *arg)
threadpool_rele(pool);
mutex_spin_exit(&pool->tp_lock);
- TP_LOG(("%s: thread %p exiting.\n", __func__, thread));
+ SDT_PROBE1(sdt, kernel, threadpool, thread__exit, pool);
KASSERT(!cv_has_waiters(&thread->tpt_cv));
cv_destroy(&thread->tpt_cv);