Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scx_rusty: use arena-based CPU masks #1293

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

etsal
Copy link
Contributor

@etsal etsal commented Feb 3, 2025

The scx_rusty scheduler currently represents domains and tasks with arena-based structs, but cannot embed cpumasks into these fields as they are represented as kptrs. Introduce a cpumask type that is implemented as a BPF library and so can be embedded/pointed to by arena structs. Also add wrappers around kfuncs that take struct bpf_cpumask * arguments to transparently translate between our new internal cpumask type and the bpf_cpumask type expected by the calls.

Note: This code currently has really suboptimal bpf_cpumask to scxmask conversions that I am in the process of fixing. We'll need a kfunc for that but the rest of the code compiles and verifies just fine so it's a matter of solving this one isolated issue.

/* XXX HACK hardcoded MAX_CPUS / 8 from src/bpf/intf.h, right now this header is a mess */
struct scx_cpumask {
union sdt_id tid;
u8 mask[64];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use u64's? BPF is a lot more efficient with 64bit operations. With smaller types, it'd be generating a lot of masking and shifting instructions.

Copy link
Contributor Author

@etsal etsal Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure, cpumask_t also uses an array of longs for the mask so this would be consistent with the kernel bitmasks.

cast_kern(data);

mask = (scx_cpumask_t)data->payload;
mask->tid = data->tid;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine for now but I wonder whether allocation ID linking can be hidden inside sdt_alloc() down the line. It's a bit weird because sdt originally meant scx data for task and the tid is unique task ID. The names and explicit tid handling make sense for task data allocations but get confusing when generalized like this. Something to clean up down the line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tid is definitely a misnomer, because what we really care about is the idx of the allocation within the radix tree.

The reason the tid is embedded in the struct is to avoid having a separate KV map of arena pointers to idx'es. The sdt_task allocator must be able to match a struct proc to the arena allocation we've made for it, and that map also holds the TID in the value. For cpumasks we don't need that kind of map if we embed the tid in the struct.

The type-specific code in cpumask.h doesn't do anything with the TID, it just stores it. We can make a wrapper struct for the cpumasks to remove the tid from the actual struct we give out during allocations and completely hide tids from outside the allocator code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, later, we can create an allocation wrapper which puts the ID after the actual allocation (to not disturb alignment requirement) so that the detail can be hidden from allocator users.



__weak
int scxmask_set_cpu(u32 cpu, scx_cpumask_t __arg_arena mask)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are three prefixes in use - scx_cpumask, scx_mask and scxmask. If this can be generalized in terms of number of bits (which we do need), maybe use scx_bitmap? In kernel, cpumasks are just wrapping bitmaps too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do a rename pass to scx_bitmap, I used scxmask for function prefixes for brevity as opposed to scx_cpumask but that may have been more confusing than helpful.

int i;

bpf_for(i, 0, nr_cpu_ids) {
if (!scxmask_test_cpu(i, big) && bpf_cpumask_test_cpu(i, small))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done word by word, right? ~mask[i] & mask[j]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are different mask types and one of them is a kptr that we cannot dereference directly (there may be a way to do that with a kernel patch though? IIRC we can direclty read some fields from task_struct. Looking into it rn)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, can't we convert them and then just operate on the scx bitmasks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can, I will adjust these accordingly.

int i;

bpf_for(i, 0, nr_cpu_ids) {
if (scxmask_test_cpu(i, scx) && bpf_cpumask_test_cpu(i, cpu))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mask[i] & mask[j]

Copy link
Contributor Author

@etsal etsal Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Same as above) These are comparisons between a const struct cpumask * and an scxmask so we can't access the cpumask's bitmap directly AFAICT.

int i;

bpf_for(i, 0, nr_cpu_ids) {
if (scxmask_test_cpu(i, scx) && bpf_cpumask_test_cpu(i, cpu))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mask[i] &= mask[j]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants