Hello, I'm investigating how to make our kernel less reliant on hardclock(9) being called at hz(9).
Please find attached a patch to reduce hardclock(9)'s responsibilities wrt the rest of the system timekeeping. The idea is that hardclock(9) will drive callout_hardclock() for now, until we modify the latter to not expect a fixed "tick" rate (ie; hz) - at which point we have the option of several callers - for eg: a carefully crafted one-shot interrupt at a programmable timespan. With this patch, I'd like to understand what it does to the system as-is - so ideally as many configs as possible (different arch/ and MP/UP) as well as virtualisation situations (eg: Xen). I look forward to your comments and test results, if any. Many Thanks, -- Math/(~cherry)
diff -r 95278b51da8b sys/kern/kern_clock.c --- a/sys/kern/kern_clock.c Tue Mar 19 10:53:00 2024 +0000 +++ b/sys/kern/kern_clock.c Wed Mar 20 05:24:07 2024 +0000 @@ -107,6 +107,9 @@ static int sysctl_kern_clockrate(SYSCTLFN_PROTO); +static callout_t clocktick_coh_var, *clocktick_coh = + &clocktick_coh_var; /* Callout handle for clock tick */ + /* * Clock handling routines. * @@ -222,6 +225,42 @@ return atomic_load_relaxed(&hardclock_ticks); } +static void +clocktick(void *coptr) +{ + struct lwp *l; + struct cpu_info *ci; + + ci = curcpu(); + l = ci->ci_onproc; + + /* + * If no separate schedclock is provided, call it here + * at about 16 Hz. + */ + if (schedhz == 0) { + if ((int)(--ci->ci_schedstate.spc_schedticks) <= 0) { + schedclock(l); + ci->ci_schedstate.spc_schedticks = hardscheddiv; + } + } + if ((--ci->ci_schedstate.spc_ticks) <= 0) + sched_tick(ci); + + if (CPU_IS_PRIMARY(ci)) { + atomic_store_relaxed(&hardclock_ticks, + atomic_load_relaxed(&hardclock_ticks) + 1); + tc_ticktock(); + } + + /* + * Make sure the CPUs and timecounter are making progress. + */ + heartbeat(); + + callout_schedule(clocktick_coh, 1); /* Schedule next one */ +} + /* * Initialize clock frequencies and start both clocks running. */ @@ -254,6 +293,10 @@ */ intr_timecounter.tc_frequency = hz; tc_init(&intr_timecounter); + callout_init(clocktick_coh, CALLOUT_MPSAFE); + callout_setfunc(clocktick_coh, clocktick, curcpu()); + callout_schedule(clocktick_coh, 1); /* Schedule first one */ + callout_hardclock(); /* And kick it down the road */ /* * Compute profhz and stathz, fix profhz if needed. @@ -318,33 +361,9 @@ if (stathz == 0) statclock(frame); /* - * If no separate schedclock is provided, call it here - * at about 16 Hz. - */ - if (schedhz == 0) { - if ((int)(--ci->ci_schedstate.spc_schedticks) <= 0) { - schedclock(l); - ci->ci_schedstate.spc_schedticks = hardscheddiv; - } - } - if ((--ci->ci_schedstate.spc_ticks) <= 0) - sched_tick(ci); - - if (CPU_IS_PRIMARY(ci)) { - atomic_store_relaxed(&hardclock_ticks, - atomic_load_relaxed(&hardclock_ticks) + 1); - tc_ticktock(); - } - - /* - * Make sure the CPUs and timecounter are making progress. - */ - heartbeat(); - - /* * Update real-time timeout queue. */ - callout_hardclock(); + callout_hardclock(); } /*