Skip to content
This repository was archived by the owner on Jun 18, 2024. It is now read-only.

Commit 0426192

Browse files
Dan Schatzberghtejun
authored andcommitted
sched_ext: Add a rust userspace hybrid example scheduler
Atropos is a multi-domain BPF / userspace hybrid scheduler where the BPF part does simple round robin in each domain and the userspace part calculates the load factor of each domain and tells the BPF part how to load balance the domains. This scheduler demonstrates dividing scheduling logic between BPF and userspace and using rust to build the userspace part. An earlier variant of this scheduler was used to balance across six domains, each representing a chiplet in a six-chiplet AMD processor, and could match the performance of production setup using CFS. v3: * The userspace code is substantially restructured and rewritten. The binary is renamed to scx_atropos and can now figure out the domain topology automatically based on L3 cache configuration. The LB logic which was rather broken in the previous postings are revamped and should behave better. * Updated to support weighted vtime scheduling (can be turned off with --fifo-sched). Added a couple options (--slice_us, --kthreads-local) to modify scheduling behaviors. * Converted to use BPF inline iterators. v2: * Updated to use generic BPF cpumask helpers. Signed-off-by: Dan Schatzberg <dschatzberg@meta.com> Signed-off-by: Tejun Heo <tj@kernel.org>
1 parent 2004d31 commit 0426192

File tree

9 files changed

+1867
-2
lines changed

9 files changed

+1867
-2
lines changed

tools/sched_ext/Makefile

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ CFLAGS += -g -O2 -rdynamic -pthread -Wall -Werror $(GENFLAGS) \
8585
-I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
8686
-I$(TOOLSINCDIR) -I$(APIDIR)
8787

88+
CARGOFLAGS := --release
89+
8890
# Silence some warnings when compiled with clang
8991
ifneq ($(LLVM),)
9092
CFLAGS += -Wno-unused-command-line-argument
@@ -116,7 +118,7 @@ BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \
116118
-O2 -mcpu=v3
117119

118120
all: scx_example_simple scx_example_qmap scx_example_central scx_example_pair \
119-
scx_example_flatcg scx_example_userland
121+
scx_example_flatcg scx_example_userland atropos
120122

