pub(crate) struct Opts {Show 25 fields
pub(crate) slice_us_underutil: u64,
pub(crate) slice_us_overutil: u64,
pub(crate) interval: f64,
pub(crate) tune_interval: f64,
pub(crate) load_half_life: f64,
pub(crate) cache_level: u32,
pub(crate) cpumasks: Vec<String>,
pub(crate) greedy_threshold: u32,
pub(crate) greedy_threshold_x_numa: u32,
pub(crate) no_load_balance: bool,
pub(crate) kthreads_local: bool,
pub(crate) balanced_kworkers: bool,
pub(crate) fifo_sched: bool,
pub(crate) direct_greedy_under: f64,
pub(crate) kick_greedy_under: f64,
pub(crate) direct_greedy_numa: bool,
pub(crate) partial: bool,
pub(crate) mempolicy_affinity: bool,
pub(crate) stats: Option<f64>,
pub(crate) monitor: Option<f64>,
pub(crate) exit_dump_len: u32,
pub(crate) verbose: u8,
pub(crate) version: bool,
pub(crate) help_stats: bool,
pub(crate) perf: u32,
}
Expand description
scx_rusty: A multi-domain BPF / userspace hybrid scheduler
The BPF part does simple vtime or round robin scheduling in each domain while tracking average load of each domain and duty cycle of each task.
The userspace part performs two roles. First, it makes higher frequency (100ms) tuning decisions. It identifies CPUs which are not too heavily loaded and marks them so that they can pull tasks from other overloaded domains on the fly.
Second, it drives lower frequency (2s) load balancing. It determines whether load balancing is necessary by comparing domain load averages. If there are large enough load differences, it examines upto 1024 recently active tasks on the domain to determine which should be migrated.
The overhead of userspace operations is low. Load balancing is not performed frequently, but work-conservation is still maintained through tuning and greedy execution. Load balancing itself is not that expensive either. It only accesses per-domain load metrics to determine the domains that need load balancing, as well as limited number of per-task metrics for each pushing domain.
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.
WARNING: scx_rusty currently assumes that all domains have equal processing power and at similar distances from each other. This limitation will be removed in the future.
Fields§
§slice_us_underutil: u64
Scheduling slice duration for under-utilized hosts, in microseconds.
slice_us_overutil: u64
Scheduling slice duration for over-utilized hosts, in microseconds.
interval: f64
Load balance interval in seconds.
tune_interval: f64
The tuner runs at a higher frequency than the load balancer to dynamically tune scheduling behavior. Tuning interval in seconds.
load_half_life: f64
The half-life of task and domain load running averages in seconds.
cache_level: u32
Build domains according to how CPUs are grouped at this cache level as determined by /sys/devices/system/cpu/cpuX/cache/indexI/id.
cpumasks: Vec<String>
Instead of using cache locality, set the cpumask for each domain manually. Provide multiple –cpumasks, one for each domain. E.g. –cpumasks 0xff_00ff –cpumasks 0xff00 will create two domains, with the corresponding CPUs belonging to each domain. Each CPU must belong to precisely one domain.
greedy_threshold: u32
When non-zero, enable greedy task stealing. When a domain is idle, a cpu will attempt to steal tasks from another domain as follows:
- Try to consume a task from the current domain
- Try to consume a task from another domain in the current NUMA node (or globally, if running on a single-socket system), if the domain has at least this specified number of tasks enqueued.
See greedy_threshold_x_numa to enable task stealing across NUMA nodes. Tasks stolen in this manner are not permanently stolen from their domain.
greedy_threshold_x_numa: u32
When non-zero, enable greedy task stealing across NUMA nodes. The order of greedy task stealing follows greedy-threshold as described above, and greedy-threshold must be nonzero to enable task stealing across NUMA nodes.
no_load_balance: bool
Disable load balancing. Unless disabled, userspace will periodically calculate the load factor of each domain and instruct BPF which processes to move.
kthreads_local: bool
Put per-cpu kthreads directly into local dsq’s.
balanced_kworkers: bool
In recent kernels (>=v6.6), the kernel is responsible for balancing kworkers across L3 cache domains. Exclude them from load-balancing to avoid conflicting operations. Greedy executions still apply.
fifo_sched: bool
Use FIFO scheduling instead of weighted vtime scheduling.
direct_greedy_under: f64
Idle CPUs with utilization lower than this will get remote tasks directly pushed onto them. 0 disables, 100 always enables.
kick_greedy_under: f64
Idle CPUs with utilization lower than this may get kicked to accelerate stealing when a task is queued on a saturated remote domain. 0 disables, 100 enables always.
direct_greedy_numa: bool
Whether tasks can be pushed directly to idle CPUs on NUMA nodes different than their domain’s node. If direct-greedy-under is disabled, this option is a no-op. Otherwise, if this option is set to false (default), tasks will only be directly pushed to idle CPUs if they reside on the same NUMA node as the task’s domain.
partial: bool
If specified, only tasks which have their scheduling policy set to SCHED_EXT using sched_setscheduler(2) are switched. Otherwise, all tasks are switched.
mempolicy_affinity: bool
Enables soft NUMA affinity for tasks that use set_mempolicy. This may improve performance in some scenarios when using mempolicies.
stats: Option<f64>
Enable stats monitoring with the specified interval.
monitor: Option<f64>
Run in stats monitoring mode with the specified interval. The scheduler is not launched.
exit_dump_len: u32
Exit debug dump buffer length. 0 indicates default.
verbose: u8
Enable verbose output, including libbpf details. Specify multiple times to increase verbosity.
version: bool
Print version and exit.
help_stats: bool
Show descriptions for statistics.
perf: u32
Tunable for prioritizing CPU performance by configuring the CPU frequency governor. Valid values are [0, 1024]. Higher values prioritize performance, lower values prioritize energy efficiency. When in doubt, use 0 or 1024.
Trait Implementations§
Source§impl Args for Opts
impl Args for Opts
Source§fn group_id() -> Option<Id>
fn group_id() -> Option<Id>
ArgGroup::id
][crate::ArgGroup::id] for this set of argumentsSource§fn augment_args<'b>(__clap_app: Command) -> Command
fn augment_args<'b>(__clap_app: Command) -> Command
Source§fn augment_args_for_update<'b>(__clap_app: Command) -> Command
fn augment_args_for_update<'b>(__clap_app: Command) -> Command
Command
] so it can instantiate self
via
[FromArgMatches::update_from_arg_matches_mut
] Read moreSource§impl FromArgMatches for Opts
impl FromArgMatches for Opts
Source§fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>
fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>
Source§fn from_arg_matches_mut(
__clap_arg_matches: &mut ArgMatches,
) -> Result<Self, Error>
fn from_arg_matches_mut( __clap_arg_matches: &mut ArgMatches, ) -> Result<Self, Error>
Source§fn update_from_arg_matches(
&mut self,
__clap_arg_matches: &ArgMatches,
) -> Result<(), Error>
fn update_from_arg_matches( &mut self, __clap_arg_matches: &ArgMatches, ) -> Result<(), Error>
ArgMatches
to self
.Source§fn update_from_arg_matches_mut(
&mut self,
__clap_arg_matches: &mut ArgMatches,
) -> Result<(), Error>
fn update_from_arg_matches_mut( &mut self, __clap_arg_matches: &mut ArgMatches, ) -> Result<(), Error>
ArgMatches
to self
.Source§impl Parser for Opts
impl Parser for Opts
§fn parse_from<I, T>(itr: I) -> Self
fn parse_from<I, T>(itr: I) -> Self
§fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
§fn update_from<I, T>(&mut self, itr: I)
fn update_from<I, T>(&mut self, itr: I)
§fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
Auto Trait Implementations§
impl Freeze for Opts
impl RefUnwindSafe for Opts
impl Send for Opts
impl Sync for Opts
impl Unpin for Opts
impl UnwindSafe for Opts
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.