SCX_CAKE · RYZEN 7 9800X3D / ZEN 5 · MEETING BRIEF · 29 SEPTEMBER 2026

Getting Cake closer
to the hardware

The CPU has fast bit operations. The opportunity is to expose them efficiently through BPF — and verify the whole scheduling path benefits.

Current source reviewed: 8fc5ec9b1 · Running kernel inspected: 7.2.8-1-cachyos · Retained experiments: September 27

Visual walkthrough: choosing CPU 3

Experimental patches ready

The kernel and optional Cake patches are built. VM JIT dumps confirm TZCNT and POPCNT; native and fallback paths pass the differential and register-preservation checks. Hardware performance and Cake native-mode activation remain unmeasured. Patches, Kernel Manager instructions, validation and wall-clock runner.

JIT investigation update

The kernel’s JIT selects native instructions, but Clang has already expanded the bit-count operation into BPF arithmetic. Fresh Clang 22.1.8 probes show 9 BPF operations for nonzero CTZ and 19 for population count; compiling the same C for Zen 5 gives TZCNT and POPCNT directly. The inspected reference JIT does not recognize and collapse those sequences.

The installed kernel ELF matches the running build ID and BTF. Actual Cake native JIT output is still unavailable: direct BPF inspection is permission-blocked. Full investigation, disassembly and implementation options.

Each bit represents a CPU. A 1 means that CPU survived Cake’s eligibility and preference checks. In this example, CPUs 3, 5 and 7 remain.

CPU number       7 6 5 4 3 2 1 0
Candidate mask   1 0 1 0 1 0 0 0
                         ↑ └───┘
                      CPU 3  three trailing zeros

Result: trailing-zero count = 3 → try to claim CPU 3
Scheduling path

Wakeup / enqueue / pool-work search
↓
Find idle CPUs allowed for this task and relevant LLC
↓
Prefer capacity, whole cores, unreserved seats, quieter CPUs and platform rank
↓
Count trailing zeros of the surviving bitmap
↓
Atomically try to claim that CPU
↓
Success: use it. Failure: remove its bit and try another candidate.

The source line in cake_pick_cold() is:

return (s32)__builtin_ctzll(
    cake_rank_tier(cake_prefer_irq_clean(best, noisy)));

The builtin states the desired calculation. It does not force the BPF backend to emit an x86 TZCNT instruction.

Software route · captured BPF

  1. Copy the candidate mask.
  2. Negate the copy.
  3. AND with the original: isolate the lowest 1 bit.
  4. Load a special constant.
  5. Multiply the isolated bit by that constant.
  6. Shift right by 58: produce a table index.
  7. Load the lookup table’s address.
  8. Add the index to the address.
  9. Load the byte containing the CPU number.

10101000 → 00001000 → index → table[index] → 3

This multiplication-and-table method is a de Bruijn bit scan. The table maps each possible single-bit position to its bit number.

Proposed inline hardware route

tzcnt result, mask

The CPU’s dedicated bit-count hardware directly returns the number of zeros below the lowest set bit.

10101000 → TZCNT → 3

No software multiplication, lookup-table address calculation or lookup-table memory read for the bit scan.

One native instruction for the core operation. Argument/result moves or surrounding spills can still add work. This is not an ordinary function call.

Why we said 12, and the more precise count

The retained standalone CTZ benchmark has 12 x86 instructions: initialize the zero-input result, compare against zero, branch if zero, then the nine scan operations. Cake’s captured nonempty path omits those three zero-input instructions. Its nine BPF operations are not a verified count of today’s final native code.

The earlier generic claim that CTZ’s count included an exit jump was incorrect: this generated CTZ block has no exit jump. The benchmark’s dependency-feeding ADD is separate from the 12-instruction count.

Only the highlighted bit scan gets replaced. Cake still needs the same CPU eligibility checks, ranking policy, atomic claim and race retry. POPCNT has a similar opportunity, replacing software bit arithmetic when counting idle CPUs; LZCNT belongs to the separate proposed division-replacement experiment.

Why LZCNT was wanted

To make an exact division-free slice calculation practical.

Cake computes q = work / n, where n comes from the task’s voluntary-switch count. The earlier work explored finding the divisor’s magnitude with a leading-zero count, then using normalization, a reciprocal/table, and multiplication/refinement to recover the exact quotient.

LZCNT accelerates normalization. It does not calculate the quotient. The retained prototype measures normalization only; a complete faster exact quotient was not demonstrated.

No direct CLZ use was found in current Cake. The earlier suggestion that LZCNT was wanted for highest-bit CPU selection did not capture the actual rationale.

Immediate application

TZCNT · choose a CPU

Cake already uses trailing-zero counts to select a CPU from a bitmap and in its irregular SMT-map fallback.

Immediate application

POPCNT · count idle CPUs

Cake already counts set bits to determine whether at least three quarters of an LLC’s CPUs are idle.

