#include <scx/common.bpf.h>
#include <scx/compat.bpf.h>
#include <lib/arena_map.h>
#include <lib/sdt_task.h>
#include "intf.h"
#include "bpf_compat.h"
char _license[] SEC("license") = "GPL";
const u64 quantum_ns = CAKE_DEFAULT_QUANTUM_NS;
const u64 new_flow_bonus_ns = CAKE_DEFAULT_NEW_FLOW_BONUS_NS;
const u64 aq_yielder_ceiling_ns = AQ_YIELDER_CEILING_NS;
const u64 aq_min_ns = AQ_MIN_NS;
const u32 preempt_vip_ns = CAKE_PREEMPT_VIP_THRESHOLD_NS;
const u32 preempt_yielder_ns = CAKE_PREEMPT_YIELDER_THRESHOLD_NS;
const u32 tier_base[4] = { 8192, 0, 49152, 32768 };
const u32 rt_cost_cap[4] = { 4096, 4096, 4096, 4096 };
const u32 preempt_thresh_ns[4] = { 100000, 50000, 100000, 100000 };
#ifdef CAKE_RELEASE
#define CAKE_STATS_ENABLED 0
#else
const bool enable_stats __attribute__((used)) = false;
#define CAKE_STATS_ENABLED (*(volatile const bool *)&enable_stats)
#endif
#define CAKE_STATS_ACTIVE (CAKE_STATS_ENABLED && !bench_active)
const bool enable_dvfs =
false;
const u32 nr_llcs = 1;
const u32 nr_cpus = 8;
const u32 nr_phys_cpus =
8;
const u32 nr_nodes = 1;
const u32 cpu_llc_id[CAKE_MAX_CPUS] = {};
const u32 cpuperf_cap_table[CAKE_MAX_CPUS] = {};
const u8 cpus_fast_to_slow[CAKE_MAX_CPUS] = {};
const u8 cpus_slow_to_fast[CAKE_MAX_CPUS] = {};
const u64 llc_cpu_mask[CAKE_MAX_LLCS] = {};
const u64 core_cpu_mask[32] = {};
const u8 cpu_sibling_map[CAKE_MAX_CPUS] = {};
u32 bench_xorshift_state = 0xDEADBEEF;
#define CAKE_CPU_MASK_WORDS (CAKE_MAX_CPUS / 64)
const u64 big_core_phys_mask[CAKE_CPU_MASK_WORDS] = {};
const u64 big_core_smt_mask[CAKE_CPU_MASK_WORDS] = {};
const u64 little_core_mask[CAKE_CPU_MASK_WORDS] = {};
const u64 vcache_llc_mask[CAKE_CPU_MASK_WORDS] = {};
const bool has_vcache = false;
const bool has_hybrid_cores = false;
const u32 nr_audio_tgids = 0;
const u32 audio_tgids[CAKE_MAX_AUDIO_TGIDS] = {};
const u32 nr_compositor_tgids = 0;
const u32 compositor_tgids[CAKE_MAX_COMPOSITOR_TGIDS] = {};
struct cake_per_cpu {
struct mega_mailbox_entry
mbox;
} __attribute__((aligned(CAKE_MBOX_ALIGN)));
_Static_assert(sizeof(struct cake_per_cpu) == CAKE_MBOX_SIZE,
"cake_per_cpu must match CAKE_MBOX_SIZE for per-CPU isolation");
struct cake_per_cpu __arena *per_cpu;
struct cake_stats global_stats[CAKE_MAX_CPUS] SEC(".bss")
__attribute__((aligned(256)));
u8 __bss_tail_guard[64] SEC(".bss") __attribute__((aligned(64)));
#define ARENA_ASSOC() asm volatile("" : : "r"(&arena))
static __always_inline struct cake_stats *get_local_stats(void)
{
#ifndef CAKE_RELEASE
asm volatile("" : : "r"(enable_stats) : "memory");
#endif
u32 cpu = bpf_get_smp_processor_id();
return &global_stats[cpu & (CAKE_MAX_CPUS - 1)];
}
static __always_inline struct cake_stats *get_local_stats_for(u32 cpu)
{
return &global_stats[cpu & (CAKE_MAX_CPUS - 1)];
}
UEI_DEFINE(uei);
u32 bench_request = 0;
u32 bench_active = 0;
struct kfunc_bench_results bench_results = {};
u32 game_tgid __attribute__((aligned(64))) = 0;
u32 game_ppid = 0;
u32 sched_state = CAKE_STATE_IDLE;
u64 quantum_ceiling_ns = 0;
u8 game_confidence = 0;
#define PID_CLASS_CACHE_SIZE 4096
static u8 pid_class_cache[PID_CLASS_CACHE_SIZE];
static u64 game_cpu_mask[CAKE_CPU_MASK_WORDS];
struct cake_cpu_bss cpu_bss[CAKE_MAX_CPUS];
u8 dsq_kick_needed[CAKE_MAX_LLCS];
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 4096);
} bench_ringbuf SEC(".maps");
struct bench_task_val {
u64 dummy;
};
struct {
__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, int);
__type(value, struct bench_task_val);
} bench_task_storage SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_TASK_STORAGE);
__uint(map_flags, BPF_F_NO_PREALLOC);
__type(key, int);
__type(value, struct cake_task_hot);
} task_hot_stor SEC(".maps");
struct bench_lock_data {
struct bpf_spin_lock lock;
u64 counter;
};
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, u32);
__type(value, struct bench_lock_data);
} bench_lock_map SEC(".maps");
#define BENCH_ONE(entry, call_expr, idx) do { \
u64 _s = bpf_ktime_get_ns(); \
u64 _v = (u64)(call_expr); \
u64 _e = bpf_ktime_get_ns(); \
u64 _d = _e - _s; \
if (_d < (entry)->min_ns) (entry)->min_ns = _d; \
if (_d > (entry)->max_ns) (entry)->max_ns = _d; \
(entry)->total_ns += _d; \
(entry)->last_value = _v; \
(entry)->samples[idx] = _d; \
} while (0)
static __always_inline void run_kfunc_bench(struct kfunc_bench_results *r,
struct task_struct *p);
static __always_inline struct cake_task_ctx __arena *
get_task_ctx(struct task_struct *p);
static __always_inline void run_kfunc_bench(struct kfunc_bench_results *r,
struct task_struct *p)
{
*(volatile u32 *)&bench_active = 1;
r->cpu = bpf_get_smp_processor_id();
r->iterations = BENCH_ITERATIONS;
#pragma unroll
for (int i = 0; i < BENCH_MAX_ENTRIES; i++) {
r->entries[i].min_ns = ~0ULL;
r->entries[i].max_ns = 0;
r->entries[i].total_ns = 0;
r->entries[i].last_value = 0;
}
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_KTIME_GET_NS], bpf_ktime_get_ns(), i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_BPF_NOW], scx_bpf_now(), i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_GET_SMP_PROC_ID], bpf_get_smp_processor_id(), i);
{
s32 pid = p->pid;
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
struct task_struct *t = bpf_task_from_pid(pid);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
if (t) bpf_task_release(t);
struct kfunc_bench_entry *e = &r->entries[BENCH_TASK_FROM_PID];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)(t != NULL);
}
}
{
u32 cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
bool idle = scx_bpf_test_and_clear_cpu_idle(cpu);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_TEST_CLEAR_IDLE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)idle;
}
}
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_NR_CPU_IDS], scx_bpf_nr_cpu_ids(), i);
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
struct cake_task_ctx __arena *t = get_task_ctx(p);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_GET_TASK_CTX];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)(t != NULL);
}
}
{
u64 dsq_id = LLC_DSQ_BASE + cpu_llc_id[r->cpu & (CAKE_MAX_CPUS - 1)];
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
s32 nr = scx_bpf_dsq_nr_queued(dsq_id);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_DSQ_NR_QUEUED];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)nr;
}
}
{
u32 bcpu = r->cpu & (CAKE_MAX_CPUS - 1);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 v = global_stats[bcpu].total_stopping_ns;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_BSS_ARRAY_ACCESS];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = v;
}
}
#ifndef CAKE_RELEASE
{
ARENA_ASSOC();
u32 bcpu = r->cpu & (CAKE_MAX_CPUS - 1);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 v = per_cpu[bcpu].mbox.tick_slice;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_ARENA_DEREF];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = v;
}
}
#endif
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_NOW_PAIR];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = _d;
}
#ifndef CAKE_RELEASE
{
u32 bcpu = r->cpu & (CAKE_MAX_CPUS - 1);
struct mega_mailbox_entry __arena *mbox = &per_cpu[bcpu].mbox;
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u32 v = mbox->tick_last_run_at;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_MBOX_CPU_READ];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = v;
}
}
#endif
#ifndef CAKE_RELEASE
{
u32 bcpu = r->cpu & (CAKE_MAX_CPUS - 1);
struct mega_mailbox_entry __arena *mbox = &per_cpu[bcpu].mbox;
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (tctx) {
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 ptr_val = mbox->tick_slice;
volatile u16 field = tctx->deficit_u16;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_TCTX_FROM_MBOX];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = field + (u32)ptr_val;
}
}
}
#endif
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
void *slot = bpf_ringbuf_reserve(&bench_ringbuf, 8, 0);
if (slot)
bpf_ringbuf_discard(slot, 0);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_RINGBUF_CYCLE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)(slot != NULL);
}
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 sl = p->scx.slice;
volatile u64 nv = p->nvcsw;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_TASK_STRUCT_READ];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = sl + nv;
}
}
{
u32 bcpu = r->cpu & (CAKE_MAX_CPUS - 1);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u32 llc = cpu_llc_id[bcpu];
volatile u64 ts = quantum_ns;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_RODATA_LOOKUP];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = ts + llc;
}
}
{
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (tctx) {
u32 packed = tctx->packed_info;
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
u32 yl_mask = (u32)CAKE_FLOW_YIELDER << SHIFT_FLAGS;
volatile u32 result = (packed & ~yl_mask) | (yl_mask & -(u32)1);
volatile u8 nf = (result >> SHIFT_FLAGS) & 1;
volatile u8 yl = (result >> SHIFT_FLAGS) & (u32)CAKE_FLOW_YIELDER;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_BITFLAG_OPS];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = nf + yl + result;
}
}
}
{
s32 ewma_cpu = bpf_get_smp_processor_id();
u64 tick_sl_bss = cpu_bss[ewma_cpu & (CAKE_MAX_CPUS - 1)].tick_slice;
u32 fused_val = 0x00C80064;
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
u64 tick_sl = tick_sl_bss;
u64 rem_sl = p->scx.slice;
u16 old_avg = (u16)(fused_val >> 16);
u16 deficit = (u16)(fused_val & 0xFFFF);
u64 used = (tick_sl > rem_sl) ? (tick_sl - rem_sl) : 0;
u16 rt_us = (u16)(used >> 10);
volatile u16 new_avg = (old_avg * 7 + rt_us) >> 3;
volatile u16 new_def = (deficit > rt_us) ? deficit - rt_us : 0;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_RESERVED_17];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = new_avg + new_def;
}
}
#ifndef CAKE_RELEASE
{
ARENA_ASSOC();
u32 bcpu = r->cpu & (CAKE_MAX_CPUS - 1);
struct mega_mailbox_entry __arena *mbox = &per_cpu[bcpu].mbox;
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 ptr = mbox->cached_tctx_ptr;
volatile u32 fused = mbox->cached_deficit;
volatile u32 packed = mbox->cached_packed;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_PSYCHIC_HIT_SIM];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = ptr + fused + packed;
}
}
#endif
{
u32 local_cpu = bpf_get_smp_processor_id();
s32 remote_cpu = (s32)((local_cpu ^ 1) & (CAKE_MAX_CPUS - 1));
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
bool idle = scx_bpf_test_and_clear_cpu_idle(remote_cpu);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_IDLE_REMOTE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)idle;
}
}
{
u32 local_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
const struct cpumask *smtmask = scx_bpf_get_idle_smtmask();
volatile bool fully_idle = bpf_cpumask_test_cpu(local_cpu, smtmask);
scx_bpf_put_idle_cpumask(smtmask);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_IDLE_SMTMASK];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)fully_idle;
}
}
#ifndef CAKE_RELEASE
{
u32 local_cpu = bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1);
struct mega_mailbox_entry __arena *mbox = &per_cpu[local_cpu].mbox;
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 _ptr = mbox->cached_tctx_ptr;
volatile u32 _fused = mbox->cached_deficit;
volatile u32 _packed = mbox->cached_packed;
volatile u64 _nvcsw = mbox->cached_nvcsw;
volatile u64 _slice = mbox->tick_slice;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_DISRUPTOR_READ];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = _ptr + _fused + _packed + _nvcsw + _slice;
}
}
#endif
{
struct task_struct *cur = bpf_get_current_task_btf();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
struct cake_task_ctx __arena *tctx = get_task_ctx(cur);
volatile u32 _packed = tctx ? tctx->packed_info : 0;
volatile u16 _fused = tctx ? tctx->deficit_u16 : 0;
volatile u64 _nvcsw = tctx ? tctx->nvcsw_snapshot : 0;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_TCTX_COLD_SIM];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = _packed + _fused + _nvcsw;
}
}
#ifndef CAKE_RELEASE
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 sum = 0;
#pragma unroll
for (int c = 0; c < 16; c++) {
sum += per_cpu[c & (CAKE_MAX_CPUS - 1)].mbox.tick_last_run_at;
}
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_ARENA_STRIDE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = sum;
}
}
#endif
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_KTIME_BOOT_NS], bpf_ktime_get_boot_ns(), i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_CURRENT_PID_TGID], bpf_get_current_pid_tgid(), i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_CURRENT_TASK_BTF], (u64)bpf_get_current_task_btf(), i);
{
char comm[16];
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
long ret = bpf_get_current_comm(comm, sizeof(comm));
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_CURRENT_COMM];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)ret;
}
}
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_NUMA_NODE_ID], bpf_get_numa_node_id(), i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_TASK_RUNNING], scx_bpf_task_running(p), i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_TASK_CPU], scx_bpf_task_cpu(p), i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_NR_NODE_IDS], scx_bpf_nr_node_ids(), i);
{
s32 bench_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_CPUPERF_CUR], scx_bpf_cpuperf_cur(bench_cpu), i);
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
struct bench_task_val *v = bpf_task_storage_get(
&bench_task_storage, p, NULL, BPF_LOCAL_STORAGE_GET_F_CREATE);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_TASK_STORAGE_GET];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = v ? v->dummy : 0;
}
}
{
const struct cpumask *online = scx_bpf_get_online_cpumask();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_PICK_IDLE_CPU],
scx_bpf_pick_idle_cpu(online, 0), i);
scx_bpf_put_cpumask(online);
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
const struct cpumask *idle = scx_bpf_get_idle_cpumask();
scx_bpf_put_idle_cpumask(idle);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_SCX_IDLE_CPUMASK];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = 0;
}
}
{
s32 self_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_KICK_CPU],
(scx_bpf_kick_cpu(self_cpu, 0), 0), i);
}
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_PRANDOM_U32], bpf_get_prandom_u32(), i);
{
u32 key = 0;
struct bench_lock_data *ld = bpf_map_lookup_elem(&bench_lock_map, &key);
if (ld) {
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
bpf_spin_lock(&ld->lock);
ld->counter++;
bpf_spin_unlock(&ld->lock);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_SPIN_LOCK];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = ld->counter;
}
}
}
{
s32 cap_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_SCX_CPUPERF_CAP], scx_bpf_cpuperf_cap(cap_cpu), i);
}
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_RODATA_NR_CPUS], (u64)nr_cpus, i);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_RODATA_NR_NODES], (u64)nr_nodes, i);
{
s32 perf_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_RODATA_CPUPERF_CAP],
(u64)cpuperf_cap_table[perf_cpu & (CAKE_MAX_CPUS - 1)], i);
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 cached_pid = ((u64)p->tgid << 32) | p->pid;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_ARENA_PID_TGID];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = cached_pid;
}
}
#ifndef CAKE_RELEASE
{
s32 mbox_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_MBOX_TASK_CPU],
(u64)per_cpu[mbox_cpu & (CAKE_MAX_CPUS - 1)].mbox.cached_cpu, i);
}
#endif
#ifndef CAKE_RELEASE
{
s32 lf_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 lf_val =
per_cpu[lf_cpu & (CAKE_MAX_CPUS - 1)].mbox.cached_cpu +
per_cpu[lf_cpu & (CAKE_MAX_CPUS - 1)].mbox.tick_tier +
cpu_bss[lf_cpu & (CAKE_MAX_CPUS - 1)].is_yielder;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_CL0_LOCKFREE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = lf_val;
}
}
#endif
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
u32 x = bench_xorshift_state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
bench_xorshift_state = x;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_BSS_XORSHIFT];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)x;
}
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 util = p->se.avg.util_avg;
volatile u64 runnable = p->se.avg.runnable_avg;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_PELT_UTIL_AVG];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (util << 16) | runnable;
}
}
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++)
BENCH_ONE(&r->entries[BENCH_PELT_RUNNABLE_AVG], p->se.avg.runnable_avg, i);
#ifndef CAKE_RELEASE
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 wakeups = p->stats.nr_wakeups;
volatile u64 wakeups_sync = p->stats.nr_wakeups_sync;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_SCHEDSTATS_WAKEUPS];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (wakeups << 32) | wakeups_sync;
}
}
#endif
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u32 policy = p->policy;
volatile u32 prio = p->prio;
volatile u32 flags = p->flags;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_TASK_POLICY_FLAGS];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = ((u64)policy << 32) | ((u64)prio << 16) | (flags & 0xFFFF);
}
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
u64 util = p->se.avg.util_avg;
volatile u8 tier = (util > 512) ? 2 : ((util > 128) ? 1 : 0);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_PELT_VS_EWMA];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = ((u64)tier << 32) | util;
}
}
{
s32 bss_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
cpu_bss[bss_cpu & (CAKE_MAX_CPUS - 1)].idle_hint = 1;
cpu_bss[bss_cpu & (CAKE_MAX_CPUS - 1)].is_yielder = 0;
cpu_bss[bss_cpu & (CAKE_MAX_CPUS - 1)].run_start = 12345678ULL;
asm volatile("" ::: "memory");
volatile u8 hint = cpu_bss[bss_cpu & (CAKE_MAX_CPUS - 1)].idle_hint;
volatile u8 yielder = cpu_bss[bss_cpu & (CAKE_MAX_CPUS - 1)].is_yielder;
volatile u64 start = cpu_bss[bss_cpu & (CAKE_MAX_CPUS - 1)].run_start;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_STORAGE_ROUNDTRIP];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = hint + yielder + start;
}
}
#ifndef CAKE_RELEASE
{
s32 ar_cpu = bpf_get_smp_processor_id();
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
per_cpu[ar_cpu & (CAKE_MAX_CPUS - 1)].mbox.tick_last_run_at = 0xCAFEBABE;
asm volatile("" ::: "memory");
volatile u64 readback = per_cpu[ar_cpu & (CAKE_MAX_CPUS - 1)].mbox.tick_last_run_at;
volatile u32 tier = per_cpu[ar_cpu & (CAKE_MAX_CPUS - 1)].mbox.tick_tier;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_ARENA_ROUNDTRIP];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = readback + tier;
}
}
#endif
{
s32 self = bpf_get_smp_processor_id();
s32 sib = cpu_sibling_map[self & (CAKE_MAX_CPUS - 1)];
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile bool prev_idle = scx_bpf_test_and_clear_cpu_idle(self);
volatile u8 sib_idle = cpu_bss[sib & (CAKE_MAX_CPUS - 1)].idle_hint;
volatile u8 home_idle = cpu_bss[self & (CAKE_MAX_CPUS - 1)].idle_hint;
volatile s32 result = prev_idle ? self :
(sib_idle ? sib : (home_idle ? self : -1));
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_CASCADE_VS_PICK];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)result;
}
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
s32 found_cpu = scx_bpf_pick_idle_cpu(p->cpus_ptr, 0);
volatile bool valid = (found_cpu >= 0) &&
bpf_cpumask_test_cpu(found_cpu, p->cpus_ptr);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_PICK_IDLE_FULL];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = (u64)found_cpu + (u64)valid;
}
}
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u32 weight = p->scx.weight;
volatile u64 vtime_offset = (40ULL * 1000000ULL * 100ULL) /
(weight ? weight : 1);
volatile u64 slice = (5000000ULL * 100ULL) /
(weight ? weight : 1);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_CLASSIFY_WEIGHT];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = vtime_offset + slice;
}
}
#ifndef CAKE_RELEASE
{
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile u64 wakeups = p->stats.nr_wakeups;
volatile u64 sync_wakeups = p->stats.nr_wakeups_sync;
volatile u64 nvcsw = p->nvcsw;
volatile u64 nivcsw = p->nivcsw;
u64 total = wakeups ? wakeups : 1;
volatile u64 sync_ratio = (sync_wakeups * 1000) / total;
volatile u64 cs_ratio = (nvcsw * 1000) / (nvcsw + nivcsw + 1);
volatile u64 lat_score = sync_ratio + cs_ratio;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_CLASSIFY_LATCRI];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = lat_score;
}
}
#endif
{
s32 self_cpu = bpf_get_smp_processor_id();
s32 sib_cpu = cpu_sibling_map[self_cpu & (CAKE_MAX_CPUS - 1)];
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
volatile bool sib_idle = scx_bpf_test_and_clear_cpu_idle(
sib_cpu & (CAKE_MAX_CPUS - 1));
volatile u8 hint = cpu_bss[sib_cpu & (CAKE_MAX_CPUS - 1)].idle_hint;
volatile bool should_use = sib_idle || hint;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_SMT_CAKE_PROBE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = should_use;
}
}
{
s32 smt_cpu = bpf_get_smp_processor_id();
s32 smt_sib = cpu_sibling_map[smt_cpu & (CAKE_MAX_CPUS - 1)];
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
const struct cpumask *idle_smt = scx_bpf_get_idle_smtmask();
volatile bool sib_fully_idle =
bpf_cpumask_test_cpu(smt_sib & (CAKE_MAX_CPUS - 1), idle_smt);
scx_bpf_put_idle_cpumask(idle_smt);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_SMT_CPUMASK_PROBE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = sib_fully_idle;
}
}
#ifndef CAKE_RELEASE
{
ARENA_ASSOC();
u32 ccpu = r->cpu & (CAKE_MAX_CPUS - 1);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
volatile u64 sink = 0;
#pragma unroll
for (int j = 0; j < 16; j++) {
u32 idx = (ccpu + j + 1) & (CAKE_MAX_CPUS - 1);
sink += per_cpu[idx].mbox.cached_cpu;
}
u64 _s = bpf_ktime_get_ns();
struct cake_task_hot *hot_cold = bpf_task_storage_get(
&task_hot_stor, p, 0, 0);
volatile u16 cold_val = hot_cold ? hot_cold->deficit_u16 : 0;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_STORAGE_GET_COLD];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = cold_val + sink;
}
}
#endif
#ifndef CAKE_RELEASE
{
ARENA_ASSOC();
u32 ccpu2 = r->cpu & (CAKE_MAX_CPUS - 1);
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
volatile u64 sink2 = 0;
#pragma unroll
for (int j = 0; j < 16; j++) {
u32 idx = (ccpu2 + j + 1) & (CAKE_MAX_CPUS - 1);
sink2 += per_cpu[idx].mbox.tick_slice;
}
u64 _s = bpf_ktime_get_ns();
u64 util_cold = p->se.avg.util_avg;
volatile u8 tier = (util_cold > 600) ? 2 : (util_cold > 200) ? 1 : 0;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_PELT_COLD];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = tier + sink2;
}
}
#endif
#ifndef CAKE_RELEASE
{
u32 ewma_c = bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1);
ARENA_ASSOC();
u32 fused_c = 0x00C80064;
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
volatile u64 sink3 = 0;
#pragma unroll
for (int j = 0; j < 16; j++) {
u32 idx = (ewma_c + j + 1) & (CAKE_MAX_CPUS - 1);
sink3 += per_cpu[idx].mbox.cached_deficit;
}
u64 _s = bpf_ktime_get_ns();
u64 tick_c = cpu_bss[ewma_c].tick_slice;
u64 rem_c = p->scx.slice;
u16 oavg = (u16)(fused_c >> 16);
u16 odef = (u16)(fused_c & 0xFFFF);
u64 used_c = (tick_c > rem_c) ? (tick_c - rem_c) : 0;
u16 rt_c = (u16)(used_c >> 10);
volatile u16 navg = (oavg * 7 + rt_c) >> 3;
volatile u16 ndef = (odef > rt_c) ? odef - rt_c : 0;
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_EWMA_COLD];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = navg + ndef + sink3;
}
}
#endif
{
s32 kick_cpu = bpf_get_smp_processor_id();
s32 kick_sib = cpu_sibling_map[kick_cpu & (CAKE_MAX_CPUS - 1)];
#pragma unroll
for (int i = 0; i < BENCH_ITERATIONS; i++) {
u64 _s = bpf_ktime_get_ns();
scx_bpf_kick_cpu(kick_sib & (CAKE_MAX_CPUS - 1), 0);
u64 _e = bpf_ktime_get_ns();
u64 _d = _e - _s;
struct kfunc_bench_entry *e = &r->entries[BENCH_KICK_REMOTE];
if (_d < e->min_ns) e->min_ns = _d;
if (_d > e->max_ns) e->max_ns = _d;
e->total_ns += _d;
e->samples[i] = _d;
e->last_value = kick_sib;
}
}
r->bench_timestamp = bpf_ktime_get_ns();
*(volatile u32 *)&bench_active = 0;
}
static __always_inline struct cake_task_ctx __arena *
get_task_ctx(struct task_struct *p)
{
return (struct cake_task_ctx __arena *)scx_task_data(p);
}
static __always_inline struct cake_task_hot *
get_task_hot(struct task_struct *p)
{
return bpf_task_storage_get(&task_hot_stor, p, 0, 0);
}
static __noinline s32 select_cpu_dfl_idle(
struct task_struct *p, s32 prev_cpu, u64 wake_flags)
{
bool is_idle = false;
s32 cpu = scx_bpf_select_cpu_dfl(p, prev_cpu, wake_flags, &is_idle);
return is_idle ? cpu : -1;
}
static __noinline s32 select_cpu_and_idle(
struct task_struct *p, s32 prev_cpu, u64 wake_flags,
u64 enq_flags)
{
return scx_bpf_select_cpu_and(p, prev_cpu, wake_flags,
p->cpus_ptr, enq_flags);
}
s32 BPF_STRUCT_OPS(cake_select_cpu, struct task_struct *p, s32 prev_cpu,
u64 wake_flags)
{
#ifndef CAKE_RELEASE
ARENA_ASSOC();
#endif
#ifndef CAKE_RELEASE
bool stats_on = CAKE_STATS_ACTIVE;
u64 start_time = 0;
if (stats_on)
start_time = scx_bpf_now();
#else
#define stats_on 0
u64 start_time = 0;
#endif
if (cpu_bss[prev_cpu & (CAKE_MAX_CPUS - 1)].sched_state_local == CAKE_STATE_GAMING)
wake_flags &= ~SCX_WAKE_SYNC;
if (!__COMPAT_HAS_scx_bpf_select_cpu_and) {
s32 cpu = select_cpu_dfl_idle(p, prev_cpu, wake_flags);
if (cpu >= 0) {
u64 slice = p->scx.slice ?: quantum_ns;
scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL_ON | cpu,
slice, wake_flags);
return cpu;
}
goto gate2;
}
{
s32 cpu = select_cpu_and_idle(p, prev_cpu, wake_flags, 0);
if (cpu >= 0) {
u64 slice = p->scx.slice ?: quantum_ns;
scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL_ON | cpu,
slice, wake_flags);
if (stats_on) {
struct cake_stats *s = get_local_stats();
s->total_gate1_latency_ns += scx_bpf_now() - start_time;
#ifndef CAKE_RELEASE
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (tctx) {
tctx->telemetry.gate_1_hits++;
tctx->telemetry.direct_dispatch_count++;
if (cpu != prev_cpu)
tctx->telemetry.migration_count++;
}
#endif
}
return cpu;
}
}
gate2:
if (has_hybrid_cores) {
u8 g2_tc = pid_class_cache[p->pid & (PID_CLASS_CACHE_SIZE - 1)];
bool is_game = (g2_tc == CAKE_CLASS_GAME);
const u8 *scan_order = is_game
? cpus_fast_to_slow
: cpus_slow_to_fast;
for (u32 i = 0; i < CAKE_MAX_CPUS && i < nr_cpus; i++) {
u8 candidate = scan_order[i];
if (candidate >= nr_cpus)
break;
u8 sib = cpu_sibling_map[candidate & (CAKE_MAX_CPUS - 1)];
if (sib < nr_cpus && sib != candidate) {
bool sib_game = (game_cpu_mask[sib >> 6] >> (sib & 63)) & 1;
if (is_game ^ sib_game)
continue;
}
if (scx_bpf_test_and_clear_cpu_idle(candidate)) {
u64 slice = p->scx.slice ?: quantum_ns;
scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL_ON | candidate,
slice, wake_flags);
return candidate;
}
}
}
#ifdef CAKE_RELEASE
#undef stats_on
#endif
return prev_cpu;
}
static __noinline void enqueue_dsq_dispatch(
struct task_struct *p,
u64 enq_flags,
u64 packed_cpu_llc)
{
u32 enq_llc = (u32)(packed_cpu_llc & 0xFFFF);
scx_bpf_dsq_insert_vtime(p, LLC_DSQ_BASE + enq_llc,
p->scx.slice ?: quantum_ns,
p->scx.dsq_vtime, enq_flags);
if (!dsq_kick_needed[enq_llc]) {
dsq_kick_needed[enq_llc] = 1;
u32 enq_cpu = (u32)(packed_cpu_llc >> 32) & 0xFFFF;
u64 kick_flags = (u64)cpu_bss[enq_cpu].idle_hint * SCX_KICK_IDLE;
scx_bpf_kick_cpu(enq_cpu, kick_flags);
}
}
static __noinline void enqueue_nostaged(struct task_struct *p, u64 enq_flags)
{
u32 enq_cpu = bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1);
u32 enq_llc = 0;
if (nr_llcs > 1) {
u32 task_cpu = scx_bpf_task_cpu(p);
enq_llc = cpu_llc_id[task_cpu < nr_cpus ? task_cpu : enq_cpu];
}
p->scx.dsq_vtime = scx_bpf_now();
p->scx.slice = quantum_ns;
enqueue_dsq_dispatch(p, enq_flags,
((u64)enq_cpu << 32) | enq_llc);
}
static __noinline void enqueue_requeue_path(
struct task_struct *p, u64 enq_flags,
struct cake_task_hot *hot, u32 enq_cpu)
{
u64 now_cached = scx_bpf_now();
u32 enq_llc = 0;
if (nr_llcs > 1) {
u32 task_cpu = scx_bpf_task_cpu(p);
enq_llc = cpu_llc_id[task_cpu < nr_cpus ? task_cpu : enq_cpu];
}
u64 staged = hot->staged_vtime_bits;
u64 requeue_slice = p->scx.slice ?: quantum_ns;
u32 dsq_weight = (u32)(staged & 0xFFFFFFFF);
p->scx.dsq_vtime = now_cached + dsq_weight;
requeue_slice >>= 1;
requeue_slice += (200000 - requeue_slice) & -(requeue_slice < 200000);
p->scx.slice = requeue_slice;
enqueue_dsq_dispatch(p, enq_flags,
((u64)enq_cpu << 32) | enq_llc);
}
static __noinline void enqueue_wakeup_path(
struct task_struct *p, u64 enq_flags,
struct cake_task_hot *hot, u32 enq_cpu)
{
u64 staged = hot->staged_vtime_bits;
u32 dsq_weight = (u32)(staged & 0xFFFFFFFF);
u8 new_flow = (staged >> STAGED_BIT_NEW_FLOW) & 1;
u64 vtime = dsq_weight + hot->dsq_vtime;
vtime -= new_flow_bonus_ns & -(u64)new_flow;
u8 is_game = (hot->task_class == CAKE_CLASS_GAME);
p->scx.dsq_vtime = vtime;
if (is_game && cpu_bss[enq_cpu].sched_state_local == CAKE_STATE_GAMING)
p->scx.slice = quantum_ns << 1;
u32 enq_llc = 0;
if (nr_llcs > 1) {
u32 task_cpu = scx_bpf_task_cpu(p);
enq_llc = cpu_llc_id[task_cpu < nr_cpus ? task_cpu : enq_cpu];
}
u64 packed = ((u64)enq_cpu << 32) | enq_llc;
enqueue_dsq_dispatch(p, enq_flags, packed);
}
static __noinline void enqueue_body(struct task_struct *p, u64 enq_flags)
{
u32 enq_cpu = bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1);
struct cake_task_hot *hot = get_task_hot(p);
u64 staged = hot ? hot->staged_vtime_bits : 0;
if (unlikely(!(staged & (1ULL << STAGED_BIT_VALID)))) {
enqueue_nostaged(p, enq_flags);
return;
}
if (!(enq_flags & (SCX_ENQ_WAKEUP | SCX_ENQ_PREEMPT))) {
enqueue_requeue_path(p, enq_flags, hot, enq_cpu);
return;
}
enqueue_wakeup_path(p, enq_flags, hot, enq_cpu);
}
void BPF_STRUCT_OPS(cake_enqueue, struct task_struct *p, u64 enq_flags)
{
#ifndef CAKE_RELEASE
ARENA_ASSOC();
#endif
enqueue_body(p, enq_flags);
}
void BPF_STRUCT_OPS(cake_dispatch, s32 raw_cpu, struct task_struct *prev)
{
#ifndef CAKE_RELEASE
ARENA_ASSOC();
#endif
u32 cpu_idx = raw_cpu & (CAKE_MAX_CPUS - 1);
bool stats_on = CAKE_STATS_ACTIVE;
u64 dispatch_start = stats_on ? scx_bpf_now() : 0;
u32 my_llc = cpu_bss[cpu_idx].llc_id;
u64 my_dsq_id = LLC_DSQ_BASE + my_llc;
{
s32 depth = scx_bpf_dsq_nr_queued(my_dsq_id);
if (depth > 0) {
if (scx_bpf_dsq_move_to_local(my_dsq_id, 0)) {
if (dsq_kick_needed[my_llc]) dsq_kick_needed[my_llc] = 0;
if (stats_on) {
struct cake_stats *s = get_local_stats_for(cpu_idx);
s->nr_local_dispatches++;
s->nr_dsq_consumed++;
u64 d_oh = scx_bpf_now() - dispatch_start;
s->total_dispatch_ns += d_oh;
s->max_dispatch_ns = s->max_dispatch_ns + ((d_oh - s->max_dispatch_ns) & -(d_oh > s->max_dispatch_ns));
}
return;
}
}
}
if (nr_llcs > 1) {
for (u32 i = 1; i < CAKE_MAX_LLCS; i++) {
if (i >= nr_llcs) break;
u32 victim = my_llc + i;
if (victim >= nr_llcs) victim -= nr_llcs;
u64 victim_dsq = LLC_DSQ_BASE + victim;
if (scx_bpf_dsq_nr_queued(victim_dsq) > 1 && scx_bpf_dsq_move_to_local(victim_dsq, 0)) {
if (dsq_kick_needed[victim]) dsq_kick_needed[victim] = 0;
if (stats_on) {
struct cake_stats *s = get_local_stats_for(cpu_idx);
s->nr_stolen_dispatches++;
s->nr_dsq_consumed++;
}
return;
}
}
}
if (stats_on) get_local_stats_for(cpu_idx)->nr_dispatch_misses++;
if (prev && (prev->scx.flags & SCX_TASK_QUEUED))
prev->scx.slice = quantum_ns;
if (!cpu_bss[cpu_idx].idle_hint) cpu_bss[cpu_idx].idle_hint = 1;
}
const u32 tier_perf_target[8] = {
1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024,
};
static __noinline void running_task_change(
struct task_struct *p,
struct cake_cpu_bss *bss,
u32 cpu)
{
u64 slice = p->scx.slice;
bss->last_pid = p->pid;
bss->tick_slice = slice ?: quantum_ns;
struct cake_task_hot *hot = get_task_hot(p);
if (!hot)
return;
u8 tc = hot->task_class;
u64 tv = hot->dsq_vtime;
if (tv > bss->vtime_local)
bss->vtime_local = tv;
if (bss->sched_state_local == CAKE_STATE_GAMING) {
u8 game_flag = (tc == CAKE_CLASS_GAME);
u32 word = cpu >> 6;
u64 bit = 1ULL << (cpu & 63);
u64 cur = READ_ONCE(game_cpu_mask[word]);
u64 want = (cur & ~bit) | (bit & -(u64)game_flag);
if (want != cur)
WRITE_ONCE(game_cpu_mask[word], want);
}
}
#ifndef CAKE_RELEASE
static __noinline void running_telemetry(
struct task_struct *p,
u32 cpu,
u64 now_full,
u64 overhead_start)
{
u64 mbox_end = scx_bpf_now();
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (!tctx)
return;
u64 start = now_full;
u64 prev_run_start = tctx->telemetry.run_start_ns;
tctx->telemetry.run_start_ns = start;
struct cake_task_hot *hot_tel = get_task_hot(p);
u32 rc = hot_tel ? hot_tel->reclass_counter : 0;
if ((rc & 63) != 0)
return;
if (prev_run_start > 0 && start > prev_run_start) {
u64 gap = start - prev_run_start;
tctx->telemetry.dispatch_gap_ns = gap;
u64 old_max_g = tctx->telemetry.max_dispatch_gap_ns;
tctx->telemetry.max_dispatch_gap_ns = old_max_g + ((gap - old_max_g) & -(gap > old_max_g));
}
tctx->telemetry.llc_id = (u16)cpu_bss[cpu & (CAKE_MAX_CPUS - 1)].llc_id;
if (tctx->telemetry.enqueue_start_ns > 0 && start > tctx->telemetry.enqueue_start_ns) {
u64 wait = start - tctx->telemetry.enqueue_start_ns;
tctx->telemetry.wait_duration_ns = wait;
tctx->telemetry.enqueue_start_ns = 0;
u64 wait_us = wait >> 10;
if (wait_us < 10)
tctx->telemetry.wait_hist_lt10us++;
else if (wait_us < 100)
tctx->telemetry.wait_hist_lt100us++;
else if (wait_us < 1000)
tctx->telemetry.wait_hist_lt1ms++;
else
tctx->telemetry.wait_hist_ge1ms++;
}
struct cake_stats *s_run = get_local_stats_for(cpu);
u64 oh_run = scx_bpf_now() - overhead_start;
tctx->telemetry.running_duration_ns = (u32)oh_run;
s_run->total_running_ns += oh_run;
s_run->max_running_ns = s_run->max_running_ns + ((oh_run - s_run->max_running_ns) & -(oh_run > s_run->max_running_ns));
tctx->telemetry.mbox_staging_ns = (u32)(mbox_end - overhead_start);
}
#endif
void BPF_STRUCT_OPS(cake_running, struct task_struct *p)
{
#ifndef CAKE_RELEASE
ARENA_ASSOC();
bool stats_on = CAKE_STATS_ACTIVE;
u64 running_overhead_start = 0;
if (stats_on)
running_overhead_start = scx_bpf_now();
#endif
u32 cpu = bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1);
u64 now_full = scx_bpf_now();
u32 now = (u32)now_full;
struct cake_cpu_bss *bss = &cpu_bss[cpu];
bss->run_start = now;
if (bss->idle_hint) bss->idle_hint = 0;
if (bss->last_pid != p->pid)
running_task_change(p, bss, cpu);
#ifndef CAKE_RELEASE
if (stats_on)
running_telemetry(p, cpu, now_full, running_overhead_start);
#endif
}
static __noinline void stopping_reclassify(
struct cake_task_hot *hot,
struct task_struct *p,
u32 rt_raw,
u32 packed,
u64 tick_slice)
{
{
u32 w = p->scx.weight ?: 100;
u16 mult = (u16)(102400 / w);
if (hot->vtime_mult != mult)
hot->vtime_mult = mult;
}
u32 snap_sched_state = sched_state;
if (snap_sched_state != CAKE_STATE_GAMING) {
if (hot->task_class != CAKE_CLASS_NORMAL)
hot->task_class = CAKE_CLASS_NORMAL;
return;
}
u8 is_kthread = (packed >> BIT_KTHREAD) & 1;
bool cls_game = (p->tgid == game_tgid)
|| (hot->ppid == game_ppid)
|| is_kthread;
bool cls_audio = false;
u32 task_tgid = p->tgid;
if (!cls_game && nr_audio_tgids) {
#pragma unroll
for (u32 i = 0; i < CAKE_MAX_AUDIO_TGIDS; i++) {
if (i >= nr_audio_tgids)
break;
if (task_tgid == audio_tgids[i]) {
cls_audio = true;
break;
}
}
}
bool cls_compositor = false;
if (!cls_game && !cls_audio && nr_compositor_tgids) {
#pragma unroll
for (u32 i = 0; i < CAKE_MAX_COMPOSITOR_TGIDS; i++) {
if (i >= nr_compositor_tgids)
break;
if (task_tgid == compositor_tgids[i]) {
cls_compositor = true;
break;
}
}
}
bool cls_penalty = !cls_game
&& !(((packed >> SHIFT_FLAGS) & CAKE_FLOW_WAKER_BOOST))
&& !is_kthread;
u32 hog_thresh = ((u32)tick_slice >> 2) * 3;
bool cls_hog = cls_penalty && (rt_raw >= hog_thresh);
bool cls_bg = cls_penalty && !cls_hog;
u8 new_tc = cls_game ? CAKE_CLASS_GAME
: cls_audio ? CAKE_CLASS_GAME
: cls_compositor ? CAKE_CLASS_GAME
: cls_hog ? CAKE_CLASS_HOG
: cls_bg ? CAKE_CLASS_BG
: CAKE_CLASS_NORMAL;
if (hot->task_class != new_tc)
hot->task_class = new_tc;
}
static __noinline u32 stopping_drr_ewma(
struct cake_task_hot *hot,
struct task_struct *p,
u32 cpu_run)
{
u32 cpu = cpu_run & 0xFF;
struct cake_cpu_bss *bss = &cpu_bss[cpu];
u32 rc = hot->reclass_counter++;
{
u32 rs = bss->run_start;
u32 interval = rs - hot->last_run_at;
hot->last_run_at = rs;
u16 wc = hot->wake_counter;
wc = (interval < 1024) ? (wc + ((1023 - wc) >> 2)) : (wc >> 1);
hot->wake_counter = wc;
}
u32 rt_raw = (u32)(bss->tick_slice - p->scx.slice);
rt_raw -= (rt_raw - (65535U << 10)) & -(rt_raw > (65535U << 10));
{
u32 cap = cpuperf_cap_table[cpu];
if (cap > 0 && cap < 1024)
rt_raw = (u32)((u64)rt_raw * cap >> 10);
}
if (unlikely((rc & 63) == 0)) {
u32 packed = hot->packed_info;
packed &= ~(((u32)CAKE_FLOW_WAKER_BOOST) << SHIFT_FLAGS);
if (hot->packed_info != packed)
hot->packed_info = packed;
stopping_reclassify(hot, p, rt_raw, packed,
bss->tick_slice);
}
return rt_raw;
}
static __noinline u32 stopping_eevdf_weight(
struct cake_task_hot *hot,
u32 rt_raw,
u32 cpu_run,
u64 vtime_local)
{
u8 tc = hot->task_class;
if (!(cpu_run >> 8))
return 0;
{
u64 vt_delta = (u64)rt_raw * (u32)hot->vtime_mult >> 10;
hot->dsq_vtime += vt_delta;
u64 vt_min = vtime_local - 200000000ULL;
if (hot->dsq_vtime < vt_min)
hot->dsq_vtime = vt_min;
}
return tier_base[tc & 3];
}
static __noinline void stopping_quantum_pack(
struct cake_task_hot *hot,
struct task_struct *p,
u32 dsq_weight)
{
u8 tc = hot->task_class;
{
u32 pid_idx = p->pid & (PID_CLASS_CACHE_SIZE - 1);
if (pid_class_cache[pid_idx] != (u8)tc)
pid_class_cache[pid_idx] = (u8)tc;
}
{
u64 nf_val = (tc == CAKE_CLASS_GAME) ? 1 : (u64)((hot->packed_info >> SHIFT_FLAGS) & 1);
hot->staged_vtime_bits = (1ULL << STAGED_BIT_VALID) |
(nf_val << STAGED_BIT_NEW_FLOW) |
(u64)dsq_weight;
}
}
void BPF_STRUCT_OPS(cake_stopping, struct task_struct *p, bool runnable)
{
#ifndef CAKE_RELEASE
ARENA_ASSOC();
#endif
u32 cpu = bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1);
u32 cpu_run = cpu | (((u32)runnable & 1) << 8);
struct cake_task_hot *hot = get_task_hot(p);
if (unlikely(!hot))
return;
u32 rt_raw = stopping_drr_ewma(hot, p, cpu_run);
u8 tc = hot->task_class;
bool stats_on = CAKE_STATS_ACTIVE;
u64 stopping_overhead_start = 0;
if (stats_on) {
stopping_overhead_start = scx_bpf_now();
per_cpu[cpu].mbox.last_stopped_pid = p->pid;
}
u64 cur_nv = 0;
u32 __maybe_unused nvcsw_accum = 0;
if (stats_on && tc != CAKE_CLASS_GAME) {
cur_nv = p->nvcsw;
u64 prev_nv = hot->nvcsw_snapshot;
if (prev_nv > 0)
nvcsw_accum = (u32)(cur_nv - prev_nv);
hot->nvcsw_snapshot = cur_nv;
}
u32 dsq_weight = stopping_eevdf_weight(hot, rt_raw, cpu_run,
cpu_bss[cpu_run & 0xFF].vtime_local);
if (dsq_weight) {
#ifndef CAKE_RELEASE
#endif
stopping_quantum_pack(hot, p, dsq_weight);
}
#ifndef CAKE_RELEASE
#endif
if (stats_on) {
#ifndef CAKE_RELEASE
if (((hot->reclass_counter - 1) & 63) == 0) {
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (tctx) {
if (nvcsw_accum)
tctx->telemetry.nvcsw_delta += nvcsw_accum;
if (tctx->telemetry.run_start_ns > 0) {
u64 now_deferred = scx_bpf_now();
u64 dur = now_deferred - tctx->telemetry.run_start_ns;
tctx->telemetry.run_duration_ns = dur;
bool same = ((u16)cpu == tctx->telemetry.core_placement);
tctx->telemetry.same_cpu_streak = (tctx->telemetry.same_cpu_streak + 1) & -(u16)same;
tctx->telemetry.core_placement = (u16)cpu;
u64 expected_ns = (u64)(rt_raw >> 10) * 1000ULL;
u64 d = dur - expected_ns;
u64 mask = -(u64)(dur < expected_ns);
u64 jitter = (d ^ mask) - mask;
tctx->telemetry.jitter_accum_ns += jitter;
tctx->telemetry.total_runs++;
u16 old_max_rt = tctx->telemetry.max_runtime_us;
u16 ps = (u16)(rt_raw >> 10);
tctx->telemetry.max_runtime_us = old_max_rt + ((ps - old_max_rt) & -(u16)(ps > old_max_rt));
u64 tslice = cpu_bss[cpu].tick_slice ?: quantum_ns;
tctx->telemetry.slice_util_pct =
(u16)((dur << 7) / tslice);
u64 cur_nivcsw = p->nivcsw;
u64 prev_nivcsw = tctx->telemetry.nivcsw_snapshot;
if (prev_nivcsw > 0)
tctx->telemetry.nivcsw_delta += (u32)(cur_nivcsw - prev_nivcsw);
tctx->telemetry.nivcsw_snapshot = cur_nivcsw;
tctx->telemetry.stopping_duration_ns =
(u32)(now_deferred - stopping_overhead_start);
}
u64 rem = p->scx.slice;
if (rem == 0)
tctx->telemetry.quantum_full_count++;
else if (!(cpu_run >> 8))
tctx->telemetry.quantum_yield_count++;
else
tctx->telemetry.quantum_preempt_count++;
tctx->telemetry.cpu_run_count[cpu & (CAKE_TELEM_MAX_CPUS - 1)]++;
if (tctx->vtime_mult != hot->vtime_mult)
tctx->vtime_mult = hot->vtime_mult;
if (tctx->task_class != hot->task_class)
tctx->task_class = hot->task_class;
}
}
#endif
struct cake_stats *s = get_local_stats_for(cpu);
u64 oh_agg = scx_bpf_now() - stopping_overhead_start;
s->total_stopping_ns += oh_agg;
s->max_stopping_ns = s->max_stopping_ns + ((oh_agg - s->max_stopping_ns) & -(oh_agg > s->max_stopping_ns));
if (((hot->reclass_counter - 1) & 63) == 0)
s->nr_stop_classify++;
else
s->nr_stop_confidence_skip++;
if (unlikely(bench_request)) {
bench_request = 0;
run_kfunc_bench(&bench_results, p);
}
}
}
s32 BPF_STRUCT_OPS_SLEEPABLE(cake_init_task, struct task_struct *p,
struct scx_init_task_args *args)
{
struct cake_task_ctx __arena *tctx;
tctx = (struct cake_task_ctx __arena *)scx_task_alloc(p);
if (!tctx) {
if (CAKE_STATS_ACTIVE) {
struct cake_stats *s = get_local_stats();
s->nr_dropped_allocations++;
}
return -ENOMEM;
}
u16 init_deficit = (u16)((quantum_ns + new_flow_bonus_ns) >> 10);
if (CAKE_STATS_ENABLED) {
tctx->deficit_u16 = init_deficit;
tctx->last_run_at = 0;
tctx->reclass_counter = 0;
tctx->warm_cpus[0] = 0xFFFF;
tctx->warm_cpus[1] = 0xFFFF;
tctx->warm_cpus[2] = 0xFFFF;
tctx->waker_cpu = 0xFFFF;
tctx->task_class = CAKE_CLASS_NORMAL;
}
#ifndef CAKE_RELEASE
if (CAKE_STATS_ACTIVE) {
tctx->telemetry.pid = p->pid;
tctx->telemetry.tgid = p->tgid;
u64 *comm_src = (u64 *)p->comm;
u64 __arena *comm_dst = (u64 __arena *)tctx->telemetry.comm;
comm_dst[0] = comm_src[0];
comm_dst[1] = comm_src[1];
tctx->telemetry.nivcsw_snapshot = p->nivcsw;
}
#endif
if (CAKE_STATS_ENABLED)
tctx->nvcsw_snapshot = p->nvcsw;
u32 packed = 0;
packed |= ((u32)CAKE_FLOW_NEW & MASK_FLAGS) << SHIFT_FLAGS;
packed |= (((u32)(p->flags >> 21) & 1u) << BIT_KTHREAD);
if (CAKE_STATS_ENABLED)
tctx->packed_info = packed;
struct cake_task_hot *hot = bpf_task_storage_get(
&task_hot_stor, p, 0, BPF_LOCAL_STORAGE_GET_F_CREATE);
if (hot) {
hot->deficit_u16 = init_deficit;
hot->wake_counter = 0;
hot->packed_info = packed;
u32 init_ppid = p->real_parent ? p->real_parent->tgid : 0;
if (CAKE_STATS_ENABLED)
tctx->ppid = init_ppid;
hot->ppid = init_ppid;
hot->last_run_at = 0;
hot->reclass_counter = 0;
*(u64 *)&hot->warm_cpus[0] = 0xFFFFFFFFFFFFFFFFULL;
hot->nvcsw_snapshot = p->nvcsw;
hot->task_class = CAKE_CLASS_NORMAL;
hot->vtime_mult = 1024;
hot->dsq_vtime = cpu_bss[bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1)].vtime_local;
}
return 0;
}
void BPF_STRUCT_OPS(cake_enable, struct task_struct *p)
{
struct cake_task_hot *hot = get_task_hot(p);
if (hot)
hot->dsq_vtime = cpu_bss[bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1)].vtime_local;
}
void BPF_STRUCT_OPS(cake_set_cpumask, struct task_struct *p __arg_trusted,
const struct cpumask *cpumask __arg_trusted)
{
#ifndef CAKE_RELEASE
if (CAKE_STATS_ENABLED) {
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (tctx)
tctx->telemetry.cpumask_change_count++;
}
#endif
}
bool BPF_STRUCT_OPS(cake_yield, struct task_struct *p)
{
#ifndef CAKE_RELEASE
if (CAKE_STATS_ACTIVE) {
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (tctx) tctx->telemetry.yield_count++;
}
#endif
return false;
}
void BPF_STRUCT_OPS(cake_runnable, struct task_struct *p, u64 enq_flags)
{
#ifndef CAKE_RELEASE
if (CAKE_STATS_ACTIVE) {
struct cake_task_ctx __arena *tctx = get_task_ctx(p);
if (tctx) {
if (enq_flags & SCX_ENQ_PREEMPT)
tctx->telemetry.preempt_count++;
struct task_struct *waker = bpf_get_current_task_btf();
if (waker) {
tctx->telemetry.wakeup_source_pid = waker->pid;
tctx->telemetry.waker_cpu = (u16)bpf_get_smp_processor_id();
tctx->telemetry.waker_tgid = waker->tgid;
}
}
}
#endif
}
void BPF_STRUCT_OPS(cake_exit_task, struct task_struct *p,
struct scx_exit_task_args *args)
{
scx_task_free(p);
}
s32 BPF_STRUCT_OPS_SLEEPABLE(cake_init)
{
for (u32 i = 0; i < CAKE_MAX_LLCS; i++) {
if (i >= nr_llcs)
break;
s32 ret = scx_bpf_create_dsq(LLC_DSQ_BASE + i, -1);
if (ret < 0)
return ret;
}
#ifdef CAKE_RELEASE
per_cpu = (struct cake_per_cpu __arena *)bpf_arena_alloc_pages(
&arena, NULL, 1, NUMA_NO_NODE, 0);
#else
per_cpu = (struct cake_per_cpu __arena *)bpf_arena_alloc_pages(
&arena, NULL, 2, NUMA_NO_NODE, 0);
#endif
if (!per_cpu)
return -ENOMEM;
for (u32 i = 0; i < CAKE_MAX_CPUS; i++) {
if (i >= nr_cpus)
break;
cpu_bss[i].llc_id = (u8)cpu_llc_id[i];
}
return 0;
}
void BPF_STRUCT_OPS(cake_exit, struct scx_exit_info *ei)
{
UEI_RECORD(uei, ei);
}
#ifndef CAKE_RELEASE
static __noinline void iter_copy_timing(
struct cake_task_ctx __arena *tctx,
struct cake_iter_record *rec)
{
rec->telemetry.run_start_ns = tctx->telemetry.run_start_ns;
rec->telemetry.run_duration_ns = tctx->telemetry.run_duration_ns;
rec->telemetry.enqueue_start_ns = tctx->telemetry.enqueue_start_ns;
rec->telemetry.wait_duration_ns = tctx->telemetry.wait_duration_ns;
rec->telemetry.select_cpu_duration_ns= tctx->telemetry.select_cpu_duration_ns;
rec->telemetry.enqueue_duration_ns = tctx->telemetry.enqueue_duration_ns;
rec->telemetry.dsq_insert_ns = tctx->telemetry.dsq_insert_ns;
rec->telemetry.jitter_accum_ns = tctx->telemetry.jitter_accum_ns;
rec->telemetry.stopping_duration_ns = tctx->telemetry.stopping_duration_ns;
rec->telemetry.running_duration_ns = tctx->telemetry.running_duration_ns;
rec->telemetry.max_runtime_us = tctx->telemetry.max_runtime_us;
rec->telemetry._pad4 = 0;
rec->telemetry.dispatch_gap_ns = tctx->telemetry.dispatch_gap_ns;
rec->telemetry.max_dispatch_gap_ns = tctx->telemetry.max_dispatch_gap_ns;
}
static __noinline void iter_copy_gates(
struct cake_task_ctx __arena *tctx,
struct cake_iter_record *rec)
{
rec->telemetry.gate_1_hits = tctx->telemetry.gate_1_hits;
rec->telemetry.gate_2_hits = tctx->telemetry.gate_2_hits;
rec->telemetry.gate_1w_hits = tctx->telemetry.gate_1w_hits;
rec->telemetry.gate_3_hits = tctx->telemetry.gate_3_hits;
rec->telemetry.gate_1p_hits = tctx->telemetry.gate_1p_hits;
rec->telemetry.gate_1c_hits = tctx->telemetry.gate_1c_hits;
rec->telemetry.gate_1cp_hits = tctx->telemetry.gate_1cp_hits;
rec->telemetry.gate_1d_hits = tctx->telemetry.gate_1d_hits;
rec->telemetry.gate_1wc_hits = tctx->telemetry.gate_1wc_hits;
rec->telemetry.gate_tun_hits = tctx->telemetry.gate_tun_hits;
rec->telemetry._pad2 = 0;
rec->telemetry.total_runs = tctx->telemetry.total_runs;
rec->telemetry.core_placement = tctx->telemetry.core_placement;
rec->telemetry.migration_count = tctx->telemetry.migration_count;
rec->telemetry.preempt_count = tctx->telemetry.preempt_count;
rec->telemetry.yield_count = tctx->telemetry.yield_count;
rec->telemetry.direct_dispatch_count = tctx->telemetry.direct_dispatch_count;
rec->telemetry.enqueue_count = tctx->telemetry.enqueue_count;
rec->telemetry.cpumask_change_count = tctx->telemetry.cpumask_change_count;
rec->telemetry._pad3 = 0;
}
static __noinline void iter_copy_hist(
struct cake_task_ctx __arena *tctx,
struct cake_iter_record *rec)
{
rec->telemetry.wait_hist_lt10us = tctx->telemetry.wait_hist_lt10us;
rec->telemetry.wait_hist_lt100us = tctx->telemetry.wait_hist_lt100us;
rec->telemetry.wait_hist_lt1ms = tctx->telemetry.wait_hist_lt1ms;
rec->telemetry.wait_hist_ge1ms = tctx->telemetry.wait_hist_ge1ms;
rec->telemetry.slice_util_pct = tctx->telemetry.slice_util_pct;
rec->telemetry.llc_id = tctx->telemetry.llc_id;
rec->telemetry.same_cpu_streak = tctx->telemetry.same_cpu_streak;
rec->telemetry._pad_recomp = 0;
rec->telemetry.wakeup_source_pid = tctx->telemetry.wakeup_source_pid;
rec->telemetry.nivcsw_snapshot = tctx->telemetry.nivcsw_snapshot;
rec->telemetry.nvcsw_delta = tctx->telemetry.nvcsw_delta;
rec->telemetry.nivcsw_delta = tctx->telemetry.nivcsw_delta;
rec->telemetry.pid_inner = tctx->telemetry.pid;
rec->telemetry.tgid = tctx->telemetry.tgid;
*((__u64 *)&rec->telemetry.comm[0]) = *((__u64 __arena *)&tctx->telemetry.comm[0]);
*((__u64 *)&rec->telemetry.comm[8]) = *((__u64 __arena *)&tctx->telemetry.comm[8]);
}
static __noinline void iter_copy_substage(
struct cake_task_ctx __arena *tctx,
struct cake_iter_record *rec)
{
rec->telemetry.gate_cascade_ns = tctx->telemetry.gate_cascade_ns;
rec->telemetry.idle_probe_ns = tctx->telemetry.idle_probe_ns;
rec->telemetry.vtime_compute_ns = tctx->telemetry.vtime_compute_ns;
rec->telemetry.mbox_staging_ns = tctx->telemetry.mbox_staging_ns;
rec->telemetry._pad_ewma = 0;
rec->telemetry.classify_ns = tctx->telemetry.classify_ns;
rec->telemetry.vtime_staging_ns = tctx->telemetry.vtime_staging_ns;
rec->telemetry.warm_history_ns = tctx->telemetry.warm_history_ns;
rec->telemetry.quantum_full_count = tctx->telemetry.quantum_full_count;
rec->telemetry.quantum_yield_count = tctx->telemetry.quantum_yield_count;
rec->telemetry.quantum_preempt_count = tctx->telemetry.quantum_preempt_count;
rec->telemetry._pad_quantum = 0;
rec->telemetry.waker_cpu = tctx->telemetry.waker_cpu;
rec->telemetry._pad_waker = 0;
rec->telemetry.waker_tgid = tctx->telemetry.waker_tgid;
for (int _ci = 0; _ci < CAKE_TELEM_MAX_CPUS; _ci++)
rec->telemetry.cpu_run_count[_ci] = tctx->telemetry.cpu_run_count[_ci];
}
#endif
SEC("iter/task")
int cake_task_iter(struct bpf_iter__task *ctx)
{
struct seq_file *seq = ctx->meta->seq;
struct task_struct *task = ctx->task;
if (!task)
return 0;
struct cake_task_ctx __arena *tctx = get_task_ctx(task);
#ifndef CAKE_RELEASE
if (!tctx || !tctx->telemetry.pid)
return 0;
#else
if (!tctx)
return 0;
#endif
struct cake_iter_record rec = {};
rec.pid = task->pid;
rec.ppid = tctx->ppid;
rec.packed_info = tctx->packed_info;
rec.pelt_util = (u16)task->se.avg.util_avg;
rec.deficit_us = tctx->deficit_u16;
rec.vtime_mult = tctx->vtime_mult;
#ifndef CAKE_RELEASE
iter_copy_timing(tctx, &rec);
iter_copy_gates(tctx, &rec);
iter_copy_hist(tctx, &rec);
iter_copy_substage(tctx, &rec);
#endif
bpf_seq_write(seq, &rec, sizeof(rec));
return 0;
}
void BPF_STRUCT_OPS(cake_tick, struct task_struct *p)
{
if (nr_llcs <= 1)
return;
u32 cpu = bpf_get_smp_processor_id() & (CAKE_MAX_CPUS - 1);
cpu_bss[cpu].tick_count++;
if (cpu_bss[cpu].tick_count & 7)
return;
u32 my_llc = cpu_bss[cpu].llc_id;
s32 my_depth = scx_bpf_dsq_nr_queued(LLC_DSQ_BASE + my_llc);
if (my_depth < 2)
return;
for (u32 i = 1; i < CAKE_MAX_LLCS && i < nr_llcs; i++) {
u32 other = (my_llc + i);
if (other >= nr_llcs) other -= nr_llcs;
s32 other_depth = scx_bpf_dsq_nr_queued(LLC_DSQ_BASE + other);
if (other_depth == 0) {
u64 mask = llc_cpu_mask[other];
if (mask) {
u32 target = __builtin_ctzll(mask);
if (target < nr_cpus)
scx_bpf_kick_cpu(target, SCX_KICK_IDLE);
}
break;
}
}
}
void BPF_STRUCT_OPS(cake_set_weight, struct task_struct *p, u32 weight)
{
}
SCX_OPS_DEFINE(cake_ops, .select_cpu = (void *)cake_select_cpu,
.enqueue = (void *)cake_enqueue,
.dispatch = (void *)cake_dispatch,
.tick = (void *)cake_tick,
.running = (void *)cake_running,
.stopping = (void *)cake_stopping,
.yield = (void *)cake_yield,
.runnable = (void *)cake_runnable,
.set_weight = (void *)cake_set_weight,
.enable = (void *)cake_enable,
.set_cpumask = (void *)cake_set_cpumask,
.init_task = (void *)cake_init_task,
.exit_task = (void *)cake_exit_task, .init = (void *)cake_init,
.exit = (void *)cake_exit, .flags = SCX_OPS_KEEP_BUILTIN_IDLE,
.timeout_ms = 5000,
.name = "cake");