Skip to content

Commit 0dd6be6

Browse files
committed
scx_mitosis: add L3 awareness and work stealing
1 parent ba1924b commit 0dd6be6

File tree

4 files changed

+446
-139
lines changed

4 files changed

+446
-139
lines changed

scheds/rust/scx_mitosis/src/bpf/dsq.bpf.h

Lines changed: 98 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* This software may be used and distributed according to the terms of the
44
* GNU General Public License version 2.
55
*
6-
* This header defines the 32-bit dispatch queue (DSQ) ID encoding
6+
* This header defines the 64-bit dispatch queue (DSQ) ID encoding
77
* scheme for scx_mitosis, using type fields to distinguish between
88
* per-CPU and cell+L3 domain queues. It includes helper functions to
99
* construct, validate, and parse these DSQ IDs for queue management.
@@ -37,96 +37,138 @@
3737
* Only the low 32 bits are used.
3838
*
3939
* [63 .. 32] [31..0]
40-
* [ 0s or unused ] [ VAL ]
40+
* [ 0][ unused ] [ VAL ]
4141
*
4242
* Mitosis uses VAL as follows:
4343
*
44-
* [31..24] [23..0]
44+
* [31..28] [27..0]
4545
* [QTYPE ] [DATA ]
4646
*
47-
* QTYPE encodes the queue type (exactly one bit set):
47+
* QTYPE encodes the queue type:
4848
*
4949
* QTYPE = 0x1 -> Per-CPU Q
50-
* [31 .. 24] [23 .. 16] [15 .. 0]
51-
* [00000001] [00000000] [ CPU# ]
50+
* [31..28] [27 .. .. 0]
51+
* [ 0001 ] [ CPU# ]
5252
* [Q-TYPE:1]
5353
*
5454
* QTYPE = 0x2 -> Cell+L3 Q
55-
* [31 .. 24] [23 .. 16] [15 .. 0]
56-
* [00000010] [ CELL# ] [ L3ID ]
55+
* [31..28] [27 .. 16] [15 .. 0]
56+
* [ 0010 ] [ CELL# ] [ L3ID ]
5757
* [Q-TYPE:2]
5858
*
5959
*/
60+
/*
61+
* The use of these bitfields depends on compiler defined byte AND bit ordering.
62+
* Make sure we're only building with Clang/LLVM and that we're little-endian.
63+
*/
64+
#ifndef __clang__
65+
#error "This code must be compiled with Clang/LLVM (eBPF: clang -target bpf)."
66+
#endif
67+
68+
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
69+
#error "dsq64 bitfield layout assumes little-endian (bpfel)."
70+
#endif
71+
72+
/* ---- Bitfield widths (bits) ---- */
73+
#define CPU_B 28
74+
#define L3_B 16
75+
#define CELL_B 12
76+
#define TYPE_B 4
77+
#define DATA_B 28
78+
#define RSVD_B 32
79+
80+
/* Sum checks (in bits) */
81+
_Static_assert(CPU_B + TYPE_B == 32, "CPU layout low half must be 32 bits");
82+
_Static_assert(L3_B + CELL_B + TYPE_B == 32, "CELL+L3 layout low half must be 32 bits");
83+
_Static_assert(DATA_B + TYPE_B == 32, "Common layout low half must be 32 bits");
84+
85+
typedef union {
86+
u64 raw;
6087

61-
#define DSQ_ERROR 0xFFFFFFFF; /* Error value for DSQ functions */
88+
/* Per-CPU user DSQ */
89+
struct { u64 cpu: CPU_B; u64 type: TYPE_B; u64 rsvd: RSVD_B; } cpu_dsq;
90+
91+
/* Cell+L3 user DSQ */
92+
struct { u64 l3: L3_B; u64 cell: CELL_B; u64 type: TYPE_B; u64 rsvd: RSVD_B; } cell_l3_dsq;
93+
94+
/* Generic user view */
95+
struct { u64 data: DATA_B; u64 type: TYPE_B; u64 rsvd: RSVD_B; } user_dsq;
96+
97+
/* Built-in DSQ view */
98+
struct { u64 value:32; u64 rsvd:30; u64 local_on:1; u64 builtin:1; } builtin_dsq;
99+
100+
/* NOTE: Considered packed and aligned attributes, but that's redundant */
101+
} dsq_id_t;
102+
103+
/*
104+
* Invalid DSQ ID Sentinel:
105+
* invalid bc bit 63 clear (it's a user DSQ) && dsq_type == 0 (no type)
106+
* Good for catching uninitialized DSQ IDs.
107+
*/
108+
#define DSQ_INVALID ((u64) 0)
109+
110+
_Static_assert(sizeof(((dsq_id_t){0}).cpu_dsq) == sizeof(u64), "cpu view must be 8 bytes");
111+
_Static_assert(sizeof(((dsq_id_t){0}).cell_l3_dsq) == sizeof(u64), "cell+l3 view must be 8 bytes");
112+
_Static_assert(sizeof(((dsq_id_t){0}).user_dsq) == sizeof(u64), "user common view must be 8 bytes");
113+
_Static_assert(sizeof(((dsq_id_t){0}).builtin_dsq) == sizeof(u64), "builtin view must be 8 bytes");
114+
115+
/* Compile-time checks (in bytes) */
116+
_Static_assert(sizeof(dsq_id_t) == sizeof(u64), "dsq_id_t must be 8 bytes (64 bits)");
117+
_Static_assert(_Alignof(dsq_id_t) == sizeof(u64), "dsq_id_t must be 8-byte aligned");
62118

63119
/* DSQ type enumeration */
64120
enum dsq_type {
65-
DSQ_UNKNOWN,
121+
DSQ_TYPE_NONE,
66122
DSQ_TYPE_CPU,
67123
DSQ_TYPE_CELL_L3,
68124
};
69125

70-
/* DSQ ID structure using unions for type-safe access */
71-
struct dsq_cpu {
72-
u32 cpu : 16;
73-
u32 unused : 8;
74-
u32 type : 8;
75-
} __attribute__((packed));
76-
77-
struct dsq_cell_l3 {
78-
u32 l3 : 16;
79-
u32 cell : 8;
80-
u32 type : 8;
81-
} __attribute__((packed));
82-
83-
union dsq_id {
84-
u32 raw;
85-
struct dsq_cpu cpu;
86-
struct dsq_cell_l3 cell_l3;
87-
struct {
88-
u32 data : 24;
89-
u32 type : 8;
90-
} common;
91-
} __attribute__((packed));
92-
93-
/* Static assertions to ensure correct sizes */
94-
/* Verify that all DSQ structures are exactly 32 bits */
95-
_Static_assert(sizeof(struct dsq_cpu) == 4, "dsq_cpu must be 32 bits");
96-
_Static_assert(sizeof(struct dsq_cell_l3) == 4, "dsq_cell_l3 must be 32 bits");
97-
_Static_assert(sizeof(union dsq_id) == 4, "dsq_id union must be 32 bits");
98-
99-
/* Inline helper functions for DSQ ID manipulation */
126+
/* Range guards */
127+
_Static_assert(MAX_CPUS <= (1u << CPU_B), "MAX_CPUS must fit in field");
128+
_Static_assert(MAX_L3S <= (1u << L3_B), "MAX_L3S must fit in field");
129+
_Static_assert(MAX_CELLS <= (1u << CELL_B), "MAX_CELLS must fit in field");
130+
_Static_assert(DSQ_TYPE_CELL_L3 < (1u << TYPE_B), "DSQ_TYPE_CELL_L3 must fit in field");
131+
132+
/*
133+
* While I considered error propagation, I decided to bail to force errors early.
134+
*/
135+
136+
static inline bool is_user_dsq(dsq_id_t dsq_id){
137+
return !dsq_id.builtin_dsq.builtin && dsq_id.user_dsq.type != DSQ_TYPE_NONE;
138+
}
100139

101140
// Is this a per CPU DSQ?
102-
static inline bool is_cpu_dsq(u32 dsq_id)
141+
static inline bool is_cpu_dsq(dsq_id_t dsq_id)
103142
{
104-
union dsq_id id = { .raw = dsq_id };
105-
return id.common.type == DSQ_TYPE_CPU;
143+
return is_user_dsq(dsq_id) && dsq_id.user_dsq.type == DSQ_TYPE_CPU;
106144
}
107145

108146
// If this is a per cpu dsq, return the cpu
109-
static inline u32 get_cpu_from_dsq(u32 dsq_id)
147+
static inline u32 get_cpu_from_dsq(u64 id)
110148
{
111-
union dsq_id id = { .raw = dsq_id };
112-
if (id.common.type != DSQ_TYPE_CPU)
113-
return DSQ_ERROR;
114-
return id.cpu.cpu;
149+
dsq_id_t dsq_id = (dsq_id_t) {.raw = id};
150+
if (!is_cpu_dsq(dsq_id))
151+
scx_bpf_error("trying to get cpu from non-cpu dsq\n");
152+
153+
return dsq_id.cpu_dsq.cpu;
115154
}
116155

117156
/* Helper functions to construct DSQ IDs */
118-
static inline u32 get_cpu_dsq_id(u32 cpu)
157+
static inline u64 get_cpu_dsq_id(u32 cpu)
119158
{
159+
// Check for valid CPU range, 0 indexed so >=.
120160
if (cpu >= MAX_CPUS)
121-
return DSQ_ERROR;
122-
union dsq_id id = { .cpu = { .cpu = cpu, .unused = 0, .type = DSQ_TYPE_CPU } };
123-
return id.raw;
161+
scx_bpf_error("invalid cpu %u\n", cpu);
162+
dsq_id_t dsq_id = { .cpu_dsq = { .cpu = cpu, .type = DSQ_TYPE_CPU } };
163+
164+
return dsq_id.raw;
124165
}
125166

126-
static inline u32 get_cell_l3_dsq_id(u32 cell, u32 l3)
167+
static inline u64 get_cell_l3_dsq_id(u32 cell, u32 l3)
127168
{
128169
if (cell >= MAX_CELLS || l3 >= MAX_L3S)
129-
return DSQ_ERROR;
130-
union dsq_id id = { .cell_l3 = {.l3 = l3, .cell = cell, .type = DSQ_TYPE_CELL_L3 } };
131-
return id.raw;
170+
scx_bpf_error("cell %u or l3 %u too large\n", cell, l3);
171+
dsq_id_t dsq_id = { .cell_l3_dsq = { .l3 = l3, .cell = cell, .type = DSQ_TYPE_CELL_L3 } };
172+
173+
return dsq_id.raw;
132174
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ typedef _Bool bool;
2020

2121
/* ---- Work stealing config (compile-time) ------------------------------- */
2222
#ifndef MITOSIS_ENABLE_STEALING
23-
#define MITOSIS_ENABLE_STEALING 0
23+
#define MITOSIS_ENABLE_STEALING 1
2424
#endif
2525
/* ----------------------------------------------------------------------- */
2626

@@ -34,7 +34,6 @@ enum consts {
3434

3535
PCPU_BASE = 0x80000000,
3636
MAX_CG_DEPTH = 256,
37-
3837
};
3938

4039
/* Statistics */

0 commit comments

Comments
 (0)