mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
Add a delay to tearing down threads.
It's been observed that in certain workloads (zvol-related being a big one), ZFS will end up spending a large amount of time spinning up taskqs only to tear them down again almost immediately, then spin them up again... I noticed this when I looked at what my mostly-idle system was doing and wondered how on earth taskq creation/destroy was a bunch of time... So I added a configurable delay to avoid it tearing down tasks the first time it notices them idle, and the total number of threads at steady state went up, but the amount of time being burned just tearing down/turning up new ones almost vanished. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Rich Ercolani <rincebrain@gmail.com> Closes #14938
This commit is contained in:
@@ -36,6 +36,12 @@ static int spl_taskq_thread_bind = 0;
|
||||
module_param(spl_taskq_thread_bind, int, 0644);
|
||||
MODULE_PARM_DESC(spl_taskq_thread_bind, "Bind taskq thread to CPU by default");
|
||||
|
||||
static uint_t spl_taskq_thread_timeout_ms = 10000;
|
||||
/* BEGIN CSTYLED */
|
||||
module_param(spl_taskq_thread_timeout_ms, uint, 0644);
|
||||
/* END CSTYLED */
|
||||
MODULE_PARM_DESC(spl_taskq_thread_timeout_ms,
|
||||
"Time to require a dynamic thread be idle before it gets cleaned up");
|
||||
|
||||
static int spl_taskq_thread_dynamic = 1;
|
||||
module_param(spl_taskq_thread_dynamic, int, 0444);
|
||||
@@ -848,12 +854,37 @@ taskq_thread_should_stop(taskq_t *tq, taskq_thread_t *tqt)
|
||||
tqt_thread_list) == tqt)
|
||||
return (0);
|
||||
|
||||
return
|
||||
int no_work =
|
||||
((tq->tq_nspawn == 0) && /* No threads are being spawned */
|
||||
(tq->tq_nactive == 0) && /* No threads are handling tasks */
|
||||
(tq->tq_nthreads > 1) && /* More than 1 thread is running */
|
||||
(!taskq_next_ent(tq)) && /* There are no pending tasks */
|
||||
(spl_taskq_thread_dynamic)); /* Dynamic taskqs are allowed */
|
||||
|
||||
/*
|
||||
* If we would have said stop before, let's instead wait a bit, maybe
|
||||
* we'll see more work come our way soon...
|
||||
*/
|
||||
if (no_work) {
|
||||
/* if it's 0, we want the old behavior. */
|
||||
/* if the taskq is being torn down, we also want to go away. */
|
||||
if (spl_taskq_thread_timeout_ms == 0 ||
|
||||
!(tq->tq_flags & TASKQ_ACTIVE))
|
||||
return (1);
|
||||
unsigned long lasttime = tq->lastshouldstop;
|
||||
if (lasttime > 0) {
|
||||
if (time_after(jiffies, lasttime +
|
||||
msecs_to_jiffies(spl_taskq_thread_timeout_ms)))
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
} else {
|
||||
tq->lastshouldstop = jiffies;
|
||||
}
|
||||
} else {
|
||||
tq->lastshouldstop = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1091,6 +1122,7 @@ taskq_create(const char *name, int threads_arg, pri_t pri,
|
||||
tq->tq_flags = (flags | TASKQ_ACTIVE);
|
||||
tq->tq_next_id = TASKQID_INITIAL;
|
||||
tq->tq_lowest_id = TASKQID_INITIAL;
|
||||
tq->lastshouldstop = 0;
|
||||
INIT_LIST_HEAD(&tq->tq_free_list);
|
||||
INIT_LIST_HEAD(&tq->tq_pend_list);
|
||||
INIT_LIST_HEAD(&tq->tq_prio_list);
|
||||
|
||||
Reference in New Issue
Block a user