Skip to content

Commit 96a06be

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

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed

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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 105 additions & 0 deletions
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,47 @@ 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 cpu;
891+
892+
cpu_ctx = lookup_cpu_ctx(prev_cpu);
893+
if (!cpu_ctx)
894+
goto llc;
895+
if (cpu_ctx->sticky_mod_pred_pct < layer->sticky_mod_pred_pct)
896+
goto llc;
897+
if (cpu_ctx->sticky_mod_end_time_ns - time > layer->sticky_mod_min_ns)
898+
goto llc;
899+
return prev_cpu;
900+
llc:
901+
if (!(cpumask = cast_mask(llc->cpumask)))
902+
goto out;
903+
bpf_for(i, 0, nr_possible_cpus) {
904+
if (i == prev_cpu)
905+
continue;
906+
if (!bpf_cpumask_test_cpu(i, cpumask))
907+
continue;
908+
if (!(cpu_ctx = lookup_cpu_ctx(i)))
909+
continue;
910+
if (cpu_ctx->sticky_mod_pred_pct < layer->sticky_mod_pred_pct)
911+
continue;
912+
if (cpu_ctx->sticky_mod_end_time_ns - time > layer->sticky_mod_min_ns)
913+
continue;
914+
cpu = i;
915+
break;
916+
}
917+
out:
918+
return cpu;
919+
}
920+
874921
static __always_inline
875922
s32 pick_idle_cpu(struct task_struct *p, s32 prev_cpu,
876923
struct cpu_ctx *cpuc, struct task_ctx *taskc, struct layer *layer,
@@ -987,6 +1034,9 @@ s32 pick_idle_cpu(struct task_struct *p, s32 prev_cpu,
9871034
cpu = -1;
9881035
goto out_put;
9891036
}
1037+
1038+
if ((cpu = pick_sticky_mod_cpu(prev_llcc, layer, prev_cpu)) >= 0)
1039+
goto out_put;
9901040
}
9911041

9921042
/*
@@ -1195,6 +1245,55 @@ static void layer_kick_idle_cpu(struct layer *layer)
11951245
scx_bpf_put_idle_cpumask(idle_smtmask);
11961246
}
11971247

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

17231825
if (scx_bpf_dsq_move_to_local(layer_dsq_id(layer_id, *llc_idp)))
@@ -3174,6 +3276,9 @@ static s32 init_layer(int layer_id)
31743276
return ret;
31753277
}
31763278

3279+
if (layer->sticky_mod_min_ns || layer->sticky_mod_pred_pct)
3280+
active_sticky_mod++;
3281+
31773282
return 0;
31783283
}
31793284

scheds/rust/scx_layered/src/config.rs

Lines changed: 4 additions & 0 deletions
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

Lines changed: 23 additions & 0 deletions
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)