121123
# sort removes libbpf duplicates when not cross-building
122124
MAKE_DIRS := $(sort $(BUILD_DIR)/libbpf $(HOST_BUILD_DIR)/libbpf \
@@ -192,13 +194,20 @@ scx_example_userland: scx_example_userland.c scx_example_userland.skel.h \
192194
$(CC) $(CFLAGS) -c $< -o $@.o
193195
$(CC) -o $@ $@.o $(HOST_BPFOBJ) $(LDFLAGS)
194196

197+
atropos: export RUSTFLAGS = -C link-args=-lzstd -C link-args=-lz -C link-args=-lelf -L $(BPFOBJ_DIR)
198+
atropos: export ATROPOS_CLANG = $(CLANG)
199+
atropos: export ATROPOS_BPF_CFLAGS = $(BPF_CFLAGS)
200+
atropos: $(INCLUDE_DIR)/vmlinux.h
201+
cargo build --manifest-path=atropos/Cargo.toml $(CARGOFLAGS)
202+
195203
clean:
204+
cargo clean --manifest-path=atropos/Cargo.toml
196205
rm -rf $(SCRATCH_DIR) $(HOST_SCRATCH_DIR)
197206
rm -f *.o *.bpf.o *.skel.h *.subskel.h
198207
rm -f scx_example_simple scx_example_qmap scx_example_central \
199208
scx_example_pair scx_example_flatcg scx_example_userland
200209

201-
.PHONY: all clean
210+
.PHONY: all atropos clean
202211

203212
# delete failed targets
204213
.DELETE_ON_ERROR:

tools/sched_ext/atropos/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
src/bpf/.output
2+
Cargo.lock
3+
target

tools/sched_ext/atropos/Cargo.toml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
name = "scx_atropos"
3+
version = "0.5.0"
4+
authors = ["Dan Schatzberg <dschatzberg@meta.com>", "Meta"]
5+
edition = "2021"
6+
description = "Userspace scheduling with BPF"
7+
license = "GPL-2.0-only"
8+
9+
[dependencies]
10+
anyhow = "1.0.65"
11+
bitvec = { version = "1.0", features = ["serde"] }
12+
clap = { version = "4.1", features = ["derive", "env", "unicode", "wrap_help"] }
13+
ctrlc = { version = "3.1", features = ["termination"] }
14+
fb_procfs = { git = "https://github.com/facebookincubator/below.git", rev = "f305730"}
15+
hex = "0.4.3"
16+
libbpf-rs = "0.19.1"
17+
libbpf-sys = { version = "1.0.4", features = ["novendor", "static"] }
18+
libc = "0.2.137"
19+
log = "0.4.17"
20+
ordered-float = "3.4.0"
21+
simplelog = "0.12.0"
22+
23+
[build-dependencies]
24+
bindgen = { version = "0.61.0", features = ["logging", "static"], default-features = false }
25+
libbpf-cargo = "0.13.0"
26+
27+
[features]
28+
enable_backtrace = []

tools/sched_ext/atropos/build.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright (c) Meta Platforms, Inc. and affiliates.
2+
3+
// This software may be used and distributed according to the terms of the
4+
// GNU General Public License version 2.
5+
extern crate bindgen;
6+
7+
use std::env;
8+
use std::fs::create_dir_all;
9+
use std::path::Path;
10+
use std::path::PathBuf;
11+
12+
use libbpf_cargo::SkeletonBuilder;
13+
14+
const HEADER_PATH: &str = "src/bpf/atropos.h";
15+
16+
fn bindgen_atropos() {
17+
// Tell cargo to invalidate the built crate whenever the wrapper changes
18+
println!("cargo:rerun-if-changed={}", HEADER_PATH);
19+
20+
// The bindgen::Builder is the main entry point
21+
// to bindgen, and lets you build up options for
22+
// the resulting bindings.
23+
let bindings = bindgen::Builder::default()
24+
// The input header we would like to generate
25+
// bindings for.
26+
.header(HEADER_PATH)
27+
// Tell cargo to invalidate the built crate whenever any of the
28+
// included header files changed.
29+
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
30+
// Finish the builder and generate the bindings.
31+
.generate()
32+
// Unwrap the Result and panic on failure.
33+
.expect("Unable to generate bindings");
34+
35+
// Write the bindings to the $OUT_DIR/bindings.rs file.
36+
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
37+
bindings
38+
.write_to_file(out_path.join("atropos-sys.rs"))
39+
.expect("Couldn't write bindings!");
40+
}
41+
42+
fn gen_bpf_sched(name: &str) {
43+
let bpf_cflags = env::var("ATROPOS_BPF_CFLAGS").unwrap();
44+
let clang = env::var("ATROPOS_CLANG").unwrap();
45+
eprintln!("{}", clang);
46+
let outpath = format!("./src/bpf/.output/{}.skel.rs", name);
47+
let skel = Path::new(&outpath);
48+
let src = format!("./src/bpf/{}.bpf.c", name);
49+
SkeletonBuilder::new()
50+
.source(src.clone())
51+
.clang(clang)
52+
.clang_args(bpf_cflags)
53+
.build_and_generate(&skel)
54+
.unwrap();
55+
println!("cargo:rerun-if-changed={}", src);
56+
}
57+
58+
fn main() {
59+
bindgen_atropos();
60+
// It's unfortunate we cannot use `OUT_DIR` to store the generated skeleton.
61+
// Reasons are because the generated skeleton contains compiler attributes
62+
// that cannot be `include!()`ed via macro. And we cannot use the `#[path = "..."]`
63+
// trick either because you cannot yet `concat!(env!("OUT_DIR"), "/skel.rs")` inside
64+
// the path attribute either (see https://github.com/rust-lang/rust/pull/83366).
65+
//
66+
// However, there is hope! When the above feature stabilizes we can clean this
67+
// all up.
68+
create_dir_all("./src/bpf/.output").unwrap();
69+
gen_bpf_sched("atropos");
70+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Get help on options with `rustfmt --help=config`
2+
# Please keep these in alphabetical order.
3+
edition = "2021"
4+
group_imports = "StdExternalCrate"
5+
imports_granularity = "Item"
6+
merge_derives = false
7+
use_field_init_shorthand = true
8+
version = "Two"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) Meta Platforms, Inc. and affiliates.
2+
3+
// This software may be used and distributed according to the terms of the
4+
// GNU General Public License version 2.
5+
#![allow(non_upper_case_globals)]
6+
#![allow(non_camel_case_types)]
7+
#![allow(non_snake_case)]
8+
#![allow(dead_code)]
9+
10+
include!(concat!(env!("OUT_DIR"), "/atropos-sys.rs"));

0 commit comments

Comments
 (0)