Skip to content

Commit b41c62c

Browse files
committed
[SCX][lavd] modify lavd to use new peek operation
Summary: The per-cpu queues mode in LAVD checks multiple queues for potential steal targets. These checks can be made more efficient with the forthcoming O(1) lockless peek operation. This patch updates LAVD to use peek in three places: - try_to_steal: picking cpu with lowest vtime - on consume_task: checking the cpu DSQ - on consume_task: checking the domain DSQ Note that these usages are necessarily racy because no lock is held. That is, we could peek a low vtime, but the task may have moved or completed by the time we attempt to steal it. Test Plan: - ran schbench under a VM [1 cpdom, 50cpus] Reviewers: daidavid
1 parent 91da19d commit b41c62c

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

scheds/include/scx/common.bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ u32 scx_bpf_reenqueue_local(void) __ksym;
7575
void scx_bpf_kick_cpu(s32 cpu, u64 flags) __ksym;
7676
s32 scx_bpf_dsq_nr_queued(u64 dsq_id) __ksym;
7777
void scx_bpf_destroy_dsq(u64 dsq_id) __ksym;
78+
struct task_struct *scx_bpf_dsq_peek(u64 dsq_id) __ksym __weak;
7879
int bpf_iter_scx_dsq_new(struct bpf_iter_scx_dsq *it, u64 dsq_id, u64 flags) __ksym __weak;
7980
struct task_struct *bpf_iter_scx_dsq_next(struct bpf_iter_scx_dsq *it) __ksym __weak;
8081
void bpf_iter_scx_dsq_destroy(struct bpf_iter_scx_dsq *it) __ksym __weak;

scheds/rust/scx_lavd/src/bpf/balance.bpf.c

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,46 @@ static bool consume_dsq(struct cpdom_ctx *cpdomc, u64 dsq_id)
173173
return ret;
174174
}
175175

176+
/*
177+
* Attempts to peek the vtime of the task at the head of the DSQ, or returns U64_MAX if the DSQ is empty.
178+
*/
179+
static int peek_vtime(u64 dsq_id) {
180+
struct task_struct *task;
181+
task = scx_bpf_dsq_peek(dsq_id);
182+
return task ? task->scx.dsq_vtime : U64_MAX;
183+
}
184+
185+
/*
186+
* Racy operation that returns the cpu that which appears to have the lowest vtime at its head.
187+
*/
188+
static int pick_cpu_with_lowest_vtime(struct cpdom_ctx *cpdomc) {
189+
u64 lowest_vtime = U64_MAX;
190+
int pick_cpu = -ENOENT;
191+
int cpu, i, j;
192+
193+
if (!per_cpu_dsq)
194+
return -ENOENT;
195+
196+
bpf_for(i, 0, LAVD_CPU_ID_MAX/64) {
197+
u64 cpumask = cpdomc->__cpumask[i];
198+
bpf_for(j, 0, 64) {
199+
if (cpumask & 0x1LLU << j) {
200+
u64 vtime;
201+
cpu = (i * 64) + j;
202+
if (cpu >= __nr_cpu_ids)
203+
break;
204+
vtime = peek_vtime(cpu_to_dsq(cpu));
205+
if (vtime < lowest_vtime) {
206+
lowest_vtime = vtime;
207+
pick_cpu = cpu;
208+
}
209+
}
210+
}
211+
}
212+
213+
return pick_cpu;
214+
}
215+
176216
/*
177217
* For simplicity, try to just steal from the CPU with
178218
* the highest number of queued_tasks in this domain.
@@ -256,7 +296,7 @@ static bool try_to_steal_task(struct cpdom_ctx *cpdomc)
256296
if (!READ_ONCE(cpdomc_pick->is_stealee) || !cpdomc_pick->is_valid)
257297
continue;
258298

259-
pick_cpu = pick_most_loaded_cpu(cpdomc_pick);
299+
pick_cpu = pick_cpu_with_lowest_vtime(cpdomc_pick);
260300
if (pick_cpu >= 0)
261301
dsq_id = cpu_to_dsq(pick_cpu);
262302
else
@@ -333,7 +373,7 @@ static bool force_to_steal_task(struct cpdom_ctx *cpdomc)
333373
if (!cpdomc_pick->is_valid)
334374
continue;
335375

336-
pick_cpu = pick_most_loaded_cpu(cpdomc_pick);
376+
pick_cpu = pick_cpu_with_lowest_vtime(cpdomc_pick);
337377
if (pick_cpu >= 0)
338378
dsq_id = cpu_to_dsq(pick_cpu);
339379
else
@@ -350,7 +390,6 @@ static bool force_to_steal_task(struct cpdom_ctx *cpdomc)
350390
static bool consume_task(u64 cpu_dsq_id, u64 cpdom_dsq_id)
351391
{
352392
struct cpdom_ctx *cpdomc;
353-
struct task_struct *p;
354393
u64 vtime = U64_MAX, dsq_id = cpu_dsq_id;
355394

356395
cpdomc = MEMBER_VPTR(cpdom_ctxs, [dsq_to_cpdom(cpdom_dsq_id)]);
@@ -368,16 +407,9 @@ static bool consume_task(u64 cpu_dsq_id, u64 cpdom_dsq_id)
368407
goto x_domain_migration_out;
369408

370409
if (per_cpu_dsq) {
371-
bpf_for_each(scx_dsq, p, cpu_dsq_id, 0) {
372-
vtime = p->scx.dsq_vtime;
373-
break;
374-
}
375-
376-
bpf_for_each(scx_dsq, p, cpdom_dsq_id, 0) {
377-
if (p->scx.dsq_vtime < vtime)
378-
dsq_id = cpdom_dsq_id;
379-
break;
380-
}
410+
vtime = peek_vtime(cpu_dsq_id);
411+
if (peek_vtime(cpdom_dsq_id) < vtime)
412+
dsq_id = cpdom_dsq_id;
381413
} else {
382414
dsq_id = cpdom_dsq_id;
383415
}

0 commit comments

Comments
 (0)