#include <scx/common.bpf.h>
#include <scx/compat.bpf.h>
char _license[] SEC("license") = "GPL";
UEI_DEFINE(uei);
#define MAX_SAMPLES 100
#define MAX_CPUS 512
#define DSQ_POOL_SIZE 8
int max_samples = MAX_SAMPLES;
int max_cpus = MAX_CPUS;
int dsq_pool_size = DSQ_POOL_SIZE;
int dsq_peek_result1 = -1;
long dsq_inserted_pid = -1;
int insert_test_cpu = -1;
long dsq_peek_result2 = -1;
long dsq_peek_result2_pid = -1;
long dsq_peek_result2_expected = -1;
int test_dsq_id = 1234;
int real_dsq_id = 1235;
int enqueue_count = -1;
int dispatch_count = -1;
bool debug_ksym_exists;
int dsq_pool_base_id = 2000;
int phase1_complete = -1;
long total_peek_attempts = -1;
long successful_peeks = -1;
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, MAX_SAMPLES);
__type(key, u32);
__type(value, long);
} peek_results SEC(".maps");
static int get_random_dsq_id(void)
{
u64 time = bpf_ktime_get_ns();
return dsq_pool_base_id + (time % DSQ_POOL_SIZE);
}
static void record_peek_result(long pid)
{
u32 slot_key;
long *slot_pid_ptr;
u32 ix;
if (pid <= 0)
return;
bpf_for(ix, 0, 10) {
slot_key = ((u64)pid + ix) % MAX_SAMPLES;
slot_pid_ptr = bpf_map_lookup_elem(&peek_results, &slot_key);
if (!slot_pid_ptr)
continue;
if (*slot_pid_ptr == -1 || *slot_pid_ptr == pid) {
*slot_pid_ptr = pid;
break;
}
}
}
static int scan_dsq_pool(void)
{
struct task_struct *task;
int moved = 0;
int i;
bpf_for(i, 0, DSQ_POOL_SIZE) {
int dsq_id = dsq_pool_base_id + i;
total_peek_attempts++;
task = __COMPAT_scx_bpf_dsq_peek(dsq_id);
if (task) {
successful_peeks++;
record_peek_result(task->pid);
if (!moved && scx_bpf_dsq_move_to_local(dsq_id) == 0) {
moved = 1;
break;
}
}
}
return moved;
}
void BPF_STRUCT_OPS(peek_dsq_enqueue, struct task_struct *p, u64 enq_flags)
{
struct task_struct *peek_result;
int last_insert_test_cpu, cpu;
enqueue_count++;
cpu = bpf_get_smp_processor_id();
last_insert_test_cpu = __sync_val_compare_and_swap(&insert_test_cpu, -1, cpu);
if (last_insert_test_cpu == -1) {
bpf_printk("peek_dsq_enqueue beginning phase 1 peek test on cpu %d", cpu);
peek_result = __COMPAT_scx_bpf_dsq_peek(test_dsq_id);
dsq_peek_result1 = (long)peek_result;
dsq_inserted_pid = p->pid;
scx_bpf_dsq_insert(p, test_dsq_id, 0, enq_flags);
dsq_peek_result2_expected = (long)p;
} else if (!phase1_complete) {
scx_bpf_dsq_insert(p, real_dsq_id, 0, enq_flags);
} else {
int random_dsq_id = get_random_dsq_id();
scx_bpf_dsq_insert(p, random_dsq_id, 0, enq_flags);
}
}
void BPF_STRUCT_OPS(peek_dsq_dispatch, s32 cpu, struct task_struct *prev)
{
dispatch_count++;
if (insert_test_cpu == cpu && dsq_peek_result2 == -1) {
struct task_struct *peek_result;
bpf_printk("peek_dsq_dispatch completing phase 1 peek test on cpu %d", cpu);
peek_result = __COMPAT_scx_bpf_dsq_peek(test_dsq_id);
dsq_peek_result2 = (long)peek_result;
dsq_peek_result2_pid = peek_result ? peek_result->pid : -1;
scx_bpf_dsq_move_to_local(test_dsq_id);
phase1_complete = 1;
bpf_printk("Phase 1 complete, starting phase 2 stress testing");
} else if (!phase1_complete) {
scx_bpf_dsq_move_to_local(real_dsq_id);
} else {
if (!scan_dsq_pool()) {
scx_bpf_dsq_move_to_local(real_dsq_id);
}
}
}
s32 BPF_STRUCT_OPS_SLEEPABLE(peek_dsq_init)
{
s32 err;
int i;
debug_ksym_exists = bpf_ksym_exists(scx_bpf_dsq_peek) ? 1 : 0;
insert_test_cpu = -1;
enqueue_count = 0;
dispatch_count = 0;
phase1_complete = 0;
total_peek_attempts = 0;
successful_peeks = 0;
err = scx_bpf_create_dsq(test_dsq_id, -1);
if (err) {
scx_bpf_error("Failed to create DSQ %d: %d", test_dsq_id, err);
return err;
}
err = scx_bpf_create_dsq(real_dsq_id, -1);
if (err) {
scx_bpf_error("Failed to create DSQ %d: %d", test_dsq_id, err);
return err;
}
bpf_for(i, 0, DSQ_POOL_SIZE) {
int dsq_id = dsq_pool_base_id + i;
err = scx_bpf_create_dsq(dsq_id, -1);
if (err) {
scx_bpf_error("Failed to create DSQ pool entry %d: %d", dsq_id, err);
return err;
}
}
bpf_for(i, 0, MAX_SAMPLES) {
u32 key = i;
long pid = -1;
bpf_map_update_elem(&peek_results, &key, &pid, BPF_ANY);
}
return 0;
}
void BPF_STRUCT_OPS(peek_dsq_exit, struct scx_exit_info *ei)
{
int i;
scx_bpf_destroy_dsq(test_dsq_id);
scx_bpf_destroy_dsq(real_dsq_id);
bpf_for(i, 0, DSQ_POOL_SIZE) {
int dsq_id = dsq_pool_base_id + i;
scx_bpf_destroy_dsq(dsq_id);
}
UEI_RECORD(uei, ei);
}
SEC(".struct_ops.link")
struct sched_ext_ops peek_dsq_ops = {
.enqueue = (void *)peek_dsq_enqueue,
.dispatch = (void *)peek_dsq_dispatch,
.init = (void *)peek_dsq_init,
.exit = (void *)peek_dsq_exit,
.name = "peek_dsq",
};