hardclock(9), roundrobin: make roundrobin() an independent clock interrupt
authorcheloha <cheloha@openbsd.org>
Fri, 11 Aug 2023 22:02:50 +0000 (22:02 +0000)
committercheloha <cheloha@openbsd.org>
Fri, 11 Aug 2023 22:02:50 +0000 (22:02 +0000)
- Remove the roundrobin() call from hardclock(9).

- Revise roundrobin() to make it a valid clock interrupt callback.
  It is still periodic and it still runs at one tenth of the hardclock
  frequency.

- Account for multiple expirations in roundrobin(): if two or more
  roundrobin periods have elapsed, set SPCF_SHOULDYIELD on the running
  thread immediately to simulate normal behavior.

- Each schedstate_percpu has its own roundrobin() handle, spc_roundrobin.
  spc_roundrobin is started/advanced during clockintr_cpu_init().
  Intervals elapsed across suspend/resume are discarded.

- rrticks_init and schedstate_percpu.spc_rrticks are now useless:
  delete them.

Tweaked by mpi@.  With input from mpi@ and claudio@.

Thread: https://marc.info/?l=openbsd-tech&m=169127381314651&w=2

ok mpi@ claudio@

sys/kern/kern_clock.c
sys/kern/kern_clockintr.c
sys/kern/kern_sched.c
sys/kern/sched_bsd.c
sys/sys/sched.h

index bcd3a9f..1e97ba8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_clock.c,v 1.111 2023/08/05 20:07:55 cheloha Exp $        */
+/*     $OpenBSD: kern_clock.c,v 1.112 2023/08/11 22:02:50 cheloha Exp $        */
 /*     $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $   */
 
 /*-
@@ -113,9 +113,6 @@ hardclock(struct clockframe *frame)
 {
        struct cpu_info *ci = curcpu();
 
-       if (--ci->ci_schedstate.spc_rrticks <= 0)
-               roundrobin(ci);
-
 #if NDT > 0
        DT_ENTER(profile, NULL);
        if (CPU_IS_PRIMARY(ci))
index 5e80c2e..6351a0b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_clockintr.c,v 1.30 2023/08/05 20:07:55 cheloha Exp $ */
+/* $OpenBSD: kern_clockintr.c,v 1.31 2023/08/11 22:02:50 cheloha Exp $ */
 /*
  * Copyright (c) 2003 Dale Rahn <drahn@openbsd.org>
  * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -69,6 +69,7 @@ clockintr_init(u_int flags)
 
        KASSERT(hz > 0 && hz <= 1000000000);
        hardclock_period = 1000000000 / hz;
+       roundrobin_period = hardclock_period * 10;
 
        KASSERT(stathz >= 1 && stathz <= 1000000000);
 
@@ -204,6 +205,11 @@ clockintr_cpu_init(const struct intrclock *ic)
                clockintr_stagger(spc->spc_profclock, profclock_period,
                    multiplier, MAXCPUS);
        }
+       if (spc->spc_roundrobin->cl_expiration == 0) {
+               clockintr_stagger(spc->spc_roundrobin, hardclock_period,
+                   multiplier, MAXCPUS);
+       }
+       clockintr_advance(spc->spc_roundrobin, roundrobin_period);
 
        if (reset_cq_intrclock)
                SET(cq->cq_flags, CQ_INTRCLOCK);
index 6faf6af..87755c6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_sched.c,v 1.84 2023/08/05 20:07:55 cheloha Exp $ */
+/*     $OpenBSD: kern_sched.c,v 1.85 2023/08/11 22:02:50 cheloha Exp $ */
 /*
  * Copyright (c) 2007, 2008 Artur Grabowski <art@openbsd.org>
  *
@@ -102,6 +102,12 @@ sched_init_cpu(struct cpu_info *ci)
                if (spc->spc_profclock == NULL)
                        panic("%s: clockintr_establish profclock", __func__);
        }
+       if (spc->spc_roundrobin == NULL) {
+               spc->spc_roundrobin = clockintr_establish(&ci->ci_queue,
+                   roundrobin);
+               if (spc->spc_roundrobin == NULL)
+                       panic("%s: clockintr_establish roundrobin", __func__);
+       }
 
        kthread_create_deferred(sched_kthreads_create, ci);
 
index d7ab050..7ffdc2e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sched_bsd.c,v 1.79 2023/08/05 20:07:55 cheloha Exp $  */
+/*     $OpenBSD: sched_bsd.c,v 1.80 2023/08/11 22:02:50 cheloha Exp $  */
 /*     $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
 
 /*-
@@ -54,9 +54,8 @@
 #include <sys/ktrace.h>
 #endif
 
-
+uint32_t roundrobin_period;    /* [I] roundrobin period (ns) */
 int    lbolt;                  /* once a second sleep address */
