Skip to content

Commit 8ade500

Browse files
authored
Merge pull request raspberrypi#20 from inwardvessel/resize_percpu_arrays_in_examples
use resizing of datasec maps in examples
2 parents 35aef07 + 845aec9 commit 8ade500

File tree

7 files changed

+112
-30
lines changed

7 files changed

+112
-30
lines changed

tools/sched_ext/scx_central.bpf.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,13 @@ char _license[] SEC("license") = "GPL";
5151

5252
enum {
5353
FALLBACK_DSQ_ID = 0,
54-
MAX_CPUS = 4096,
5554
MS_TO_NS = 1000LLU * 1000,
5655
TIMER_INTERVAL_NS = 1 * MS_TO_NS,
5756
};
5857

5958
const volatile bool switch_partial;
6059
const volatile s32 central_cpu;
61-
const volatile u32 nr_cpu_ids = 64; /* !0 for veristat, set during init */
60+
const volatile u32 nr_cpu_ids = 1; /* !0 for veristat, set during init */
6261

6362
u64 nr_total, nr_locals, nr_queued, nr_lost_pids;
6463
u64 nr_timers, nr_dispatches, nr_mismatches, nr_retries;
@@ -73,8 +72,8 @@ struct {
7372
} central_q SEC(".maps");
7473

7574
/* can't use percpu map due to bad lookups */
76-
static bool cpu_gimme_task[MAX_CPUS];
77-
static u64 cpu_started_at[MAX_CPUS];
75+
bool RESIZABLE_ARRAY(data, cpu_gimme_task);
76+
u64 RESIZABLE_ARRAY(data, cpu_started_at);
7877

7978
struct central_timer {
8079
struct bpf_timer timer;
@@ -189,7 +188,7 @@ void BPF_STRUCT_OPS(central_dispatch, s32 cpu, struct task_struct *prev)
189188
break;
190189

191190
/* central's gimme is never set */
192-
gimme = MEMBER_VPTR(cpu_gimme_task, [cpu]);
191+
gimme = ARRAY_ELEM_PTR(cpu_gimme_task, cpu, nr_cpu_ids);
193192
if (gimme && !*gimme)
194193
continue;
195194

@@ -220,7 +219,7 @@ void BPF_STRUCT_OPS(central_dispatch, s32 cpu, struct task_struct *prev)
220219
if (scx_bpf_consume(FALLBACK_DSQ_ID))
221220
return;
222221

223-
gimme = MEMBER_VPTR(cpu_gimme_task, [cpu]);
222+
gimme = ARRAY_ELEM_PTR(cpu_gimme_task, cpu, nr_cpu_ids);
224223
if (gimme)
225224
*gimme = true;
226225

@@ -235,15 +234,15 @@ void BPF_STRUCT_OPS(central_dispatch, s32 cpu, struct task_struct *prev)
235234
void BPF_STRUCT_OPS(central_running, struct task_struct *p)
236235
{
237236
s32 cpu = scx_bpf_task_cpu(p);
238-
u64 *started_at = MEMBER_VPTR(cpu_started_at, [cpu]);
237+
u64 *started_at = ARRAY_ELEM_PTR(cpu_started_at, cpu, nr_cpu_ids);
239238
if (started_at)
240239
*started_at = bpf_ktime_get_ns() ?: 1; /* 0 indicates idle */
241240
}
242241

243242
void BPF_STRUCT_OPS(central_stopping, struct task_struct *p, bool runnable)
244243
{
245244
s32 cpu = scx_bpf_task_cpu(p);
246-
u64 *started_at = MEMBER_VPTR(cpu_started_at, [cpu]);
245+
u64 *started_at = ARRAY_ELEM_PTR(cpu_started_at, cpu, nr_cpu_ids);
247246
if (started_at)
248247
*started_at = 0;
249248
}
@@ -262,7 +261,7 @@ static int central_timerfn(void *map, int *key, struct bpf_timer *timer)
262261
continue;
263262

264263
/* kick iff the current one exhausted its slice */
265-
started_at = MEMBER_VPTR(cpu_started_at, [cpu]);
264+
started_at = ARRAY_ELEM_PTR(cpu_started_at, cpu, nr_cpu_ids);
266265
if (started_at && *started_at &&
267266
vtime_before(now, *started_at + SCX_SLICE_DFL))
268267
continue;

tools/sched_ext/scx_central.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ int main(int argc, char **argv)
6363
}
6464
}
6565

