Skip to content

Commit a6d1ca0

Browse files
committed
sched: switch to BESTWAIT hardware interrupt steering, retire software lowprio
Replace the software reschedule-interrupt steering with the hardware BESTWAIT/SCHEDCFG comparator (V85 spec Rev AB, section 6.5). The hardware raises RESCHED_INT whenever any HW thread's STID.PRIO is strictly worse than the armed BESTWAIT value and then resets BESTWAIT to 0x1FF, so the kernel no longer needs to designate a victim thread in software. TARGET=ref passes on archs 68/73/81. TARGET=opt is intentionally NOT converted yet -- the opt *.Svariants still implement the old software model and will be rewritten in a follow-up after this ref change is reviewed. Enable hardware steering ------------------------- * boot.ref.S: set imask = 0 on all threads so every HW thread is a qualified RESCHED target. Previously imask was closed (-1) and software opened exactly one victim's RESCHED bit via lowprio_imask(). * setup.ref.c: SCHEDCFG.EN | INTNO(RESCHED_INT) arms the feature at boot. BESTWAIT arming moved into the readylist API --------------------------------------------- Arming the comparator is now the readylist's job. New *_arm variants (H2K_ready_append_arm / _insert_arm / _remove_arm) call H2K_set_bestwait( H2K_ready_best_prio()); the plain variants do not touch BESTWAIT. Callsites choose based on whether they are a wake/sleep transition or a mid-reschedule step: arm : intpool, popup, futex_common (wakes that go straight to H2K_switch), create, vmop kill paths, vmint deliver, resched, and getbest. noarm: yield and futex_pi raise -- these are immediately followed by H2K_dosched on the same HW thread, which re-arms via getbest. resched() must arm: the hardware fire that delivered the interrupt already reset BESTWAIT to 0x1FF, so re-arming immediately closes the disarmed window before dosched's getbest/cluster-search runs. Voluntary paths (yield/hwconfig) did not fire and still hold a valid armed value, so they can defer to dosched. Delete the software steering subsystem --------------------------------------- * Removed sched/lowprio/ entirely (lowprio_imask/highprio_imask/priomask designated-victim machinery and H2K_lowprio_notify). * Removed the priomask block from dosched.ref.c and the H2K_lowprio_notify call site; deleted check_sanity.ref.c (H2K_check_sanity / _unlock). Callers now BKL_UNLOCK and return directly (futex_classic, futex_pi, create). * switch.ref.S: sleep path no longer writes priomask; opens imask fully; switch-in path returns via k0unlock/jumpr r31 instead of jumping to the deleted check_sanity_unlock. Retire the software runlist mirror ----------------------------------- * Removed data/runlist/ and checkers/checker_runlist/. The runlist[]/ runlist_prios[] mirror and the wip_dummy_runlist* timing shim only fed H2K_runlist_worst_prio() for software steering; nothing reads it once steering is in hardware. * Every H2K_runlist_push/_remove replaced by a direct status = H2K_STATUS_RUNNING (dosched, intpool, popup, setup boot path). futex_pi priority sync ---------------------- PI boost/restore now writes dest->prio and set_thread_stid_prio() directly (no runlist mirror). unlock_pi restores me->base_prio in software and hardware STID up front, before releasing, so the BESTWAIT comparator reads the correct priority and cannot hide the unblocked holder behind a stale boosted value. Spec-mandated synchronization ----------------------------- switch.ref.S adds isync after STID writes (V85 spec: "After updating the STID, an isync instruction must be executed to ensure that the new STID value is fully observed"). This is a correctness requirement, not removable overhead -- and the change is still faster overall (see below). CLUSTER_SCHED guards -------------------- Convert every `#ifdef CLUSTER_SCHED` to `#if CLUSTER_SCHED` so the single `#define CLUSTER_SCHED 0/1` in h2_common_defs.h actually gates the cluster/coproc code. Behavior is identical to the previously-tested build: the cluster paths were already runtime-gated by `cluster`sched == 0`, so compiling them out changes nothing observable. H2K_ready_head reduces to returning the ready-list head; getbest's sleep branch reduces to `return NULL`. Performance (futex/pi TOTAL TEST TIME, pcycles) ----------------------------------------------- ARCHV before (SW) after (HW) delta 68 1,813,302 1,731,697 -81,605 (-4.5%) 73 1,833,006 1,765,404 -67,602 (-3.7%) 81 1,968,943 1,889,073 -79,870 (-4.1%) Faster on every arch despite the added spec-mandated isyncs, from removing per-schedule software work: the runlist_worst_prio() walk, priomask bookkeeping, H2K_lowprio_notify, and the mirror writes. Follow-ups (not in this change) ------------------------------- * Rewrite the opt *.Svariants to the pure-BESTWAIT model; TARGET=opt failures are expected until then. * Research whether wait_mask is still needed for cluster scheduling; if not, drop it and its write sites in resched/intpool/popup/switch.ref.S/setup. Signed-off-by: Zeev Belinsky <zbelinsk@qti.qualcomm.com>
1 parent 5a88e2c commit a6d1ca0

99 files changed

Lines changed: 280 additions & 1523 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

kernel/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ set(
1616
"data/readylist/readylist.ref.c"
1717
"data/intconfig/intconfig.ref.c"
1818
"data/stacks/stacks.ref.S"
19-
"data/runlist/runlist.ref.c"
2019
"data/globals/globals.ref.c"
2120
"data/context/context.v${ARCHV}opt.S"
2221
"data/vm/vm.ref.c"

kernel/bugs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,3 @@ Other specing / assertions
3737
* For every data element in a struct, spec where it should be updated
3838
* Add collection of assertions that we can check on function entry/exit
3939
* Add structure verifier that can make sure structures are sane
40-
41-
42-
43-
runlist valid states
44-
====================
45-
46-
An empty runlist is apparently not a valid state; should probably
47-
document this in the spec and maybe make an assertion.
48-
49-
50-
51-
52-
53-

kernel/build/offsets/offsets.ref.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ int main(int argc, char **argv)
119119
PRINT_KG_OFFSET(hthreads_mask);
120120
PRINT_KG_OFFSET(hthreads);
121121

122-
#ifdef CLUSTER_SCHED
122+
#if CLUSTER_SCHED
123123
PRINT_KG_OFFSET(cluster_clusters);
124124
PRINT_KG_OFFSET(cluster_hthreads);
125125
PRINT_KG_OFFSET(cluster_mask);

kernel/checkers/checker_runlist/checker_runlist.check.c

Lines changed: 0 additions & 25 deletions
This file was deleted.

kernel/checkers/checker_runlist/checker_runlist.h

Lines changed: 0 additions & 14 deletions
This file was deleted.

kernel/checkers/checker_runlist/make.inc

Lines changed: 0 additions & 1 deletion
This file was deleted.

kernel/data/globals/globals.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ typedef struct {
9797
pa_t gpio_reg;
9898
#endif
9999

100-
#ifdef CLUSTER_SCHED
100+
#if CLUSTER_SCHED
101101
u32_t cluster_clusters; // number of clusters
102102
u32_t cluster_hthreads; // hardware threads per cluster
103103
u32_t cluster_mask[4]; // bitmask of threads in cluster
@@ -146,8 +146,6 @@ typedef struct {
146146
#endif
147147
H2K_thread_context *runlist[MAX_HTHREADS];
148148
s16_t runlist_prios[(MAX_HTHREADS+7)/8*8] __attribute__((aligned(8)));
149-
H2K_thread_context *wip_dummy_runlist[MAX_HTHREADS];
150-
s16_t wip_dummy_runlist_prios[(MAX_HTHREADS+7)/8*8] __attribute__((aligned(8)));
151149
H2K_vmblock_t *vmblocks[H2K_ID_MAX_VMS];
152150
u32_t phys_offset;
153151
u32_t build_id;
@@ -218,7 +216,7 @@ static inline H2K_kg_t PURITY *H2K_gp_llvm()
218216
#undef PURITY
219217
#endif
220218

221-
#ifdef CLUSTER_SCHED
219+
#if CLUSTER_SCHED
222220

223221
static inline u32_t H2K_hthread_cluster(u32_t hthread) {
224222
return (hthread / H2K_gp->cluster_hthreads);

kernel/data/globals/globals.ref.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ void H2K_kg_init(u32_t phys_offset, u32_t multicore_shift, u32_t devpage_offset,
6969
have_hvx = (H2K_cfg_table(CFG_TABLE_COPROC_TYPE) & CFG_TABLE_COPROC_TYPE_HVX_MASK) != 0;
7070
have_silver = (H2K_cfg_table(CFG_TABLE_COPROC_TYPE) & CFG_TABLE_COPROC_TYPE_SILVER_MASK) != 0;
7171
H2K_kg.coproc_contexts = (have_hvx || have_silver ? H2K_cfg_table(CFG_TABLE_COPROC_CONTEXTS) : 0);
72-
#ifdef CLUSTER_SCHED
72+
#if CLUSTER_SCHED
7373
/* FIXME: need a cfg_table entry for this */
7474
H2K_kg.cluster_clusters = (u32_t)(Q6_R_popcount_P(H2K_cfg_table(CFG_TABLE_HTHREADS_MASK)) > 8 ? 4 : 2); // hack
7575
H2K_kg.cluster_hthreads = (u32_t)(Q6_R_popcount_P(H2K_cfg_table(CFG_TABLE_HTHREADS_MASK)) / H2K_kg.cluster_clusters);
@@ -144,7 +144,7 @@ void H2K_kg_init(u32_t phys_offset, u32_t multicore_shift, u32_t devpage_offset,
144144
H2K_kg.hmx_units = (H2K_cfg_table(CFG_TABLE_HMX_INT8_RATE) != 0); // exists?
145145
H2K_kg.info_boot_flags.boot_have_hmx = (H2K_kg.hmx_units > 0);
146146
#endif
147-
#ifdef CLUSTER_SCHED
147+
#if CLUSTER_SCHED
148148
H2K_kg.coproc_max_save = ((H2K_kg.coproc_contexts + H2K_kg.hmx_units) / H2K_kg.cluster_clusters) + (((H2K_kg.coproc_contexts + H2K_kg.hmx_units) % H2K_kg.cluster_clusters) != 0);
149149
H2K_kg.coproc_max_save = (H2K_kg.coproc_max < CLUSTER_SCHED_MIN_COPROCS ? CLUSTER_SCHED_MIN_COPROCS : H2K_kg.coproc_max);
150150
#endif
@@ -230,7 +230,7 @@ void H2K_kg_init(u32_t phys_offset, u32_t multicore_shift, u32_t devpage_offset,
230230

231231
}
232232

233-
#ifdef CLUSTER_SCHED
233+
#if CLUSTER_SCHED
234234
void H2K_cluster_config(void) {
235235
u32_t i;
236236

kernel/data/readylist/readylist.h

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <globals.h>
1414
#include <hw.h>
1515
#include <log.h>
16-
#include <runlist.h>
1716

1817
/* Get the best ready priority */
1918
static inline u32_t H2K_ready_best_prio()
@@ -86,7 +85,29 @@ static inline void H2K_ready_remove(H2K_thread_context *thread)
8685
if (H2K_gp->ready[prio] == NULL) H2K_ready_clear_prio(prio);
8786
}
8887

89-
#ifdef CLUSTER_SCHED
88+
static inline void H2K_ready_append_arm(H2K_thread_context *thread)
89+
{
90+
H2K_ready_append(thread);
91+
H2K_set_bestwait(H2K_ready_best_prio());
92+
}
93+
94+
/* Take the thread and place it in the ready structure,
95+
* the first thread to be scheduled at its priority */
96+
static inline void H2K_ready_insert_arm(H2K_thread_context *thread)
97+
{
98+
H2K_ready_insert(thread);
99+
H2K_set_bestwait(H2K_ready_best_prio());
100+
}
101+
102+
/* Remove a specific thread from the ready list */
103+
/* The caller guarantees that the thread is actually in the ready list correctly */
104+
static inline void H2K_ready_remove_arm(H2K_thread_context *thread)
105+
{
106+
H2K_ready_remove(thread);
107+
H2K_set_bestwait(H2K_ready_best_prio());
108+
}
109+
110+
#if CLUSTER_SCHED
90111
static inline void H2K_update_coprocs(u32_t hthread, u32_t hthread_xe, u32_t hthread_xe2, u32_t hthread_xe3,u32_t head_xe, u32_t head_xe2, u32_t head_xe3) {
91112
xex(hthread, head_xe, head_xe2, head_xe3, hthread_xe, hthread_xe2, hthread_xe3);
92113
if (hthread_xe) {
@@ -123,7 +144,7 @@ static inline void H2K_update_coprocs(u32_t hthread, u32_t hthread_xe, u32_t hth
123144
static inline H2K_thread_context *H2K_ready_head(u32_t prio, u32_t hthread) {
124145
H2K_thread_context *head = H2K_gp->ready[prio];
125146

126-
#ifdef CLUSTER_SCHED
147+
#if CLUSTER_SCHED
127148
if ((!H2K_gp->cluster_sched) || H2K_gp->coproc_max == -1) {
128149
return head;
129150
}
@@ -223,7 +244,7 @@ static inline H2K_thread_context *H2K_ready_getbest(u32_t hthread)
223244
H2K_log("hthread %d getbest\n", hthread);
224245
prio = H2K_ready_best_prio();
225246
if (prio >= MAX_PRIOS) { // !H2K_ready_any_valid(), go to sleep
226-
#ifdef CLUSTER_SCHED
247+
#if CLUSTER_SCHED
227248
if (!H2K_gp->cluster_sched) {
228249
return NULL;
229250
}
@@ -246,7 +267,7 @@ static inline H2K_thread_context *H2K_ready_getbest(u32_t hthread)
246267

247268
ret = H2K_ready_head(prio, hthread);
248269
if (ret != NULL) {
249-
H2K_ready_remove(ret);
270+
H2K_ready_remove_arm(ret);
250271
}
251272
return ret;
252273
}

kernel/data/readylist/test/test.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ H2K_thread_context *H2K_ready_getbest_TB()
9090
return H2K_ready_getbest(CURRENT_HTHREAD);
9191
}
9292

93-
#ifdef CLUSTER_SCHED
93+
#if CLUSTER_SCHED
9494
void H2K_ready_REG_SSR_XE_CLEAR_TB()
9595
{
9696
H2K_set_ssr(H2K_get_ssr() & ~SSR_XE_BIT_MASK);
@@ -230,7 +230,7 @@ __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg));
230230
if (H2K_ready_getbest_TB() != &c) FAIL("ready_best_prio failed (c) ");
231231
if (H2K_ready_getbest_TB() != NULL) FAIL("ready_best_prio failed (empty) ");
232232

233-
# ifdef CLUSTER_SCHED
233+
# if CLUSTER_SCHED
234234

235235
u32_t hthreadmask = H2K_cfg_table(CFG_TABLE_HTHREADS_MASK);
236236
u32_t hthreads = (u32_t)Q6_R_popcount_P(hthreadmask);

0 commit comments

Comments
 (0)