uma: Use a taskqueue to execute uma_timeout()

uma_timeout() has several responsibilities; it visits every UMA zone and
as of recently will drain underutilized caches, so is rather expensive
(>1ms in some cases).  Currently it is executed by softclock threads
and so will preempt most other CPU activity.  None of this work requires
a high scheduling priority, though, so defer it to a taskqueue so as to
avoid stalling higher-priority work.

Reviewed by:	rlibby, alc, mav, kib
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D35738
This commit is contained in:
Mark Johnston 2022-07-11 15:45:36 -04:00
parent a889a65ba3
commit 93cd28ea82

View File

@ -207,7 +207,7 @@ static enum {
* This is the handle used to schedule events that need to happen
* outside of the allocation fast path.
*/
static struct callout uma_callout;
static struct timeout_task uma_timeout_task;
#define UMA_TIMEOUT 20 /* Seconds for callout interval. */
/*
@ -311,7 +311,7 @@ static void zone_timeout(uma_zone_t zone, void *);
static int hash_alloc(struct uma_hash *, u_int);
static int hash_expand(struct uma_hash *, struct uma_hash *);
static void hash_free(struct uma_hash *hash);
static void uma_timeout(void *);
static void uma_timeout(void *, int);
static void uma_shutdown(void);
static void *zone_alloc_item(uma_zone_t, void *, int, int);
static void zone_free_item(uma_zone_t, void *, void *, enum zfreeskip);
@ -1107,13 +1107,14 @@ zone_maxaction(uma_zone_t zone)
* Nothing
*/
static void
uma_timeout(void *unused)
uma_timeout(void *unused __unused, int pending __unused)
{
bucket_enable();
zone_foreach(zone_timeout, NULL);
/* Reschedule this event */
callout_reset(&uma_callout, UMA_TIMEOUT * hz, uma_timeout, NULL);
taskqueue_enqueue_timeout(taskqueue_thread, &uma_timeout_task,
UMA_TIMEOUT * hz);
}
/*
@ -3208,8 +3209,6 @@ uma_startup3(void *arg __unused)
uma_skip_cnt = counter_u64_alloc(M_WAITOK);
#endif
zone_foreach_unlocked(zone_alloc_sysctl, NULL);
callout_init(&uma_callout, 1);
callout_reset(&uma_callout, UMA_TIMEOUT * hz, uma_timeout, NULL);
booted = BOOT_RUNNING;
EVENTHANDLER_REGISTER(shutdown_post_sync, uma_shutdown, NULL,
@ -3217,6 +3216,16 @@ uma_startup3(void *arg __unused)
}
SYSINIT(uma_startup3, SI_SUB_VM_CONF, SI_ORDER_SECOND, uma_startup3, NULL);
static void
uma_startup4(void *arg __unused)
{
TIMEOUT_TASK_INIT(taskqueue_thread, &uma_timeout_task, 0, uma_timeout,
NULL);
taskqueue_enqueue_timeout(taskqueue_thread, &uma_timeout_task,
UMA_TIMEOUT * hz);
}
SYSINIT(uma_startup4, SI_SUB_TASKQ, SI_ORDER_ANY, uma_startup4, NULL);
static void
uma_shutdown(void)
{