Enables an experiment

LZCNT · normalize a divisor

Potentially removes an expensive software step from a proposed reciprocal-based quotient. Remaining arithmetic and exactness still need validation.

Which fast paths deserve attention?

MechanismCake relevanceAssessment
TZCNT / POPCNTCPU bitmap selection; idle censusStrongest direct bitops candidates. Historical loaded BPF shows software bit operations. Compare inlined native operations including moves and spills.
LZCNTProposed exact slice/burst quotientPromising normalization primitive; no complete quotient win yet.
High multiply · MUL / MULXExact wide starvation cross-products; reciprocal arithmeticBPF low-product multiply does not provide the high half. Native high multiply could replace limb arithmetic. Current cross-products can wrap: correctness matters too.
Carry / borrow · ADC / SBBMultiword arithmetic and comparisonSupporting capability for exact wide math. No complete Cake speedup demonstrated.
Conditional move / min-maxRanking and capsNot automatically better than branches. Retained predictable-branch test beat the CMOV chain.
Rotate / prefetchPossible traversal or remote-state designsLower priority; no demonstrated hot rotate site or useful prefetch path. Prefetch needs valid pointers and lead time.
Atomic bit updatesQueue, idle, seat and frontier stateFetching the old value for AND/OR/XOR can require a CMPXCHG retry loop. Non-fetch forms can use a locked instruction. Cake already uses several efficient forms.
Multiply / shifts / divideAccounting and slice arithmeticAlready map to hardware operations in the reference JIT. Division is native DIV/IDIV with setup, not software division.
Helpers / DSQ operationsCPU ID, clocks, lookup, queue movementSome helpers already inline; historical CPU ID does. DSQ lookup, locks and migration are separate kernel-service costs, not missing ALU instructions.

What the retained experiments actually show

September 27, three-run cakesim medians. These are userspace timings of custom-translated BPF with explicit what-if instruction substitutions — not an installed kernel patch or whole-callback measurements.

Primitive / variantIndependent callsDependent chainMeaning
Hardware quotient0.577 ns1.903 nsComplete a / (n | 1) primitive
BPF CLZ normalization1.382 ns4.333 nsNormalization only
Byte-table normalization2.152 ns2.716 nsNormalization only
What-if native LZCNT0.722 ns0.536 nsNormalization only; quotient work remains
CPU picker → native TZCNT2.032 → 1.967 ns3.214 → 1.673 nsSimulated picker, not all of select_cpu
Idle census → native POPCNT1.744 → 1.319 ns1.221 → 0.870 nsSimulated census

Independent operations overlap; dependent chains wait for the previous result. The difference matters when a CPU index feeds the next scheduling operation.

Evidence limits found during review

  • All 16 retained native JIT dump files contain retrieval errors. The translated BPF dumps are valid and show software population count.
  • The raw instruction microbenchmark includes dependency-feeding instructions. Its printed “cycles” are ADD-calibrated chain costs, not isolated hardware-counter latency.
  • The 16-bit census table fails the general test domain. It requires a proven low-16-bit CPU mask and a portable fallback.
  • No new scheduler activation or performance test was run for this review. No FPS or input-latency gain is claimed.

One instruction at which layer?

C expression → LLVM BPF → verifier → x86 JIT → CPU µops

Native code can still contain a long emulation sequence. One x86 instruction can contain multiple µops. Latency and reciprocal throughput are different measurements.

BPF expansion

The compiler emits shifts, masks and arithmetic. The JIT turns that sequence into native instructions.

Ordinary kfunc

A native function contains the operation, but calling it can add moves, spills, call and return costs.

JIT-inlined kfunc

The JIT substitutes the dedicated instruction. Surrounding argument/result moves and spills still need checking.

The host advertises ABM, BMI1, BMI2 and POPCNT. Its inspected vmlinux BTF does not expose the proposed bpf_clz64, bpf_ctz64, or bpf_popcnt64. This is a BPF access-path question, not missing CPU hardware.

Published Zen 5 register-to-register LZCNT and POPCNT measurements report one executed µop and one-cycle input-to-result latency. These are architecture reference measurements, separate from Cake’s full expression costs.

Concrete meeting questions

  1. Can shared BPF bitops provide JIT-inlined CTZ, POPCNT and CLZ with portable fallbacks and useful verifier bounds?
  2. Can the compiler and JIT avoid call-ABI spills around those operations?
  3. Should unsigned high multiply be considered alongside bitops for exact wide comparisons and reciprocal arithmetic?
  4. Can we compare the complete exact quotient against native division, rather than compare normalization alone?
  5. Which costs belong in separate DSQ, clock, locking or migration fast-path work?

Other schedulers can benefit when they perform bitmap selection, priority-bucket searches, population counts or wide arithmetic. Shared BPF support also benefits programs outside sched_ext; the gain depends on actual use and generated code.

References and retained evidence