66+
/* Resize arrays so their element count is equal to cpu count. */
67+
RESIZE_ARRAY(data, cpu_gimme_task, skel->rodata->nr_cpu_ids);
68+
RESIZE_ARRAY(data, cpu_started_at, skel->rodata->nr_cpu_ids);
69+
6670
SCX_BUG_ON(scx_central__load(skel), "Failed to load skel");
6771

6872
link = bpf_map__attach_struct_ops(skel->maps.central_ops);

tools/sched_ext/scx_common.bpf.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,26 @@ BPF_PROG(name, ##args)
8181
SEC("struct_ops.s/"#name) \
8282
BPF_PROG(name, ##args)
8383

84+
/**
85+
* RESIZABLE_ARRAY - Generates annotations for an array that may be resized
86+
* @elfsec: the data section of the BPF program in which to place the array
87+
* @arr: the name of the array
88+
*
89+
* libbpf has an API for setting map value sizes. Since data sections (i.e.
90+
* bss, data, rodata) themselves are maps, a data section can be resized. If
91+
* a data section has an array as its last element, the BTF info for that
92+
* array will be adjusted so that length of the array is extended to meet the
93+
* new length of the data section. This macro annotates an array to have an
94+
* element count of one with the assumption that this array can be resized
95+
* within the userspace program. It also annotates the section specifier so
96+
* this array exists in a custom sub data section which can be resized
97+
* independently.
98+
*
99+
* See RESIZE_ARRAY() for the userspace convenience macro for resizing an
100+
* array declared with RESIZABLE_ARRAY().
101+
*/
102+
#define RESIZABLE_ARRAY(elfsec, arr) arr[1] SEC("."#elfsec"."#arr)
103+
84104
/**
85105
* MEMBER_VPTR - Obtain the verified pointer to a struct or array member
86106
* @base: struct or array to index
@@ -117,6 +137,34 @@ BPF_PROG(name, ##args)
117137
__addr; \
118138
})
119139

140+
/**
141+
* ARRAY_ELEM_PTR - Obtain the verified pointer to an array element
142+
* @arr: array to index into
143+
* @i: array index
144+
* @n: number of elements in array
145+
*
146+
* Similar to MEMBER_VPTR() but is intended for use with arrays where the
147+
* element count needs to be explicit.
148+
* It can be used in cases where a global array is defined with an initial
149+
* size but is intended to be be resized before loading the BPF program.
150+
* Without this version of the macro, MEMBER_VPTR() will use the compile time
151+
* size of the array to compute the max, which will result in rejection by
152+
* the verifier.
153+
*/
154+
#define ARRAY_ELEM_PTR(arr, i, n) (typeof(arr[i]) *)({ \
155+
u64 __base = (u64)arr; \
156+
u64 __addr = (u64)&(arr[i]) - __base; \
157+
asm volatile ( \
158+
"if %0 <= %[max] goto +2\n" \
159+
"%0 = 0\n" \
160+
"goto +1\n" \
161+
"%0 += %1\n" \
162+
: "+r"(__addr) \
163+
: "r"(__base), \
164+
[max]"r"(sizeof(arr[0]) * ((n) - 1))); \
165+
__addr; \
166+
})
167+
120168
/*
121169
* BPF core and other generic helpers
122170
*/

tools/sched_ext/scx_pair.bpf.c

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,19 @@ char _license[] SEC("license") = "GPL";
123123
const volatile bool switch_partial;
124124

125125
/* !0 for veristat, set during init */
126-
const volatile u32 nr_cpu_ids = 64;
126+
const volatile u32 nr_cpu_ids = 1;
127127

128128
/* a pair of CPUs stay on a cgroup for this duration */
129129
const volatile u32 pair_batch_dur_ns = SCX_SLICE_DFL;
130130

131131
/* cpu ID -> pair cpu ID */
132-
const volatile s32 pair_cpu[MAX_CPUS] = { [0 ... MAX_CPUS - 1] = -1 };
132+
const volatile s32 RESIZABLE_ARRAY(rodata, pair_cpu);
133133

134134
/* cpu ID -> pair_id */
135-
const volatile u32 pair_id[MAX_CPUS];
135+
const volatile u32 RESIZABLE_ARRAY(rodata, pair_id);
136136

137137
/* CPU ID -> CPU # in the pair (0 or 1) */
138-
const volatile u32 in_pair_idx[MAX_CPUS];
138+
const volatile u32 RESIZABLE_ARRAY(rodata, in_pair_idx);
139139

140140
struct pair_ctx {
141141
struct bpf_spin_lock lock;
@@ -161,7 +161,6 @@ struct pair_ctx {
161161

162162
struct {
163163
__uint(type, BPF_MAP_TYPE_ARRAY);
164-
__uint(max_entries, MAX_CPUS / 2);
165164
__type(key, u32);
166165
__type(value, struct pair_ctx);
167166
} pair_ctx SEC(".maps");
@@ -299,15 +298,15 @@ static int lookup_pairc_and_mask(s32 cpu, struct pair_ctx **pairc, u32 *mask)
299298
{
300299
u32 *vptr;
301300

302-
vptr = (u32 *)MEMBER_VPTR(pair_id, [cpu]);
301+
vptr = (u32 *)ARRAY_ELEM_PTR(pair_id, cpu, nr_cpu_ids);
303302
if (!vptr)
304303
return -EINVAL;
305304

306305
*pairc = bpf_map_lookup_elem(&pair_ctx, vptr);
307306
if (!(*pairc))
308307
return -EINVAL;
309308

310-
vptr = (u32 *)MEMBER_VPTR(in_pair_idx, [cpu]);
309+
vptr = (u32 *)ARRAY_ELEM_PTR(in_pair_idx, cpu, nr_cpu_ids);
311310
if (!vptr)
312311
return -EINVAL;
313312

@@ -490,7 +489,7 @@ static int try_dispatch(s32 cpu)
490489

491490
out_maybe_kick:
492491
if (kick_pair) {
493-
s32 *pair = (s32 *)MEMBER_VPTR(pair_cpu, [cpu]);
492+
s32 *pair = (s32 *)ARRAY_ELEM_PTR(pair_cpu, cpu, nr_cpu_ids);
494493
if (pair) {
495494
__sync_fetch_and_add(&nr_kicks, 1);
496495
scx_bpf_kick_cpu(*pair, SCX_KICK_PREEMPT);
@@ -525,7 +524,7 @@ void BPF_STRUCT_OPS(pair_cpu_acquire, s32 cpu, struct scx_cpu_acquire_args *args
525524
bpf_spin_unlock(&pairc->lock);
526525

527526
if (kick_pair) {
528-
s32 *pair = (s32 *)MEMBER_VPTR(pair_cpu, [cpu]);
527+
s32 *pair = (s32 *)ARRAY_ELEM_PTR(pair_cpu, cpu, nr_cpu_ids);
529528

530529
if (pair) {
531530
__sync_fetch_and_add(&nr_kicks, 1);
@@ -554,7 +553,7 @@ void BPF_STRUCT_OPS(pair_cpu_release, s32 cpu, struct scx_cpu_release_args *args
554553
bpf_spin_unlock(&pairc->lock);
555554

556555
if (kick_pair) {
557-
s32 *pair = (s32 *)MEMBER_VPTR(pair_cpu, [cpu]);
556+
s32 *pair = (s32 *)ARRAY_ELEM_PTR(pair_cpu, cpu, nr_cpu_ids);
558557

559558
if (pair) {
560559
__sync_fetch_and_add(&nr_kicks, 1);

tools/sched_ext/scx_pair.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,27 +67,37 @@ int main(int argc, char **argv)
6767
}
6868
}
6969

70+
bpf_map__set_max_entries(skel->maps.pair_ctx, skel->rodata->nr_cpu_ids / 2);
71+
72+
/* Resize arrays so their element count is equal to cpu count. */
73+
RESIZE_ARRAY(rodata, pair_cpu, skel->rodata->nr_cpu_ids);
74+
RESIZE_ARRAY(rodata, pair_id, skel->rodata->nr_cpu_ids);
75+
RESIZE_ARRAY(rodata, in_pair_idx, skel->rodata->nr_cpu_ids);
76+
77+
for (i = 0; i < skel->rodata->nr_cpu_ids; i++)
78+
skel->rodata_pair_cpu->pair_cpu[i] = -1;
79+
7080
printf("Pairs: ");
7181
for (i = 0; i < skel->rodata->nr_cpu_ids; i++) {
7282
int j = (i + stride) % skel->rodata->nr_cpu_ids;
7383

74-
if (skel->rodata->pair_cpu[i] >= 0)
84+
if (skel->rodata_pair_cpu->pair_cpu[i] >= 0)
7585
continue;
7686

7787
SCX_BUG_ON(i == j,
7888
"Invalid stride %d - CPU%d wants to be its own pair",
7989
stride, i);
8090

81-
SCX_BUG_ON(skel->rodata->pair_cpu[j] >= 0,
91+
SCX_BUG_ON(skel->rodata_pair_cpu->pair_cpu[j] >= 0,
8292
"Invalid stride %d - three CPUs (%d, %d, %d) want to be a pair",
83-
stride, i, j, skel->rodata->pair_cpu[j]);
84-
85-
skel->rodata->pair_cpu[i] = j;
86-
skel->rodata->pair_cpu[j] = i;
87-
skel->rodata->pair_id[i] = i;
88-
skel->rodata->pair_id[j] = i;
89-
skel->rodata->in_pair_idx[i] = 0;
90-
skel->rodata->in_pair_idx[j] = 1;
93+
stride, i, j, skel->rodata_pair_cpu->pair_cpu[j]);
94+
95+
skel->rodata_pair_cpu->pair_cpu[i] = j;
96+
skel->rodata_pair_cpu->pair_cpu[j] = i;
97+
skel->rodata_pair_id->pair_id[i] = i;
98+
skel->rodata_pair_id->pair_id[j] = i;
99+
skel->rodata_in_pair_idx->in_pair_idx[i] = 0;
100+
skel->rodata_in_pair_idx->in_pair_idx[j] = 1;
91101

92102
printf("[%d, %d] ", i, j);
93103
}

tools/sched_ext/scx_pair.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
#define __SCX_EXAMPLE_PAIR_H
33

44
enum {
5-
MAX_CPUS = 4096,
65
MAX_QUEUED = 4096,
76
MAX_CGRPS = 4096,
87
};

tools/sched_ext/scx_user_common.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,27 @@
3131
SCX_BUG((__fmt) __VA_OPT__(,) __VA_ARGS__); \
3232
} while (0)
3333

34+
/**
35+
* RESIZE_ARRAY - Convenience macro for resizing a BPF array
36+
* @elfsec: the data section of the BPF program in which to the array exists
37+
* @arr: the name of the array
38+
* @n: the desired array element count
39+
*
40+
* For BPF arrays declared with RESIZABLE_ARRAY(), this macro performs two
41+
* operations. It resizes the map which corresponds to the custom data
42+
* section that contains the target array. As a side effect, the BTF info for
43+
* the array is adjusted so that the array length is sized to cover the new
44+
* data section size. The second operation is reassigning the skeleton pointer
45+
* for that custom data section so that it points to the newly memory mapped
46+
* region.
47+
*/
48+
#define RESIZE_ARRAY(elfsec, arr, n) \
49+
do { \
50+
size_t __sz; \
51+
bpf_map__set_value_size(skel->maps.elfsec##_##arr, \
52+
sizeof(skel->elfsec##_##arr->arr[0]) * (n)); \
53+
skel->elfsec##_##arr = \
54+
bpf_map__initial_value(skel->maps.elfsec##_##arr, &__sz); \
55+
} while (0)
56+
3457
#endif /* __SCHED_EXT_USER_COMMON_H */

0 commit comments

Comments
 (0)