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

Commit

Permalink
sched_ext: Add a rust userspace hybrid example scheduler
Browse files Browse the repository at this point in the history
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.

v2: Updated to use generic BPF cpumask helpers.

Signed-off-by: Dan Schatzberg <[email protected]>
Signed-off-by: Tejun Heo <[email protected]>
  • Loading branch information
Dan Schatzberg authored and htejun committed Jan 27, 2023
1 parent 7c97780 commit 314818d
Show file tree
Hide file tree
Showing 11 changed files with 1,507 additions and 2 deletions.
13 changes: 11 additions & 2 deletions tools/sched_ext/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ CFLAGS += -g -O2 -rdynamic -pthread -Wall -Werror $(GENFLAGS) \
-I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
-I$(TOOLSINCDIR) -I$(APIDIR)

CARGOFLAGS := --release

# Silence some warnings when compiled with clang
ifneq ($(LLVM),)
CFLAGS += -Wno-unused-command-line-argument
Expand Down Expand Up @@ -116,7 +118,7 @@ BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \
-O2 -mcpu=v3

all: scx_example_dummy scx_example_qmap scx_example_central scx_example_pair \
scx_example_userland
scx_example_userland atropos

# sort removes libbpf duplicates when not cross-building
MAKE_DIRS := $(sort $(BUILD_DIR)/libbpf $(HOST_BUILD_DIR)/libbpf \
Expand Down Expand Up @@ -188,13 +190,20 @@ scx_example_userland: scx_example_userland.c scx_example_userland.skel.h \
$(CC) $(CFLAGS) -c $< -o $@.o
$(CC) -o $@ $@.o $(HOST_BPFOBJ) $(LDFLAGS)

atropos: export RUSTFLAGS = -C link-args=-lzstd -C link-args=-lz -C link-args=-lelf -L $(BPFOBJ_DIR)
atropos: export ATROPOS_CLANG = $(CLANG)
atropos: export ATROPOS_BPF_CFLAGS = $(BPF_CFLAGS)
atropos: $(INCLUDE_DIR)/vmlinux.h
cargo build --manifest-path=atropos/Cargo.toml $(CARGOFLAGS)

clean:
cargo clean --manifest-path=atropos/Cargo.toml
rm -rf $(SCRATCH_DIR) $(HOST_SCRATCH_DIR)
rm -f *.o *.bpf.o *.skel.h *.subskel.h
rm -f scx_example_dummy scx_example_qmap scx_example_central \
scx_example_pair scx_example_userland

.PHONY: all clean
.PHONY: all atropos clean

# delete failed targets
.DELETE_ON_ERROR:
Expand Down
3 changes: 3 additions & 0 deletions tools/sched_ext/atropos/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
src/bpf/.output
Cargo.lock
target
28 changes: 28 additions & 0 deletions tools/sched_ext/atropos/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "atropos-bin"
version = "0.5.0"
authors = ["Dan Schatzberg <[email protected]>", "Meta"]
edition = "2021"
description = "Userspace scheduling with BPF"
license = "GPL-2.0-only"

[dependencies]
anyhow = "1.0.65"
bitvec = { version = "1.0", features = ["serde"] }
clap = { version = "3.2.17", features = ["derive", "env", "regex", "unicode", "wrap_help"] }
ctrlc = { version = "3.1", features = ["termination"] }
fb_procfs = { git = "https://github.com/facebookincubator/below.git", rev = "f305730"}
hex = "0.4.3"
libbpf-rs = "0.19.1"
libbpf-sys = { version = "1.0.4", features = ["novendor", "static"] }
libc = "0.2.137"
slog = { version = "2.7", features = ["max_level_trace", "nested-values"] }
slog-async = { version = "2.3", features = ["nested-values"] }
slog-term = "2.8"

[build-dependencies]
bindgen = { version = "0.61.0", features = ["logging", "static"], default-features = false }
libbpf-cargo = "0.13.0"

[features]
enable_backtrace = []
70 changes: 70 additions & 0 deletions tools/sched_ext/atropos/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Meta Platforms, Inc. and affiliates.

// This software may be used and distributed according to the terms of the
// GNU General Public License version 2.
extern crate bindgen;

use std::env;
use std::fs::create_dir_all;
use std::path::Path;
use std::path::PathBuf;

use libbpf_cargo::SkeletonBuilder;

const HEADER_PATH: &str = "src/bpf/atropos.h";

fn bindgen_atropos() {
// Tell cargo to invalidate the built crate whenever the wrapper changes
println!("cargo:rerun-if-changed={}", HEADER_PATH);

// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header(HEADER_PATH)
// Tell cargo to invalidate the built crate whenever any of the
// included header files changed.
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");

// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("atropos-sys.rs"))
.expect("Couldn't write bindings!");
}

fn gen_bpf_sched(name: &str) {
let bpf_cflags = env::var("ATROPOS_BPF_CFLAGS").unwrap();
let clang = env::var("ATROPOS_CLANG").unwrap();
eprintln!("{}", clang);
let outpath = format!("./src/bpf/.output/{}.skel.rs", name);
let skel = Path::new(&outpath);
let src = format!("./src/bpf/{}.bpf.c", name);
SkeletonBuilder::new()
.source(src.clone())
.clang(clang)
.clang_args(bpf_cflags)
.build_and_generate(&skel)
.unwrap();
println!("cargo:rerun-if-changed={}", src);
}

fn main() {
bindgen_atropos();
// It's unfortunate we cannot use `OUT_DIR` to store the generated skeleton.
// Reasons are because the generated skeleton contains compiler attributes
// that cannot be `include!()`ed via macro. And we cannot use the `#[path = "..."]`
// trick either because you cannot yet `concat!(env!("OUT_DIR"), "/skel.rs")` inside
// the path attribute either (see https://github.com/rust-lang/rust/pull/83366).
//
// However, there is hope! When the above feature stabilizes we can clean this
// all up.
create_dir_all("./src/bpf/.output").unwrap();
gen_bpf_sched("atropos");
}
8 changes: 8 additions & 0 deletions tools/sched_ext/atropos/rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Get help on options with `rustfmt --help=config`
# Please keep these in alphabetical order.
edition = "2021"
group_imports = "StdExternalCrate"
imports_granularity = "Item"
merge_derives = false
use_field_init_shorthand = true
version = "Two"
Loading

0 comments on commit 314818d

Please sign in to comment.