u64 __attribute__ ((noinline)) calc_mig_delta(u64 avg_sc_load, int nz_qlen)
{
if (nz_qlen >= sys_stat.nr_active_cpdoms)
return avg_sc_load >> LAVD_CPDOM_MIG_SHIFT_OL;
if (nz_qlen == 0)
return avg_sc_load >> LAVD_CPDOM_MIG_SHIFT_UL;
return avg_sc_load >> LAVD_CPDOM_MIG_SHIFT;
}
static void plan_x_cpdom_migration(void)
{
struct cpdom_ctx *cpdomc;
u64 dsq_id;
u32 stealer_threshold, stealee_threshold, nr_stealee = 0;
u64 avg_sc_load = 0, min_sc_load = U64_MAX, max_sc_load = 0;
u64 x_mig_delta, util, qlen, sc_qlen;
bool overflow_running = false;
int nz_qlen = 0;
bpf_for(dsq_id, 0, nr_cpdoms) {
if (dsq_id >= LAVD_CPDOM_MAX_NR)
break;
cpdomc = MEMBER_VPTR(cpdom_ctxs, [dsq_id]);
if (!cpdomc->nr_active_cpus) {
if (cpdomc->cur_util_sum > 0) {
overflow_running = true;
cpdomc->sc_load = U32_MAX;
}
else
cpdomc->sc_load = 0;
continue;
}
util = (cpdomc->cur_util_sum << LAVD_SHIFT) / cpdomc->nr_active_cpus;
qlen = cpdomc->nr_queued_task;
sc_qlen = (qlen << (LAVD_SHIFT * 3)) / cpdomc->cap_sum_active_cpus;
cpdomc->sc_load = util + sc_qlen;
avg_sc_load += cpdomc->sc_load;
if (min_sc_load > cpdomc->sc_load)
min_sc_load = cpdomc->sc_load;
if (max_sc_load < cpdomc->sc_load)
max_sc_load = cpdomc->sc_load;
if (qlen)
nz_qlen++;
}
if (sys_stat.nr_active_cpdoms)
avg_sc_load /= sys_stat.nr_active_cpdoms;
x_mig_delta = calc_mig_delta(avg_sc_load, nz_qlen);
stealer_threshold = avg_sc_load - x_mig_delta;
stealee_threshold = avg_sc_load + x_mig_delta;
if ((stealee_threshold > max_sc_load) && !overflow_running) {
return;
}
if ((stealee_threshold <= max_sc_load || overflow_running) &&
(stealer_threshold < min_sc_load)) {
stealer_threshold = min_sc_load;
}
bpf_for(dsq_id, 0, nr_cpdoms) {
if (dsq_id >= LAVD_CPDOM_MAX_NR)
break;
cpdomc = MEMBER_VPTR(cpdom_ctxs, [dsq_id]);
if (cpdomc->nr_active_cpus &&
cpdomc->sc_load <= stealer_threshold) {
WRITE_ONCE(cpdomc->is_stealer, true);
WRITE_ONCE(cpdomc->is_stealee, false);
continue;
}
if (!cpdomc->nr_active_cpus ||
cpdomc->sc_load >= stealee_threshold) {
WRITE_ONCE(cpdomc->is_stealer, false);
WRITE_ONCE(cpdomc->is_stealee, true);
nr_stealee++;
continue;
}
WRITE_ONCE(cpdomc->is_stealer, false);
WRITE_ONCE(cpdomc->is_stealee, false);
}
sys_stat.nr_stealee = nr_stealee;
}
static bool consume_dsq(u64 dsq_id)
{
return scx_bpf_dsq_move_to_local(dsq_id);
}
static bool try_to_steal_task(struct cpdom_ctx *cpdomc)
{
struct cpdom_ctx *cpdomc_pick;
s64 nr_nbr, dsq_id;
s64 nuance;
if (!cpdomc->nr_active_cpus)
return false;
if (!prob_x_out_of_y(1, cpdomc->nr_active_cpus * LAVD_CPDOM_MIG_PROB_FT))
return false;
nuance = bpf_get_prandom_u32();
for (int i = 0; i < LAVD_CPDOM_MAX_DIST; i++) {
nr_nbr = min(cpdomc->nr_neighbors[i], LAVD_CPDOM_MAX_NR);
if (nr_nbr == 0)
break;
for (int j = 0; j < LAVD_CPDOM_MAX_NR; j++, nuance = dsq_id + 1) {
if (j >= nr_nbr)
break;
dsq_id = pick_any_bit(cpdomc->neighbor_bits[i], nuance);
if (dsq_id < 0)
continue;
cpdomc_pick = MEMBER_VPTR(cpdom_ctxs, [dsq_id]);
if (!cpdomc_pick) {
scx_bpf_error("Failed to lookup cpdom_ctx for %llu", dsq_id);
return false;
}
if (!READ_ONCE(cpdomc_pick->is_stealee) || !cpdomc_pick->is_valid)
continue;
if (consume_dsq(dsq_id)) {
WRITE_ONCE(cpdomc_pick->is_stealee, false);
WRITE_ONCE(cpdomc->is_stealer, false);
return true;
}
}
if (!prob_x_out_of_y(1, LAVD_CPDOM_MIG_PROB_FT))
break;
}
return false;
}
static bool force_to_steal_task(struct cpdom_ctx *cpdomc)
{
struct cpdom_ctx *cpdomc_pick;
s64 nr_nbr, dsq_id;
s64 nuance;
nuance = bpf_get_prandom_u32();
for (int i = 0; i < LAVD_CPDOM_MAX_DIST; i++) {
nr_nbr = min(cpdomc->nr_neighbors[i], LAVD_CPDOM_MAX_NR);
if (nr_nbr == 0)
break;
for (int j = 0; j < LAVD_CPDOM_MAX_NR; j++, nuance = dsq_id + 1) {
if (j >= nr_nbr)
break;
dsq_id = pick_any_bit(cpdomc->neighbor_bits[i], nuance);
if (dsq_id < 0)
continue;
cpdomc_pick = MEMBER_VPTR(cpdom_ctxs, [dsq_id]);
if (!cpdomc_pick) {
scx_bpf_error("Failed to lookup cpdom_ctx for %llu", dsq_id);
return false;
}
if (!cpdomc_pick->is_valid)
continue;
if (consume_dsq(dsq_id))
return true;
}
}
return false;
}
static bool consume_task(u64 dsq_id)
{
struct cpdom_ctx *cpdomc;
cpdomc = MEMBER_VPTR(cpdom_ctxs, [dsq_id]);
if (!cpdomc) {
scx_bpf_error("Failed to lookup cpdom_ctx for %llu", dsq_id);
return false;
}
if (nr_cpdoms > 1 && READ_ONCE(cpdomc->is_stealer) &&
try_to_steal_task(cpdomc))
goto x_domain_migration_out;
if (consume_dsq(dsq_id))
return true;
if (nr_cpdoms > 1 && force_to_steal_task(cpdomc))
goto x_domain_migration_out;
return false;
x_domain_migration_out:
return true;
}