mirror of
https://github.com/sched-ext/scx.git
synced 2024-11-25 04:00:24 +00:00
compat: Implement scx_utils::compat and fix up scx_layered
Implement scx_utils::compat to match C's scx/compat.h and update scx_layered. Other rust scheds are still broken.
This commit is contained in:
parent
891df57b98
commit
59bbd800c1
@ -15,7 +15,7 @@ include = [
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
libbpf-rs = "0.22.0"
|
libbpf-rs = "0.22"
|
||||||
libc = "0.2.137"
|
libc = "0.2.137"
|
||||||
buddy-alloc = "0.5.1"
|
buddy-alloc = "0.5.1"
|
||||||
scx_utils = { path = "../scx_utils", version = "0.6" }
|
scx_utils = { path = "../scx_utils", version = "0.6" }
|
||||||
@ -24,3 +24,8 @@ scx_utils = { path = "../scx_utils", version = "0.6" }
|
|||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
walkdir = "2.4"
|
walkdir = "2.4"
|
||||||
scx_utils = { path = "../scx_utils", version = "0.6" }
|
scx_utils = { path = "../scx_utils", version = "0.6" }
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
libbpf-sys = { git = "https://github.com/libbpf/libbpf-sys.git", rev = "75042c653ee956b8c262e41ca4bcfcb0e2c461a1" }
|
||||||
|
libbpf-rs = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "560641a5aff2c613dff6ae02147b0000558e4945" }
|
||||||
|
libbpf-cargo = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "7745f2e43c2bde59920b8b7400d62f66b906f05b" }
|
||||||
|
@ -17,9 +17,10 @@ glob = "0.3"
|
|||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
libbpf-cargo = "0.22"
|
libbpf-cargo = "0.22"
|
||||||
libbpf-rs = "0.22.0"
|
libbpf-rs = "0.22"
|
||||||
buddy-alloc = "0.5.1"
|
buddy-alloc = "0.5"
|
||||||
log = "0.4.17"
|
log = "0.4"
|
||||||
|
paste = "1.0"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
sscanf = "0.4"
|
sscanf = "0.4"
|
||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
@ -30,3 +31,8 @@ version-compare = "0.1"
|
|||||||
bindgen = ">=0.68, <0.70"
|
bindgen = ">=0.68, <0.70"
|
||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
walkdir = "2.4"
|
walkdir = "2.4"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
libbpf-sys = { git = "https://github.com/libbpf/libbpf-sys.git", rev = "125444300e2db452131dd6453101599c1a277784" }
|
||||||
|
libbpf-rs = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "560641a5aff2c613dff6ae02147b0000558e4945" }
|
||||||
|
libbpf-cargo = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "125444300e2db452131dd6453101599c1a277784" }
|
||||||
|
@ -478,14 +478,6 @@ impl BpfBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cflags_string(&self) -> String {
|
|
||||||
self.cflags
|
|
||||||
.iter()
|
|
||||||
.map(|x| x.as_str())
|
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.join(" ")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bindgen_bpf_intf(&self, deps: &mut BTreeSet<String>) -> Result<()> {
|
fn bindgen_bpf_intf(&self, deps: &mut BTreeSet<String>) -> Result<()> {
|
||||||
let (input, output) = match &self.intf_input_output {
|
let (input, output) = match &self.intf_input_output {
|
||||||
Some(pair) => pair,
|
Some(pair) => pair,
|
||||||
@ -538,7 +530,7 @@ impl BpfBuilder {
|
|||||||
.source(input)
|
.source(input)
|
||||||
.obj(&obj)
|
.obj(&obj)
|
||||||
.clang(&self.clang.0)
|
.clang(&self.clang.0)
|
||||||
.clang_args(self.cflags_string())
|
.clang_args(&self.cflags)
|
||||||
.build_and_generate(&skel_path)?;
|
.build_and_generate(&skel_path)?;
|
||||||
|
|
||||||
match &self.skel_deps {
|
match &self.skel_deps {
|
||||||
|
@ -45,6 +45,7 @@ impl Builder {
|
|||||||
let bindings = bindgen::Builder::default()
|
let bindings = bindgen::Builder::default()
|
||||||
.header("bindings.h")
|
.header("bindings.h")
|
||||||
.allowlist_type("scx_exit_kind")
|
.allowlist_type("scx_exit_kind")
|
||||||
|
.allowlist_type("scx_internal_consts")
|
||||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
||||||
.generate()
|
.generate()
|
||||||
.expect("Unable to generate bindings");
|
.expect("Unable to generate bindings");
|
||||||
|
180
rust/scx_utils/src/compat.rs
Normal file
180
rust/scx_utils/src/compat.rs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
|
use libbpf_rs::libbpf_sys::*;
|
||||||
|
use std::ffi::c_void;
|
||||||
|
use std::ffi::CStr;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::mem::size_of;
|
||||||
|
use std::slice::from_raw_parts;
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
pub static ref SCX_OPS_SWITCH_PARTIAL: u64 =
|
||||||
|
read_enum("scx_ops_flags", "SCX_OPS_SWITCH_PARTIAL").unwrap_or(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_vmlinux_btf() -> &'static mut btf {
|
||||||
|
let btf = unsafe { btf__load_vmlinux_btf() };
|
||||||
|
if btf.is_null() {
|
||||||
|
panic!("btf__load_vmlinux_btf() returned NULL");
|
||||||
|
}
|
||||||
|
unsafe { &mut *btf }
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref VMLINUX_BTF: &'static mut btf = load_vmlinux_btf();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btf_kind(t: &btf_type) -> u32 {
|
||||||
|
(t.info >> 24) & 0x1f
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btf_vlen(t: &btf_type) -> u32 {
|
||||||
|
t.info & 0xffff
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btf_type_plus_1(t: &btf_type) -> *const c_void {
|
||||||
|
let ptr_val = t as *const btf_type as usize;
|
||||||
|
(ptr_val + size_of::<btf_type>()) as *const c_void
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btf_enum(t: &btf_type) -> &[btf_enum] {
|
||||||
|
let ptr = btf_type_plus_1(t);
|
||||||
|
unsafe { from_raw_parts(ptr as *const btf_enum, btf_vlen(t) as usize) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btf_enum64(t: &btf_type) -> &[btf_enum64] {
|
||||||
|
let ptr = btf_type_plus_1(t);
|
||||||
|
unsafe { from_raw_parts(ptr as *const btf_enum64, btf_vlen(t) as usize) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btf_members(t: &btf_type) -> &[btf_member] {
|
||||||
|
let ptr = btf_type_plus_1(t);
|
||||||
|
unsafe { from_raw_parts(ptr as *const btf_member, btf_vlen(t) as usize) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn btf_name_str_by_offset(btf: &btf, name_off: u32) -> Result<&str> {
|
||||||
|
let n = unsafe { btf__name_by_offset(btf, name_off) };
|
||||||
|
if n.is_null() {
|
||||||
|
bail!("btf__name_by_offset() returned NULL");
|
||||||
|
}
|
||||||
|
Ok(unsafe { CStr::from_ptr(n) }
|
||||||
|
.to_str()
|
||||||
|
.with_context(|| format!("Failed to convert {:?} to string", n))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_enum(type_name: &str, name: &str) -> Result<u64> {
|
||||||
|
let btf: &btf = *VMLINUX_BTF;
|
||||||
|
|
||||||
|
let type_name = CString::new(type_name).unwrap();
|
||||||
|
let tid = unsafe { btf__find_by_name(btf, type_name.as_ptr()) };
|
||||||
|
if tid < 0 {
|
||||||
|
bail!("type {:?} doesn't exist, ret={}", type_name, tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
let t = unsafe { btf__type_by_id(btf, tid as _) };
|
||||||
|
if t.is_null() {
|
||||||
|
bail!("btf__type_by_id({}) returned NULL", tid);
|
||||||
|
}
|
||||||
|
let t = unsafe { &*t };
|
||||||
|
|
||||||
|
match btf_kind(t) {
|
||||||
|
BTF_KIND_ENUM => {
|
||||||
|
for e in btf_enum(t).iter() {
|
||||||
|
if btf_name_str_by_offset(btf, e.name_off)? == name {
|
||||||
|
return Ok(e.val as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BTF_KIND_ENUM64 => {
|
||||||
|
for e in btf_enum64(t).iter() {
|
||||||
|
if btf_name_str_by_offset(btf, e.name_off)? == name {
|
||||||
|
return Ok(((e.val_hi32 as u64) << 32) | (e.val_lo32) as u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow!("{:?} doesn't exist in {:?}", name, type_name))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn struct_has_field(type_name: &str, field: &str) -> Result<bool> {
|
||||||
|
let btf: &btf = *VMLINUX_BTF;
|
||||||
|
|
||||||
|
let type_name = CString::new(type_name).unwrap();
|
||||||
|
let tid = unsafe { btf__find_by_name_kind(btf, type_name.as_ptr(), BTF_KIND_STRUCT) };
|
||||||
|
if tid < 0 {
|
||||||
|
bail!("type {:?} doesn't exist, ret={}", type_name, tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
let t = unsafe { btf__type_by_id(btf, tid as _) };
|
||||||
|
if t.is_null() {
|
||||||
|
bail!("btf__type_by_id({}) returned NULL", tid);
|
||||||
|
}
|
||||||
|
let t = unsafe { &*t };
|
||||||
|
|
||||||
|
for m in btf_members(t).iter() {
|
||||||
|
if btf_name_str_by_offset(btf, m.name_off)? == field {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// struct sched_ext_ops can change over time. If
|
||||||
|
/// compat.bpf.h::SCX_OPS_DEFINE() is used to define ops and scx_ops_load!()
|
||||||
|
/// and scx_ops_attach!() are used to load and attach it, backward
|
||||||
|
/// compatibility is automatically maintained where reasonable.
|
||||||
|
///
|
||||||
|
/// - sched_ext_ops.exit_dump_len was added later. On kernels which don't
|
||||||
|
/// support it, the value is ignored and a warning is triggered if the value
|
||||||
|
/// is requested to be non-zero.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! scx_ops_load {
|
||||||
|
($skel: expr, $ops: ident, $uei: ident) => {{
|
||||||
|
scx_utils::paste! {
|
||||||
|
scx_utils::uei_set_size!($skel, $ops, $uei);
|
||||||
|
|
||||||
|
let ops = $skel.struct_ops.[<$ops _mut>]();
|
||||||
|
let has_field = scx_utils::compat::struct_has_field("sched_ext_ops", "exit_dump_len")?;
|
||||||
|
if !has_field && ops.exit_dump_len != 0 {
|
||||||
|
scx_utils::warn!("Kernel doesn't support setting exit dump len");
|
||||||
|
ops.exit_dump_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$skel.load().context("Failed to load BPF program")
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Must be used together with scx_ops_load!(). See there.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! scx_ops_attach {
|
||||||
|
($skel: expr, $ops: ident) => {{
|
||||||
|
$skel
|
||||||
|
.maps_mut()
|
||||||
|
.$ops()
|
||||||
|
.attach_struct_ops()
|
||||||
|
.context("Failed to attach struct ops")
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
fn test_read_enum() {
|
||||||
|
assert_eq!(super::read_enum("pid_type", "PIDTYPE_TGID").unwrap(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_struct_has_field() {
|
||||||
|
assert!(super::struct_has_field("task_struct", "flags").unwrap());
|
||||||
|
assert!(!super::struct_has_field("task_struct", "NO_SUCH_FIELD").unwrap());
|
||||||
|
assert!(super::struct_has_field("NO_SUCH_STRUCT", "NO_SUCH_FIELD").is_err());
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,9 @@
|
|||||||
//! Utility modules which can be useful for userspace component of sched_ext
|
//! Utility modules which can be useful for userspace component of sched_ext
|
||||||
//! schedulers.
|
//! schedulers.
|
||||||
|
|
||||||
|
pub use paste::paste;
|
||||||
|
pub use log::warn;
|
||||||
|
|
||||||
mod bindings;
|
mod bindings;
|
||||||
|
|
||||||
mod bpf_builder;
|
mod bpf_builder;
|
||||||
@ -38,21 +41,26 @@ pub use bpf_builder::BpfBuilder;
|
|||||||
mod builder;
|
mod builder;
|
||||||
pub use builder::Builder;
|
pub use builder::Builder;
|
||||||
|
|
||||||
pub mod ravg;
|
mod user_exit_info;
|
||||||
|
pub use user_exit_info::ScxExitKind;
|
||||||
|
pub use user_exit_info::ScxInternalConsts;
|
||||||
|
pub use user_exit_info::UeiDumpPtr;
|
||||||
|
pub use user_exit_info::UserExitInfo;
|
||||||
|
pub use user_exit_info::UEI_DUMP_PTR_MUTEX;
|
||||||
|
|
||||||
|
pub mod compat;
|
||||||
|
|
||||||
mod libbpf_logger;
|
mod libbpf_logger;
|
||||||
pub use libbpf_logger::init_libbpf_logging;
|
pub use libbpf_logger::init_libbpf_logging;
|
||||||
|
|
||||||
mod user_exit_info;
|
pub mod ravg;
|
||||||
pub use user_exit_info::UserExitInfo;
|
|
||||||
pub use user_exit_info::ScxExitKind;
|
|
||||||
|
|
||||||
mod topology;
|
mod topology;
|
||||||
pub use topology::Topology;
|
|
||||||
pub use topology::Cpu;
|
|
||||||
pub use topology::Core;
|
|
||||||
pub use topology::Cache;
|
pub use topology::Cache;
|
||||||
|
pub use topology::Core;
|
||||||
|
pub use topology::Cpu;
|
||||||
pub use topology::Node;
|
pub use topology::Node;
|
||||||
|
pub use topology::Topology;
|
||||||
|
|
||||||
mod cpumask;
|
mod cpumask;
|
||||||
pub use cpumask::Cpumask;
|
pub use cpumask::Cpumask;
|
||||||
|
@ -7,6 +7,16 @@ use anyhow::bail;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::os::raw::c_char;
|
use std::os::raw::c_char;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
pub struct UeiDumpPtr {
|
||||||
|
pub ptr: *const c_char,
|
||||||
|
}
|
||||||
|
unsafe impl Send for UeiDumpPtr {}
|
||||||
|
|
||||||
|
pub static UEI_DUMP_PTR_MUTEX: Mutex<UeiDumpPtr> = Mutex::new(UeiDumpPtr {
|
||||||
|
ptr: std::ptr::null(),
|
||||||
|
});
|
||||||
|
|
||||||
pub enum ScxExitKind {
|
pub enum ScxExitKind {
|
||||||
None = bindings::scx_exit_kind_SCX_EXIT_NONE as isize,
|
None = bindings::scx_exit_kind_SCX_EXIT_NONE as isize,
|
||||||
@ -18,29 +28,63 @@ pub enum ScxExitKind {
|
|||||||
ErrorStall = bindings::scx_exit_kind_SCX_EXIT_ERROR_STALL as isize,
|
ErrorStall = bindings::scx_exit_kind_SCX_EXIT_ERROR_STALL as isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum ScxInternalConsts {
|
||||||
|
ExitDumpDflLen = bindings::scx_internal_consts_SCX_EXIT_DUMP_DFL_LEN as isize,
|
||||||
|
}
|
||||||
|
|
||||||
/// Takes a reference to C struct user_exit_info and reads it into
|
/// Takes a reference to C struct user_exit_info and reads it into
|
||||||
/// UserExitInfo. See UserExitInfo.
|
/// UserExitInfo. See UserExitInfo.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! uei_read {
|
macro_rules! uei_read {
|
||||||
($bpf_uei:expr) => {{
|
($skel: expr, $uei:ident) => {{
|
||||||
{
|
scx_utils::paste! {
|
||||||
let bpf_uei = $bpf_uei;
|
let bpf_uei = $skel.data().$uei;
|
||||||
|
let bpf_dump = scx_utils::UEI_DUMP_PTR_MUTEX.lock().unwrap().ptr;
|
||||||
|
|
||||||
scx_utils::UserExitInfo::new(
|
scx_utils::UserExitInfo::new(
|
||||||
&bpf_uei.kind as *const _,
|
&bpf_uei.kind as *const _,
|
||||||
bpf_uei.reason.as_ptr() as *const _,
|
bpf_uei.reason.as_ptr() as *const _,
|
||||||
bpf_uei.msg.as_ptr() as *const _,
|
bpf_uei.msg.as_ptr() as *const _,
|
||||||
bpf_uei.dump.as_ptr() as *const _,
|
bpf_dump,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resize debug dump area according to ops.exit_dump_len. If this macro is
|
||||||
|
/// not called, debug dump area is not allocated and debug dump won't be
|
||||||
|
/// printed out.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! uei_set_size {
|
||||||
|
($skel: expr, $ops: ident, $uei:ident) => {{
|
||||||
|
scx_utils::paste! {
|
||||||
|
let len = match $skel.struct_ops.$ops().exit_dump_len {
|
||||||
|
0 => scx_utils::ScxInternalConsts::ExitDumpDflLen as u32,
|
||||||
|
v => v,
|
||||||
|
};
|
||||||
|
$skel.rodata_mut().[<$uei _dump_len>] = len;
|
||||||
|
$skel.maps_mut().[<data_ $uei _dump>]().set_value_size(len).unwrap();
|
||||||
|
|
||||||
|
let mut ptr = scx_utils::UEI_DUMP_PTR_MUTEX.lock().unwrap();
|
||||||
|
*ptr = scx_utils::UeiDumpPtr { ptr:
|
||||||
|
$skel
|
||||||
|
.maps()
|
||||||
|
.[<data_ $uei _dump>]()
|
||||||
|
.initial_value()
|
||||||
|
.unwrap()
|
||||||
|
.as_ptr() as *const _,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
/// Takes a reference to C struct user_exit_info and test whether the BPF
|
/// Takes a reference to C struct user_exit_info and test whether the BPF
|
||||||
/// scheduler has exited. See UserExitInfo.
|
/// scheduler has exited. See UserExitInfo.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! uei_exited {
|
macro_rules! uei_exited {
|
||||||
($bpf_uei:expr) => {{
|
($skel: expr, $uei:ident) => {{
|
||||||
(unsafe { std::ptr::read_volatile(&$bpf_uei.kind as *const _) } != 0)
|
let bpf_uei = $skel.data().uei;
|
||||||
|
(unsafe { std::ptr::read_volatile(&bpf_uei.kind as *const _) } != 0)
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,8 +92,8 @@ macro_rules! uei_exited {
|
|||||||
/// UserExitInfo::report() on it. See UserExitInfo.
|
/// UserExitInfo::report() on it. See UserExitInfo.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! uei_report {
|
macro_rules! uei_report {
|
||||||
($bpf_uei:expr) => {{
|
($skel: expr, $uei:ident) => {{
|
||||||
scx_utils::uei_read!($bpf_uei).report()
|
scx_utils::uei_read!($skel, $uei).report()
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +122,7 @@ impl UserExitInfo {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let kind = unsafe { std::ptr::read_volatile(kind_ptr) };
|
let kind = unsafe { std::ptr::read_volatile(kind_ptr) };
|
||||||
|
|
||||||
let (reason, msg, dump) = (
|
let (reason, msg) = (
|
||||||
Some(
|
Some(
|
||||||
unsafe { CStr::from_ptr(reason_ptr) }
|
unsafe { CStr::from_ptr(reason_ptr) }
|
||||||
.to_str()
|
.to_str()
|
||||||
@ -93,14 +137,19 @@ impl UserExitInfo {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
.filter(|s| !s.is_empty()),
|
.filter(|s| !s.is_empty()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let dump = if dump_ptr.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
Some(
|
Some(
|
||||||
unsafe { CStr::from_ptr(dump_ptr) }
|
unsafe { CStr::from_ptr(dump_ptr) }
|
||||||
.to_str()
|
.to_str()
|
||||||
.expect("Failed to convert msg to string")
|
.expect("Failed to convert msg to string")
|
||||||
.to_string(),
|
.to_string(),
|
||||||
)
|
)
|
||||||
.filter(|s| !s.is_empty()),
|
.filter(|s| !s.is_empty())
|
||||||
);
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
kind,
|
kind,
|
||||||
@ -118,12 +167,12 @@ impl UserExitInfo {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(dump) = &self.dump {
|
if let Some(dump) = &self.dump {
|
||||||
eprintln!("\nDEBUG DUMP");
|
eprintln!("\nDEBUG DUMP");
|
||||||
eprintln!("================================================================================\n");
|
eprintln!("================================================================================\n");
|
||||||
eprintln!("{}", dump);
|
eprintln!("{}", dump);
|
||||||
eprintln!("================================================================================\n");
|
eprintln!("================================================================================\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
let why = match (&self.reason, &self.msg) {
|
let why = match (&self.reason, &self.msg) {
|
||||||
(Some(reason), None) => format!("EXIT: {}", reason),
|
(Some(reason), None) => format!("EXIT: {}", reason),
|
||||||
|
@ -13,7 +13,7 @@ clap = { version = "4.1", features = ["derive", "env", "unicode", "wrap_help"] }
|
|||||||
ctrlc = { version = "3.1", features = ["termination"] }
|
ctrlc = { version = "3.1", features = ["termination"] }
|
||||||
fb_procfs = "0.7.0"
|
fb_procfs = "0.7.0"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
libbpf-rs = "0.22.0"
|
libbpf-rs = "0.22"
|
||||||
libc = "0.2.137"
|
libc = "0.2.137"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
ordered-float = "3.4.0"
|
ordered-float = "3.4.0"
|
||||||
@ -29,3 +29,8 @@ scx_utils = { path = "../../../rust/scx_utils", version = "0.6" }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
enable_backtrace = []
|
enable_backtrace = []
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
libbpf-sys = { git = "https://github.com/libbpf/libbpf-sys.git", rev = "75042c653ee956b8c262e41ca4bcfcb0e2c461a1" }
|
||||||
|
libbpf-rs = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "560641a5aff2c613dff6ae02147b0000558e4945" }
|
||||||
|
libbpf-cargo = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "7745f2e43c2bde59920b8b7400d62f66b906f05b" }
|
||||||
|
@ -27,3 +27,8 @@ scx_utils = { path = "../../../rust/scx_utils", version = "0.6" }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
enable_backtrace = []
|
enable_backtrace = []
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
libbpf-sys = { git = "https://github.com/libbpf/libbpf-sys.git", rev = "125444300e2db452131dd6453101599c1a277784" }
|
||||||
|
libbpf-rs = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "7745f2e43c2bde59920b8b7400d62f66b906f05b" }
|
||||||
|
libbpf-cargo = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "7745f2e43c2bde59920b8b7400d62f66b906f05b" }
|
||||||
|
@ -30,7 +30,7 @@ static u32 preempt_cursor;
|
|||||||
|
|
||||||
#include "util.bpf.c"
|
#include "util.bpf.c"
|
||||||
|
|
||||||
struct user_exit_info uei;
|
UEI_DEFINE(uei);
|
||||||
|
|
||||||
static inline bool vtime_before(u64 a, u64 b)
|
static inline bool vtime_before(u64 a, u64 b)
|
||||||
{
|
{
|
||||||
@ -894,7 +894,7 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(layered_init)
|
|||||||
struct bpf_cpumask *cpumask;
|
struct bpf_cpumask *cpumask;
|
||||||
int i, j, k, nr_online_cpus, ret;
|
int i, j, k, nr_online_cpus, ret;
|
||||||
|
|
||||||
scx_bpf_switch_all();
|
__COMPAT_scx_bpf_switch_all();
|
||||||
|
|
||||||
cpumask = bpf_cpumask_create();
|
cpumask = bpf_cpumask_create();
|
||||||
if (!cpumask)
|
if (!cpumask)
|
||||||
@ -1020,23 +1020,21 @@ s32 BPF_STRUCT_OPS_SLEEPABLE(layered_init)
|
|||||||
|
|
||||||
void BPF_STRUCT_OPS(layered_exit, struct scx_exit_info *ei)
|
void BPF_STRUCT_OPS(layered_exit, struct scx_exit_info *ei)
|
||||||
{
|
{
|
||||||
uei_record(&uei, ei);
|
UEI_RECORD(uei, ei);
|
||||||
}
|
}
|
||||||
|
|
||||||
SEC(".struct_ops.link")
|
SCX_OPS_DEFINE(layered,
|
||||||
struct sched_ext_ops layered = {
|
.select_cpu = (void *)layered_select_cpu,
|
||||||
.select_cpu = (void *)layered_select_cpu,
|
.enqueue = (void *)layered_enqueue,
|
||||||
.enqueue = (void *)layered_enqueue,
|
.dispatch = (void *)layered_dispatch,
|
||||||
.dispatch = (void *)layered_dispatch,
|
.runnable = (void *)layered_runnable,
|
||||||
.runnable = (void *)layered_runnable,
|
.running = (void *)layered_running,
|
||||||
.running = (void *)layered_running,
|
.stopping = (void *)layered_stopping,
|
||||||
.stopping = (void *)layered_stopping,
|
.quiescent = (void *)layered_quiescent,
|
||||||
.quiescent = (void *)layered_quiescent,
|
.set_weight = (void *)layered_set_weight,
|
||||||
.set_weight = (void *)layered_set_weight,
|
.set_cpumask = (void *)layered_set_cpumask,
|
||||||
.set_cpumask = (void *)layered_set_cpumask,
|
.init_task = (void *)layered_init_task,
|
||||||
.init_task = (void *)layered_init_task,
|
.exit_task = (void *)layered_exit_task,
|
||||||
.exit_task = (void *)layered_exit_task,
|
.init = (void *)layered_init,
|
||||||
.init = (void *)layered_init,
|
.exit = (void *)layered_exit,
|
||||||
.exit = (void *)layered_exit,
|
.name = "layered");
|
||||||
.name = "layered",
|
|
||||||
};
|
|
||||||
|
@ -29,7 +29,6 @@ use anyhow::Result;
|
|||||||
use bitvec::prelude::*;
|
use bitvec::prelude::*;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use libbpf_rs::skel::OpenSkel as _;
|
use libbpf_rs::skel::OpenSkel as _;
|
||||||
use libbpf_rs::skel::Skel as _;
|
|
||||||
use libbpf_rs::skel::SkelBuilder as _;
|
use libbpf_rs::skel::SkelBuilder as _;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use log::info;
|
use log::info;
|
||||||
@ -41,6 +40,8 @@ use prometheus_client::metrics::gauge::Gauge;
|
|||||||
use prometheus_client::registry::Registry;
|
use prometheus_client::registry::Registry;
|
||||||
use scx_utils::init_libbpf_logging;
|
use scx_utils::init_libbpf_logging;
|
||||||
use scx_utils::ravg::ravg_read;
|
use scx_utils::ravg::ravg_read;
|
||||||
|
use scx_utils::scx_ops_attach;
|
||||||
|
use scx_utils::scx_ops_load;
|
||||||
use scx_utils::uei_exited;
|
use scx_utils::uei_exited;
|
||||||
use scx_utils::uei_report;
|
use scx_utils::uei_report;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
@ -271,6 +272,10 @@ struct Opts {
|
|||||||
#[clap(short = 'n', long)]
|
#[clap(short = 'n', long)]
|
||||||
no_load_frac_limit: bool,
|
no_load_frac_limit: bool,
|
||||||
|
|
||||||
|
/// Exit debug dump buffer length. 0 indicates default.
|
||||||
|
#[clap(long, default_value = "0")]
|
||||||
|
exit_dump_len: u32,
|
||||||
|
|
||||||
/// Enable verbose output including libbpf details. Specify multiple
|
/// Enable verbose output including libbpf details. Specify multiple
|
||||||
/// times to increase verbosity.
|
/// times to increase verbosity.
|
||||||
#[clap(short = 'v', long, action = clap::ArgAction::Count)]
|
#[clap(short = 'v', long, action = clap::ArgAction::Count)]
|
||||||
@ -303,28 +308,28 @@ enum LayerMatch {
|
|||||||
enum LayerKind {
|
enum LayerKind {
|
||||||
Confined {
|
Confined {
|
||||||
util_range: (f64, f64),
|
util_range: (f64, f64),
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
cpus_range: Option<(usize, usize)>,
|
cpus_range: Option<(usize, usize)>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
min_exec_us: u64,
|
min_exec_us: u64,
|
||||||
},
|
},
|
||||||
Grouped {
|
Grouped {
|
||||||
util_range: (f64, f64),
|
util_range: (f64, f64),
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
cpus_range: Option<(usize, usize)>,
|
cpus_range: Option<(usize, usize)>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
min_exec_us: u64,
|
min_exec_us: u64,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
preempt: bool,
|
preempt: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
exclusive: bool,
|
exclusive: bool,
|
||||||
},
|
},
|
||||||
Open {
|
Open {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
min_exec_us: u64,
|
min_exec_us: u64,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
preempt: bool,
|
preempt: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
exclusive: bool,
|
exclusive: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1282,10 +1287,10 @@ impl<'a> Scheduler<'a> {
|
|||||||
exclusive,
|
exclusive,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
layer.open = true;
|
layer.open.write(true);
|
||||||
layer.min_exec_ns = min_exec_us * 1000;
|
layer.min_exec_ns = min_exec_us * 1000;
|
||||||
layer.preempt = *preempt;
|
layer.preempt.write(*preempt);
|
||||||
layer.exclusive = *exclusive;
|
layer.exclusive.write(*exclusive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1304,6 +1309,8 @@ impl<'a> Scheduler<'a> {
|
|||||||
let mut skel = skel_builder.open().context("Failed to open BPF program")?;
|
let mut skel = skel_builder.open().context("Failed to open BPF program")?;
|
||||||
|
|
||||||
// Initialize skel according to @opts.
|
// Initialize skel according to @opts.
|
||||||
|
skel.struct_ops.layered_mut().exit_dump_len = opts.exit_dump_len;
|
||||||
|
|
||||||
skel.rodata_mut().debug = opts.verbose as u32;
|
skel.rodata_mut().debug = opts.verbose as u32;
|
||||||
skel.rodata_mut().slice_ns = opts.slice_us * 1000;
|
skel.rodata_mut().slice_ns = opts.slice_us * 1000;
|
||||||
skel.rodata_mut().nr_possible_cpus = *NR_POSSIBLE_CPUS as u32;
|
skel.rodata_mut().nr_possible_cpus = *NR_POSSIBLE_CPUS as u32;
|
||||||
@ -1316,7 +1323,8 @@ impl<'a> Scheduler<'a> {
|
|||||||
}
|
}
|
||||||
Self::init_layers(&mut skel, &layer_specs)?;
|
Self::init_layers(&mut skel, &layer_specs)?;
|
||||||
|
|
||||||
let mut skel = skel.load().context("Failed to load BPF program")?;
|
let mut skel = scx_ops_load!(skel, layered, uei)?;
|
||||||
|
|
||||||
let mut layers = vec![];
|
let mut layers = vec![];
|
||||||
for spec in layer_specs.iter() {
|
for spec in layer_specs.iter() {
|
||||||
layers.push(Layer::new(&mut cpu_pool, &spec.name, spec.kind.clone())?);
|
layers.push(Layer::new(&mut cpu_pool, &spec.name, spec.kind.clone())?);
|
||||||
@ -1357,24 +1365,13 @@ impl<'a> Scheduler<'a> {
|
|||||||
// huge problem in the interim until we figure it out.
|
// huge problem in the interim until we figure it out.
|
||||||
|
|
||||||
// Attach.
|
// Attach.
|
||||||
sched
|
sched.struct_ops = Some(scx_ops_attach!(sched.skel, layered)?);
|
||||||
.skel
|
|
||||||
.attach()
|
|
||||||
.context("Failed to attach BPF program")?;
|
|
||||||
sched.struct_ops = Some(
|
|
||||||
sched
|
|
||||||
.skel
|
|
||||||
.maps_mut()
|
|
||||||
.layered()
|
|
||||||
.attach_struct_ops()
|
|
||||||
.context("Failed to attach layered struct ops")?,
|
|
||||||
);
|
|
||||||
info!("Layered Scheduler Attached");
|
info!("Layered Scheduler Attached");
|
||||||
|
|
||||||
Ok(sched)
|
Ok(sched)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_bpf_layer_cpumask(layer: &Layer, bpf_layer: &mut bpf_bss_types::layer) {
|
fn update_bpf_layer_cpumask(layer: &Layer, bpf_layer: &mut bpf_types::layer) {
|
||||||
for bit in 0..layer.cpus.len() {
|
for bit in 0..layer.cpus.len() {
|
||||||
if layer.cpus[bit] {
|
if layer.cpus[bit] {
|
||||||
bpf_layer.cpus[bit / 8] |= 1 << (bit % 8);
|
bpf_layer.cpus[bit / 8] |= 1 << (bit % 8);
|
||||||
@ -1709,7 +1706,7 @@ impl<'a> Scheduler<'a> {
|
|||||||
let mut next_sched_at = now + self.sched_intv;
|
let mut next_sched_at = now + self.sched_intv;
|
||||||
let mut next_monitor_at = now + self.monitor_intv;
|
let mut next_monitor_at = now + self.monitor_intv;
|
||||||
|
|
||||||
while !shutdown.load(Ordering::Relaxed) && !uei_exited!(&self.skel.bss().uei) {
|
while !shutdown.load(Ordering::Relaxed) && !uei_exited!(&self.skel, uei) {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
if now >= next_sched_at {
|
if now >= next_sched_at {
|
||||||
@ -1734,7 +1731,7 @@ impl<'a> Scheduler<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.struct_ops.take();
|
self.struct_ops.take();
|
||||||
uei_report!(&self.skel.bss().uei)
|
uei_report!(&self.skel, uei)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ license = "GPL-2.0-only"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.65"
|
anyhow = "1.0.65"
|
||||||
ctrlc = { version = "3.1", features = ["termination"] }
|
ctrlc = { version = "3.1", features = ["termination"] }
|
||||||
libbpf-rs = "0.22.0"
|
libbpf-rs = "0.22"
|
||||||
libc = "0.2.137"
|
libc = "0.2.137"
|
||||||
scx_utils = { path = "../../../rust/scx_utils", version = "0.6" }
|
scx_utils = { path = "../../../rust/scx_utils", version = "0.6" }
|
||||||
scx_rustland_core = { path = "../../../rust/scx_rustland_core", version = "0.1" }
|
scx_rustland_core = { path = "../../../rust/scx_rustland_core", version = "0.1" }
|
||||||
@ -20,3 +20,8 @@ scx_rustland_core = { path = "../../../rust/scx_rustland_core", version = "0.1"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
enable_backtrace = []
|
enable_backtrace = []
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
libbpf-sys = { git = "https://github.com/libbpf/libbpf-sys.git", rev = "75042c653ee956b8c262e41ca4bcfcb0e2c461a1" }
|
||||||
|
libbpf-rs = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "560641a5aff2c613dff6ae02147b0000558e4945" }
|
||||||
|
libbpf-cargo = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "7745f2e43c2bde59920b8b7400d62f66b906f05b" }
|
||||||
|
@ -11,7 +11,7 @@ anyhow = "1.0.65"
|
|||||||
clap = { version = "4.1", features = ["derive", "env", "unicode", "wrap_help"] }
|
clap = { version = "4.1", features = ["derive", "env", "unicode", "wrap_help"] }
|
||||||
ctrlc = { version = "3.1", features = ["termination"] }
|
ctrlc = { version = "3.1", features = ["termination"] }
|
||||||
fb_procfs = "0.7.0"
|
fb_procfs = "0.7.0"
|
||||||
libbpf-rs = "0.22.0"
|
libbpf-rs = "0.22"
|
||||||
libc = "0.2.137"
|
libc = "0.2.137"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
ordered-float = "3.4.0"
|
ordered-float = "3.4.0"
|
||||||
@ -25,3 +25,8 @@ scx_rustland_core = { path = "../../../rust/scx_rustland_core", version = "0.1"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
enable_backtrace = []
|
enable_backtrace = []
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
libbpf-sys = { git = "https://github.com/libbpf/libbpf-sys.git", rev = "75042c653ee956b8c262e41ca4bcfcb0e2c461a1" }
|
||||||
|
libbpf-rs = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "560641a5aff2c613dff6ae02147b0000558e4945" }
|
||||||
|
libbpf-cargo = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "7745f2e43c2bde59920b8b7400d62f66b906f05b" }
|
||||||
|
@ -11,7 +11,7 @@ anyhow = "1.0.65"
|
|||||||
clap = { version = "4.1", features = ["derive", "env", "unicode", "wrap_help"] }
|
clap = { version = "4.1", features = ["derive", "env", "unicode", "wrap_help"] }
|
||||||
ctrlc = { version = "3.1", features = ["termination"] }
|
ctrlc = { version = "3.1", features = ["termination"] }
|
||||||
fb_procfs = "0.7.0"
|
fb_procfs = "0.7.0"
|
||||||
libbpf-rs = "0.22.0"
|
libbpf-rs = "0.22"
|
||||||
libc = "0.2.137"
|
libc = "0.2.137"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
ordered-float = "3.4.0"
|
ordered-float = "3.4.0"
|
||||||
@ -25,3 +25,8 @@ scx_utils = { path = "../../../rust/scx_utils", version = "0.6" }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
enable_backtrace = []
|
enable_backtrace = []
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
libbpf-sys = { git = "https://github.com/libbpf/libbpf-sys.git", rev = "75042c653ee956b8c262e41ca4bcfcb0e2c461a1" }
|
||||||
|
libbpf-rs = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "560641a5aff2c613dff6ae02147b0000558e4945" }
|
||||||
|
libbpf-cargo = { git = "https://github.com/libbpf/libbpf-rs.git", rev = "7745f2e43c2bde59920b8b7400d62f66b906f05b" }
|
||||||
|
Loading…
Reference in New Issue
Block a user