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.

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 <[email protected]>
Signed-off-by: Tejun Heo <[email protected]>
  • Loading branch information
Dan Schatzberg authored and htejun committed Mar 17, 2023
1 parent 2004d31 commit 0426192
Show file tree
Hide file tree
Showing 9 changed files with 1,867 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_simple scx_example_qmap scx_example_central scx_example_pair \
scx_example_flatcg scx_example_userland
scx_example_flatcg 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 @@ -192,13 +194,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_simple scx_example_qmap scx_example_central \
scx_example_pair scx_example_flatcg 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 = "scx_atropos"
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 = "4.1", features = ["derive", "env", "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"
log = "0.4.17"
ordered-float = "3.4.0"
simplelog = "0.12.0"

[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"
10 changes: 10 additions & 0 deletions tools/sched_ext/atropos/src/atropos_sys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// 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.
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]

include!(concat!(env!("OUT_DIR"), "/atropos-sys.rs"));
Loading

0 comments on commit 0426192

Please sign in to comment.