-int    rrticks_init;           /* # of hardclock ticks per roundrobin() */
 
 #ifdef MULTIPROCESSOR
 struct __mp_lock sched_lock;
@@ -69,21 +68,23 @@ uint32_t            decay_aftersleep(uint32_t, uint32_t);
  * Force switch among equal priority processes every 100ms.
  */
 void
-roundrobin(struct cpu_info *ci)
+roundrobin(struct clockintr *cl, void *cf)
 {
+       uint64_t count;
+       struct cpu_info *ci = curcpu();
        struct schedstate_percpu *spc = &ci->ci_schedstate;
 
-       spc->spc_rrticks = rrticks_init;
+       count = clockintr_advance(cl, roundrobin_period);
 
        if (ci->ci_curproc != NULL) {
-               if (spc->spc_schedflags & SPCF_SEENRR) {
+               if (spc->spc_schedflags & SPCF_SEENRR || count >= 2) {
                        /*
                         * The process has already been through a roundrobin
                         * without switching and may be hogging the CPU.
                         * Indicate that the process should yield.
                         */
                        atomic_setbits_int(&spc->spc_schedflags,
-                           SPCF_SHOULDYIELD);
+                           SPCF_SEENRR | SPCF_SHOULDYIELD);
                } else {
                        atomic_setbits_int(&spc->spc_schedflags,
                            SPCF_SEENRR);
@@ -695,8 +696,6 @@ scheduler_start(void)
         * its job.
         */
        timeout_set(&schedcpu_to, schedcpu, &schedcpu_to);
-
-       rrticks_init = hz / 10;
        schedcpu(&schedcpu_to);
 
 #ifndef SMALL_KERNEL
index c63d96d..9b4e278 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sched.h,v 1.60 2023/08/05 20:07:56 cheloha Exp $      */
+/*     $OpenBSD: sched.h,v 1.61 2023/08/11 22:02:50 cheloha Exp $      */
 /* $NetBSD: sched.h,v 1.2 1999/02/28 18:14:58 ross Exp $ */
 
 /*-
@@ -105,10 +105,10 @@ struct schedstate_percpu {
        u_int spc_schedticks;           /* ticks for schedclock() */
        u_int64_t spc_cp_time[CPUSTATES]; /* CPU state statistics */
        u_char spc_curpriority;         /* usrpri of curproc */
-       int spc_rrticks;                /* ticks until roundrobin() */
 
        struct clockintr *spc_itimer;   /* [o] itimer_update handle */
        struct clockintr *spc_profclock; /* [o] profclock handle */
+       struct clockintr *spc_roundrobin; /* [o] roundrobin handle */
 
        u_int spc_nrun;                 /* procs on the run queues */
 
@@ -145,16 +145,16 @@ struct cpustats {
 #define NICE_WEIGHT 2                  /* priorities per nice level */
 #define        ESTCPULIM(e) min((e), NICE_WEIGHT * PRIO_MAX - SCHED_PPQ)
 
+extern uint32_t roundrobin_period;
 extern int schedhz;                    /* ideally: 16 */
-extern int rrticks_init;               /* ticks per roundrobin() */
 
 struct proc;
 void schedclock(struct proc *);
-struct cpu_info;
-void roundrobin(struct cpu_info *);
+void roundrobin(struct clockintr *, void *);
 void scheduler_start(void);
 void userret(struct proc *p);
 
+struct cpu_info;
 void sched_init_cpu(struct cpu_info *);
 void sched_idle(void *);
 void sched_exit(struct proc *);