Skip to content

Commit af16be8

Browse files
committed
scx_layered: Implement sticky modulation optimization
Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]>
1 parent 9213bad commit af16be8

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

scheds/rust/scx_layered/src/bpf/intf.h

+6
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ struct cpu_ctx {
202202
u32 gn_layer_order[MAX_LAYERS]; /* grouped non-preempt */
203203

204204
struct cpu_prox_map prox_map;
205+
206+
u64 sticky_mod_end_time_ns;
207+
u64 sticky_mod_pred_pct;
205208
};
206209

207210
struct llc_prox_map {
@@ -332,6 +335,9 @@ struct layer {
332335

333336
char name[MAX_LAYER_NAME];
334337
bool is_protected;
338+
339+
u64 sticky_mod_min_ns;
340+
u64 sticky_mod_pred_pct;
335341
};
336342

337343
struct scx_cmd {

scheds/rust/scx_layered/src/bpf/main.bpf.c

+106
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ const volatile u64 min_open_layer_disallow_preempt_after_ns;
5252
const volatile u64 lo_fb_wait_ns = 5000000; /* !0 for veristat */
5353
const volatile u32 lo_fb_share_ppk = 128; /* !0 for veristat */
5454
const volatile bool percpu_kthread_preempt = true;
55+
int active_sticky_mod = 0;
5556

5657
/* Flag to enable or disable antistall feature */
5758
const volatile bool enable_antistall = true;
@@ -499,6 +500,11 @@ struct task_ctx {
499500
u32 qrt_llc_id;
500501

501502
char join_layer[SCXCMD_COMLEN];
503+
504+
#define STICKY_MOD_NR_BUCKETS 8
505+
u64 sticky_mod_buckets[STICKY_MOD_NR_BUCKETS];
506+
u64 sticky_mod_nr_cnt;
507+
u64 sticky_mod_start_ns;
502508
};
503509

504510
struct {
@@ -871,6 +877,48 @@ s32 pick_idle_big_little(struct layer *layer, struct task_ctx *taskc,
871877
return cpu;
872878
}
873879

880+
static __always_inline
881+
s32 pick_sticky_mod_cpu(struct llc_ctx *llc, struct layer *layer, s32 prev_cpu)
882+
{
883+
u64 time = bpf_ktime_get_ns();
884+
const struct cpumask *cpumask;
885+
struct cpu_ctx *cpu_ctx;
886+
s32 cpu = -1;
887+
int i;
888+
889+
if (!active_sticky_mod)
890+
return 0;
891+
bpf_printk("active!");
892+
893+
cpu_ctx = lookup_cpu_ctx(prev_cpu);
894+
if (!cpu_ctx)
895+
goto llc;
896+
if (cpu_ctx->sticky_mod_pred_pct < layer->sticky_mod_pred_pct)
897+
goto llc;
898+
if (cpu_ctx->sticky_mod_end_time_ns - time > layer->sticky_mod_min_ns)
899+
goto llc;
900+
return prev_cpu;
901+
llc:
902+
if (!(cpumask = cast_mask(llc->cpumask)))
903+
goto out;
904+
bpf_for(i, 0, nr_possible_cpus) {
905+
if (i == prev_cpu)
906+
continue;
907+
if (!bpf_cpumask_test_cpu(i, cpumask))
908+
continue;
909+
if (!(cpu_ctx = lookup_cpu_ctx(i)))
910+
continue;
911+
if (cpu_ctx->sticky_mod_pred_pct < layer->sticky_mod_pred_pct)
912+
continue;
913+
if (cpu_ctx->sticky_mod_end_time_ns - time > layer->sticky_mod_min_ns)
914+
continue;
915+
cpu = i;
916+
break;
917+
}
918+
out:
919+
return cpu;
920+
}
921+
874922
static __always_inline
875923
s32 pick_idle_cpu(struct task_struct *p, s32 prev_cpu,
876924
struct cpu_ctx *cpuc, struct task_ctx *taskc, struct layer *layer,
@@ -987,6 +1035,9 @@ s32 pick_idle_cpu(struct task_struct *p, s32 prev_cpu,
9871035
cpu = -1;
9881036
goto out_put;
9891037
}
1038+
1039+
if ((cpu = pick_sticky_mod_cpu(prev_llcc, layer, prev_cpu)) >= 0)
1040+
goto out_put;
9901041
}
9911042

9921043
/*
@@ -1195,6 +1246,55 @@ static void layer_kick_idle_cpu(struct layer *layer)
11951246
scx_bpf_put_idle_cpumask(idle_smtmask);
11961247
}
11971248

1249+
SEC("tp_btf/sched_switch")
1250+
int BPF_PROG(layered_sched_switch, bool ignore, struct task_struct *prev, struct task_struct *next)
1251+
{
1252+
u64 time = bpf_ktime_get_ns();
1253+
u64 duration = time, max = 0;
1254+
u32 beg = 0, end = 50000, i;
1255+
struct task_ctx *pc, *nc;
1256+
struct cpu_ctx *c;
1257+
u32 max_i = 0;
1258+
1259+
if (!active_sticky_mod)
1260+
return 0;
1261+
1262+
if (!(pc = lookup_task_ctx_may_fail(prev)))
1263+
goto next;
1264+
1265+
duration -= pc->sticky_mod_start_ns;
1266+
duration /= 1000;
1267+
1268+
pc->sticky_mod_nr_cnt++;
1269+
1270+
for (i = 0; i < STICKY_MOD_NR_BUCKETS; i++) {
1271+
u64 cnt = pc->sticky_mod_buckets[i];
1272+
1273+
if (duration >= beg && duration <= end) {
1274+
pc->sticky_mod_buckets[i]++;
1275+
cnt++;
1276+
}
1277+
if (max < cnt) {
1278+
max = cnt;
1279+
max_i = i;
1280+
}
1281+
beg += 50000;
1282+
end += 50000;
1283+
if (i == STICKY_MOD_NR_BUCKETS - 2)
1284+
end = -1;
1285+
}
1286+
1287+
if (!(c = lookup_cpu_ctx(-1)))
1288+
goto next;
1289+
c->sticky_mod_end_time_ns = (max_i + 1) * 50000;
1290+
c->sticky_mod_pred_pct = (max / pc->sticky_mod_nr_cnt);
1291+
next:
1292+
if (!(nc = lookup_task_ctx_may_fail(next)))
1293+
return 0;
1294+
nc->sticky_mod_start_ns = time;
1295+
return 0;
1296+
}
1297+
11981298
void BPF_STRUCT_OPS(layered_enqueue, struct task_struct *p, u64 enq_flags)
11991299
{
12001300
struct cpu_ctx *cpuc, *task_cpuc;
@@ -1718,6 +1818,9 @@ static __always_inline bool try_consume_layer(u32 layer_id, struct cpu_ctx *cpuc
17181818
xllc_mig_skipped = true;
17191819
continue;
17201820
}
1821+
1822+
if (pick_sticky_mod_cpu(remote_llcc, layer, -1) >= 0)
1823+
continue;
17211824
}
17221825

17231826
if (scx_bpf_dsq_move_to_local(layer_dsq_id(layer_id, *llc_idp)))
@@ -3174,6 +3277,9 @@ static s32 init_layer(int layer_id)
31743277
return ret;
31753278
}
31763279

3280+
if (layer->sticky_mod_min_ns || layer->sticky_mod_pred_pct)
3281+
active_sticky_mod++;
3282+
31773283
return 0;
31783284
}
31793285

scheds/rust/scx_layered/src/config.rs

+4
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ pub struct LayerCommon {
122122
pub nodes: Vec<usize>,
123123
#[serde(default)]
124124
pub llcs: Vec<usize>,
125+
#[serde(default)]
126+
pub sticky_mod_min_us: f64,
127+
#[serde(default)]
128+
pub sticky_mod_pred_pct: f64,
125129
}
126130

127131
#[derive(Clone, Debug, Serialize, Deserialize)]

scheds/rust/scx_layered/src/main.rs

+23
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ lazy_static! {
123123
perf: 1024,
124124
nodes: vec![],
125125
llcs: vec![],
126+
sticky_mod_min_us: 0.0,
127+
sticky_mod_pred_pct: 0.0,
126128
},
127129
},
128130
},
@@ -154,6 +156,8 @@ lazy_static! {
154156
idle_resume_us: None,
155157
nodes: vec![],
156158
llcs: vec![],
159+
sticky_mod_min_us: 0.0,
160+
sticky_mod_pred_pct: 0.0,
157161
},
158162
},
159163
},
@@ -189,6 +193,8 @@ lazy_static! {
189193
idle_resume_us: None,
190194
nodes: vec![],
191195
llcs: vec![],
196+
sticky_mod_min_us: 0.0,
197+
sticky_mod_pred_pct: 0.0,
192198
},
193199
},
194200
},
@@ -221,6 +227,8 @@ lazy_static! {
221227
idle_resume_us: None,
222228
nodes: vec![],
223229
llcs: vec![],
230+
sticky_mod_min_us: 0.0,
231+
sticky_mod_pred_pct: 0.0,
224232
},
225233
},
226234
},
@@ -428,6 +436,17 @@ lazy_static! {
428436
/// the nodes value is set the cpuset of LLCs will be or'ed with the nodes
429437
/// config.
430438
///
439+
/// - sticky_mod_min_us: Skip cross-CPU migration if the previous CPU is likely
440+
/// to be available for execution sooner than this threshold, same applies for
441+
/// one of the CPUs in the previous LLC.
442+
///
443+
/// - sticky_mod_pred_pct: The percentage threshold to decide whether to stick
444+
/// to previous CPU, or one of the CPUs in the previous LLC, opening up. It
445+
/// is compared against the percentage of times the process stayed in a
446+
/// predictable bucket of execution time, increasing confidence on
447+
/// predictions. E.g. 90 would mean only processes predictable with 90%
448+
/// accuracy or more will be chosen for stickiness modulation.
449+
///
431450
///
432451
/// Similar to matches, adding new policies and extending existing ones
433452
/// should be relatively straightforward.
@@ -1318,6 +1337,8 @@ impl<'a> Scheduler<'a> {
13181337
disallow_open_after_us,
13191338
disallow_preempt_after_us,
13201339
xllc_mig_min_us,
1340+
sticky_mod_min_us,
1341+
sticky_mod_pred_pct,
13211342
..
13221343
} = spec.kind.common();
13231344

@@ -1359,6 +1380,8 @@ impl<'a> Scheduler<'a> {
13591380
}
13601381
layer.llc_mask |= llcmask_from_llcs(&topo_node.llcs) as u64;
13611382
}
1383+
layer.sticky_mod_min_ns = (sticky_mod_min_us * 1000.0) as u64;
1384+
layer.sticky_mod_pred_pct = sticky_mod_pred_pct.clamp(0.0, 100.0) as u64;
13621385
}
13631386

13641387
layer.is_protected.write(match spec.kind {

0 commit comments

Comments
 (0)