The branch main has been updated by olce: URL: https://cgit.FreeBSD.org/src/commit/?id=7e2502e3dec989ea31e5300ade759a721718548d
commit 7e2502e3dec989ea31e5300ade759a721718548d Author: Olivier Certner <o...@freebsd.org> AuthorDate: 2024-04-23 11:33:02 +0000 Commit: Olivier Certner <o...@freebsd.org> CommitDate: 2025-06-18 02:07:58 +0000 runq: More macros; Better and more consistent naming Most existing macros have ambiguous names regarding which index they operate on (queue, word, bit?), so have been renamed to improve clarity. Use the 'RQSW_' prefix for all macros related to status words, and change the status word type name accordingly. Rename RQB_FFS() to RQSW_BSF() to remove confusion about the return value (ffs*() return bit indices starting at 1, or 0 if the input is 0, whereas BSF on x86 returns 0-based indices, which is what the current code assumes). While here, add a check (under INVARIANTS) that RQSW_BSF() isn't called with 0 as an argument. Also, rename 'rqb_bits_t' to the more concise 'rqsw_t', 'struct rqbits' to 'struct rq_status', its 'rqb_bits' field to 'rq_sw' (it designates an array of words, not bits), and the type 'rqhead' to 'rq_queue' Add macros computing a queue index from a status word index and a bit in order to factorize code. If the precise index of the bit is known, callers can use RQSW_TO_QUEUE_IDX() to get the corresponding queue index, whereas if they want the one corresponding to the first (least-significant): set bit in a given status word (corresponding to the non-empty queue with lower index in the status word), they can use RQSW_FIRST_QUEUE_IDX() instead. Add RQSW_BIT_IDX(), which computes the correspond bit's index in the corresponding status word. This allows more code factorization (even if most uses will be eliminated in a later commit) and makes what is computed clearer. Reviewed by: kib MFC after: 1 month Event: Kitchener-Waterloo Hackathon 202506 Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D45387 --- sys/kern/kern_switch.c | 114 ++++++++++++++++++++++++------------------------- sys/kern/sched_4bsd.c | 2 +- sys/kern/sched_ule.c | 56 ++++++++++++------------ sys/sys/runq.h | 40 ++++++++++------- 4 files changed, 111 insertions(+), 101 deletions(-) diff --git a/sys/kern/kern_switch.c b/sys/kern/kern_switch.c index 906efca4bb51..9e63709d0acc 100644 --- a/sys/kern/kern_switch.c +++ b/sys/kern/kern_switch.c @@ -281,15 +281,15 @@ runq_init(struct runq *rq) static __inline void runq_clrbit(struct runq *rq, int idx) { - struct rqbits *rqb; + struct rq_status *rqs; CHECK_IDX(idx); - rqb = &rq->rq_status; + rqs = &rq->rq_status; CTR4(KTR_RUNQ, "runq_clrbit: bits=%#x %#x bit=%#x word=%d", - rqb->rqb_bits[RQB_WORD(idx)], - rqb->rqb_bits[RQB_WORD(idx)] & ~RQB_BIT(idx), - RQB_BIT(idx), RQB_WORD(idx)); - rqb->rqb_bits[RQB_WORD(idx)] &= ~RQB_BIT(idx); + rqs->rq_sw[RQSW_IDX(idx)], + rqs->rq_sw[RQSW_IDX(idx)] & ~RQSW_BIT(idx), + RQSW_BIT(idx), RQSW_IDX(idx)); + rqs->rq_sw[RQSW_IDX(idx)] &= ~RQSW_BIT(idx); } /* @@ -299,16 +299,16 @@ runq_clrbit(struct runq *rq, int idx) static __inline int runq_findbit(struct runq *rq) { - struct rqbits *rqb; + struct rq_status *rqs; int idx; - rqb = &rq->rq_status; - for (int i = 0; i < RQB_LEN; i++) - if (rqb->rqb_bits[i] != 0) { - idx = RQB_FFS(rqb->rqb_bits[i]) + i * RQB_BPW; + rqs = &rq->rq_status; + for (int i = 0; i < RQSW_NB; i++) + if (rqs->rq_sw[i] != 0) { + idx = RQSW_FIRST_QUEUE_IDX(i, rqs->rq_sw[i]); CHECK_IDX(idx); CTR3(KTR_RUNQ, "runq_findbit: bits=%#x i=%d idx=%d", - rqb->rqb_bits[i], i, idx); + rqs->rq_sw[i], i, idx); return (idx); } @@ -318,20 +318,20 @@ runq_findbit(struct runq *rq) static __inline int runq_findbit_from(struct runq *rq, int idx) { - struct rqbits *rqb; - rqb_word_t mask; + struct rq_status *rqs; + rqsw_t mask; int i; CHECK_IDX(idx); /* Set the mask for the first word so we ignore indices before 'idx'. */ - mask = (rqb_word_t)-1 << (idx & (RQB_BPW - 1)); - rqb = &rq->rq_status; + mask = (rqsw_t)-1 << RQSW_BIT_IDX(idx); + rqs = &rq->rq_status; again: - for (i = RQB_WORD(idx); i < RQB_LEN; mask = -1, i++) { - mask = rqb->rqb_bits[i] & mask; + for (i = RQSW_IDX(idx); i < RQSW_NB; mask = -1, i++) { + mask = rqs->rq_sw[i] & mask; if (mask == 0) continue; - idx = RQB_FFS(mask) + i * RQB_BPW; + idx = RQSW_FIRST_QUEUE_IDX(i, mask); CTR3(KTR_RUNQ, "runq_findbit_from: bits=%#x i=%d idx=%d", mask, i, idx); return (idx); @@ -353,15 +353,15 @@ again: static __inline void runq_setbit(struct runq *rq, int idx) { - struct rqbits *rqb; + struct rq_status *rqs; CHECK_IDX(idx); - rqb = &rq->rq_status; + rqs = &rq->rq_status; CTR4(KTR_RUNQ, "runq_setbit: bits=%#x %#x bit=%#x word=%d", - rqb->rqb_bits[RQB_WORD(idx)], - rqb->rqb_bits[RQB_WORD(idx)] | RQB_BIT(idx), - RQB_BIT(idx), RQB_WORD(idx)); - rqb->rqb_bits[RQB_WORD(idx)] |= RQB_BIT(idx); + rqs->rq_sw[RQSW_IDX(idx)], + rqs->rq_sw[RQSW_IDX(idx)] | RQSW_BIT(idx), + RQSW_BIT(idx), RQSW_IDX(idx)); + rqs->rq_sw[RQSW_IDX(idx)] |= RQSW_BIT(idx); } /* @@ -372,13 +372,13 @@ void runq_add(struct runq *rq, struct thread *td, int flags) { - runq_add_idx(rq, td, RQ_PRI_TO_IDX(td->td_priority), flags); + runq_add_idx(rq, td, RQ_PRI_TO_QUEUE_IDX(td->td_priority), flags); } void runq_add_idx(struct runq *rq, struct thread *td, int idx, int flags) { - struct rqhead *rqh; + struct rq_queue *rqq; /* * runq_setbit() asserts 'idx' is non-negative and below 'RQ_NQS', and @@ -387,13 +387,13 @@ runq_add_idx(struct runq *rq, struct thread *td, int idx, int flags) */ td->td_rqindex = idx; runq_setbit(rq, idx); - rqh = &rq->rq_queues[idx]; - CTR4(KTR_RUNQ, "runq_add_idx: td=%p pri=%d idx=%d rqh=%p", - td, td->td_priority, idx, rqh); + rqq = &rq->rq_queues[idx]; + CTR4(KTR_RUNQ, "runq_add_idx: td=%p pri=%d idx=%d rqq=%p", + td, td->td_priority, idx, rqq); if (flags & SRQ_PREEMPTED) - TAILQ_INSERT_HEAD(rqh, td, td_runq); + TAILQ_INSERT_HEAD(rqq, td, td_runq); else - TAILQ_INSERT_TAIL(rqh, td, td_runq); + TAILQ_INSERT_TAIL(rqq, td, td_runq); } /* @@ -403,13 +403,13 @@ runq_add_idx(struct runq *rq, struct thread *td, int idx, int flags) bool runq_not_empty(struct runq *rq) { - struct rqbits *rqb; + struct rq_status *rqs; - rqb = &rq->rq_status; - for (int i = 0; i < RQB_LEN; i++) - if (rqb->rqb_bits[i] != 0) { + rqs = &rq->rq_status; + for (int i = 0; i < RQSW_NB; i++) + if (rqs->rq_sw[i] != 0) { CTR2(KTR_RUNQ, "runq_not_empty: bits=%#x i=%d", - rqb->rqb_bits[i], i); + rqs->rq_sw[i], i); return (true); } CTR0(KTR_RUNQ, "runq_not_empty: empty"); @@ -423,13 +423,13 @@ runq_not_empty(struct runq *rq) struct thread * runq_choose_fuzz(struct runq *rq, int fuzz) { - struct rqhead *rqh; + struct rq_queue *rqq; struct thread *td; int idx; idx = runq_findbit(rq); if (idx != -1) { - rqh = &rq->rq_queues[idx]; + rqq = &rq->rq_queues[idx]; /* fuzz == 1 is normal.. 0 or less are ignored */ if (fuzz > 1) { /* @@ -439,7 +439,7 @@ runq_choose_fuzz(struct runq *rq, int fuzz) int count = fuzz; int cpu = PCPU_GET(cpuid); struct thread *td2; - td2 = td = TAILQ_FIRST(rqh); + td2 = td = TAILQ_FIRST(rqq); while (count-- && td2) { if (td2->td_lastcpu == cpu) { @@ -449,10 +449,10 @@ runq_choose_fuzz(struct runq *rq, int fuzz) td2 = TAILQ_NEXT(td2, td_runq); } } else - td = TAILQ_FIRST(rqh); + td = TAILQ_FIRST(rqq); KASSERT(td != NULL, ("runq_choose_fuzz: no proc on busy queue")); CTR3(KTR_RUNQ, - "runq_choose_fuzz: idx=%d thread=%p rqh=%p", idx, td, rqh); + "runq_choose_fuzz: idx=%d thread=%p rqq=%p", idx, td, rqq); return (td); } CTR1(KTR_RUNQ, "runq_choose_fuzz: idleproc idx=%d", idx); @@ -466,17 +466,17 @@ runq_choose_fuzz(struct runq *rq, int fuzz) struct thread * runq_choose(struct runq *rq) { - struct rqhead *rqh; + struct rq_queue *rqq; struct thread *td; int idx; idx = runq_findbit(rq); if (idx != -1) { - rqh = &rq->rq_queues[idx]; - td = TAILQ_FIRST(rqh); + rqq = &rq->rq_queues[idx]; + td = TAILQ_FIRST(rqq); KASSERT(td != NULL, ("runq_choose: no thread on busy queue")); CTR3(KTR_RUNQ, - "runq_choose: idx=%d thread=%p rqh=%p", idx, td, rqh); + "runq_choose: idx=%d thread=%p rqq=%p", idx, td, rqq); return (td); } CTR1(KTR_RUNQ, "runq_choose: idlethread idx=%d", idx); @@ -487,17 +487,17 @@ runq_choose(struct runq *rq) struct thread * runq_choose_from(struct runq *rq, int from_idx) { - struct rqhead *rqh; + struct rq_queue *rqq; struct thread *td; int idx; if ((idx = runq_findbit_from(rq, from_idx)) != -1) { - rqh = &rq->rq_queues[idx]; - td = TAILQ_FIRST(rqh); + rqq = &rq->rq_queues[idx]; + td = TAILQ_FIRST(rqq); KASSERT(td != NULL, ("runq_choose: no thread on busy queue")); CTR4(KTR_RUNQ, - "runq_choose_from: idx=%d thread=%p idx=%d rqh=%p", - idx, td, td->td_rqindex, rqh); + "runq_choose_from: idx=%d thread=%p idx=%d rqq=%p", + idx, td, td->td_rqindex, rqq); return (td); } CTR1(KTR_RUNQ, "runq_choose_from: idlethread idx=%d", idx); @@ -513,17 +513,17 @@ runq_choose_from(struct runq *rq, int from_idx) bool runq_remove(struct runq *rq, struct thread *td) { - struct rqhead *rqh; + struct rq_queue *rqq; int idx; KASSERT(td->td_flags & TDF_INMEM, ("runq_remove: Thread swapped out")); idx = td->td_rqindex; CHECK_IDX(idx); - rqh = &rq->rq_queues[idx]; - CTR4(KTR_RUNQ, "runq_remove: td=%p pri=%d idx=%d rqh=%p", - td, td->td_priority, idx, rqh); - TAILQ_REMOVE(rqh, td, td_runq); - if (TAILQ_EMPTY(rqh)) { + rqq = &rq->rq_queues[idx]; + CTR4(KTR_RUNQ, "runq_remove: td=%p pri=%d idx=%d rqq=%p", + td, td->td_priority, idx, rqq); + TAILQ_REMOVE(rqq, td, td_runq); + if (TAILQ_EMPTY(rqq)) { runq_clrbit(rq, idx); CTR1(KTR_RUNQ, "runq_remove: queue at idx=%d now empty", idx); return (true); diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c index ef49832da017..d15f5d68fbec 100644 --- a/sys/kern/sched_4bsd.c +++ b/sys/kern/sched_4bsd.c @@ -873,7 +873,7 @@ sched_priority(struct thread *td, u_char prio) if (td->td_priority == prio) return; td->td_priority = prio; - if (TD_ON_RUNQ(td) && td->td_rqindex != RQ_PRI_TO_IDX(prio)) { + if (TD_ON_RUNQ(td) && td->td_rqindex != RQ_PRI_TO_QUEUE_IDX(prio)) { sched_rem(td); sched_add(td, SRQ_BORING | SRQ_HOLDTD); } diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c index cd508d12395e..1cec38597952 100644 --- a/sys/kern/sched_ule.c +++ b/sys/kern/sched_ule.c @@ -387,20 +387,20 @@ SDT_PROBE_DEFINE2(sched, , , surrender, "struct thread *", static void runq_print(struct runq *rq) { - struct rqhead *rqh; + struct rq_queue *rqq; struct thread *td; int pri; int j; int i; - for (i = 0; i < RQB_LEN; i++) { + for (i = 0; i < RQSW_NB; i++) { printf("\t\trunq bits %d 0x%zx\n", - i, rq->rq_status.rqb_bits[i]); - for (j = 0; j < RQB_BPW; j++) - if (rq->rq_status.rqb_bits[i] & (1ul << j)) { - pri = j + i * RQB_BPW; - rqh = &rq->rq_queues[pri]; - TAILQ_FOREACH(td, rqh, td_runq) { + i, rq->rq_status.rq_sw[i]); + for (j = 0; j < RQSW_BPW; j++) + if (rq->rq_status.rq_sw[i] & (1ul << j)) { + pri = RQSW_TO_QUEUE_IDX(i, j); + rqq = &rq->rq_queues[pri]; + TAILQ_FOREACH(td, rqq, td_runq) { printf("\t\t\ttd %p(%s) priority %d rqindex %d pri %d\n", td, td->td_name, td->td_priority, td->td_rqindex, pri); @@ -1190,26 +1190,26 @@ tdq_notify(struct tdq *tdq, int lowpri) static struct thread * runq_steal_from(struct runq *rq, int cpu, u_char start) { - struct rqbits *rqb; - struct rqhead *rqh; + struct rq_status *rqs; + struct rq_queue *rqq; struct thread *td, *first; int bit; int i; - rqb = &rq->rq_status; - bit = start & (RQB_BPW -1); + rqs = &rq->rq_status; + bit = RQSW_BIT_IDX(start); first = NULL; again: - for (i = RQB_WORD(start); i < RQB_LEN; bit = 0, i++) { - if (rqb->rqb_bits[i] == 0) + for (i = RQSW_IDX(start); i < RQSW_NB; bit = 0, i++) { + if (rqs->rq_sw[i] == 0) continue; if (bit == 0) - bit = RQB_FFS(rqb->rqb_bits[i]); - for (; bit < RQB_BPW; bit++) { - if ((rqb->rqb_bits[i] & (1ul << bit)) == 0) + bit = RQSW_BSF(rqs->rq_sw[i]); + for (; bit < RQSW_BPW; bit++) { + if ((rqs->rq_sw[i] & (1ul << bit)) == 0) continue; - rqh = &rq->rq_queues[bit + i * RQB_BPW]; - TAILQ_FOREACH(td, rqh, td_runq) { + rqq = &rq->rq_queues[RQSW_TO_QUEUE_IDX(i, bit)]; + TAILQ_FOREACH(td, rqq, td_runq) { if (first) { if (THREAD_CAN_MIGRATE(td) && THREAD_CAN_SCHED(td, cpu)) @@ -1236,21 +1236,21 @@ again: static struct thread * runq_steal(struct runq *rq, int cpu) { - struct rqhead *rqh; - struct rqbits *rqb; + struct rq_queue *rqq; + struct rq_status *rqs; struct thread *td; int word; int bit; - rqb = &rq->rq_status; - for (word = 0; word < RQB_LEN; word++) { - if (rqb->rqb_bits[word] == 0) + rqs = &rq->rq_status; + for (word = 0; word < RQSW_NB; word++) { + if (rqs->rq_sw[word] == 0) continue; - for (bit = 0; bit < RQB_BPW; bit++) { - if ((rqb->rqb_bits[word] & (1ul << bit)) == 0) + for (bit = 0; bit < RQSW_BPW; bit++) { + if ((rqs->rq_sw[word] & (1ul << bit)) == 0) continue; - rqh = &rq->rq_queues[bit + word * RQB_BPW]; - TAILQ_FOREACH(td, rqh, td_runq) + rqq = &rq->rq_queues[RQSW_TO_QUEUE_IDX(word, bit)]; + TAILQ_FOREACH(td, rqq, td_runq) if (THREAD_CAN_MIGRATE(td) && THREAD_CAN_SCHED(td, cpu)) return (td); diff --git a/sys/sys/runq.h b/sys/sys/runq.h index 030b4bb370a8..80a1fad0a089 100644 --- a/sys/sys/runq.h +++ b/sys/sys/runq.h @@ -47,16 +47,26 @@ /* * Deduced from the above parameters and machine ones. */ -typedef unsigned long rqb_word_t; /* runq's status words type. */ - #define RQ_NQS (howmany(RQ_MAX_PRIO + 1, RQ_PPQ)) /* Number of run queues. */ -#define RQ_PRI_TO_IDX(pri) ((pri) / RQ_PPQ) /* Priority to queue index. */ - -#define RQB_BPW (sizeof(rqb_word_t) * NBBY) /* Bits per runq word. */ -#define RQB_LEN (howmany(RQ_NQS, RQB_BPW)) /* Words to cover RQ_NQS queues. */ -#define RQB_WORD(idx) ((idx) / RQB_BPW) -#define RQB_BIT(idx) (1ul << ((idx) % RQB_BPW)) -#define RQB_FFS(word) (ffsl((long)(word)) - 1) /* Assumes two-complement. */ +#define RQ_PRI_TO_QUEUE_IDX(pri) ((pri) / RQ_PPQ) /* Priority to queue index. */ + +typedef unsigned long rqsw_t; /* runq's status words type. */ +#define RQSW_BPW (sizeof(rqsw_t) * NBBY) /* Bits per runq word. */ + +/* Number of status words to cover RQ_NQS queues. */ +#define RQSW_NB (howmany(RQ_NQS, RQSW_BPW)) +#define RQSW_IDX(idx) ((idx) / RQSW_BPW) +#define RQSW_BIT_IDX(idx) ((idx) % RQSW_BPW) +#define RQSW_BIT(idx) (1ul << RQSW_BIT_IDX(idx)) +#define RQSW_BSF(word) __extension__ ({ \ + int _res = ffsl((long)(word)); /* Assumes two-complement. */ \ + MPASS(_res > 0); \ + _res - 1; \ +}) +#define RQSW_TO_QUEUE_IDX(word_idx, bit_idx) \ + (((word_idx) * RQSW_BPW) + (bit_idx)) +#define RQSW_FIRST_QUEUE_IDX(word_idx, word) \ + RQSW_TO_QUEUE_IDX(word_idx, RQSW_BSF(word)) #ifdef _KERNEL @@ -66,16 +76,16 @@ typedef unsigned long rqb_word_t; /* runq's status words type. */ struct thread; /* - * Head of run queues. + * The queue for a given index as a list of threads. */ -TAILQ_HEAD(rqhead, thread); +TAILQ_HEAD(rq_queue, thread); /* * Bit array which maintains the status of a run queue. When a queue is * non-empty the bit corresponding to the queue number will be set. */ -struct rqbits { - rqb_word_t rqb_bits[RQB_LEN]; +struct rq_status { + rqsw_t rq_sw[RQSW_NB]; }; /* @@ -83,8 +93,8 @@ struct rqbits { * are placed, and a structure to maintain the status of each queue. */ struct runq { - struct rqbits rq_status; - struct rqhead rq_queues[RQ_NQS]; + struct rq_status rq_status; + struct rq_queue rq_queues[RQ_NQS]; }; void runq_add(struct runq *, struct thread *, int _flags);