#[non_exhaustive]pub struct Payload {
pub name: &'static str,
pub kind: PayloadKind,
pub output: OutputFormat,
pub default_args: &'static [&'static str],
pub default_checks: &'static [MetricCheck],
pub metrics: &'static [MetricHint],
pub include_files: &'static [&'static str],
pub uses_parent_pgrp: bool,
pub known_flags: Option<&'static [&'static str]>,
}Expand description
A test payload — either a scheduler or a userspace binary to run inside the guest VM.
Payload unifies the two launch modes under one #[ktstr_test]
attribute surface: tests declare scheduler = SOME_SCHED for
scheduler-centric runs, payload = SOME_BIN for binary runs, or
both with workloads = [...] to compose binaries under a
scheduler. See PayloadKind for the two variants.
Use Payload::KERNEL_DEFAULT as the default scheduler
placeholder when a test doesn’t attach a sched_ext scheduler —
it wraps the kernel’s default scheduler (EEVDF on Linux 6.6+)
via Scheduler::EEVDF.
Payload intentionally does NOT implement serde::Serialize /
serde::Deserialize. It is a compile-time-static definition that
references &'static Scheduler and &'static [&'static str]
slices — lifetimes that serialization cannot round-trip. Runtime
telemetry (per-payload metrics, exit codes, names) is serialized
via PayloadMetrics and Metric instead; those own their
data.
#[non_exhaustive] reserves the right to add fields without
breaking downstream code. Out-of-crate callers cannot construct
Payload via struct literal — use the const-fn constructors
(Payload::new, Payload::binary) or the
#[derive(Payload)] macro, which routes through Payload::new
under the hood.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.name: &'static strShort, stable name used in logs and sidecar records.
kind: PayloadKindLaunch kind — scheduler reference or binary name.
output: OutputFormatHow the framework extracts metrics from the payload’s
stdout, with stderr fallback when stdout yields no metrics.
See OutputFormat for the per-variant contract and
scenario::payload_run for the fallback mechanics.
default_args: &'static [&'static str]Default CLI args appended when this payload runs. Test bodies
can extend via .arg(...) or replace via .clear_args() +
.arg(...) on the runtime builder.
default_checks: &'static [MetricCheck]Author-declared default checks evaluated against extracted
PayloadMetrics. Payloads that need exit-code gating
should include MetricCheck::ExitCodeEq(0)
here; the runtime evaluates ExitCodeEq as a pre-pass
before metric checks.
metrics: &'static [MetricHint]Declared metric hints — polarity, unit. Unhinted metrics
extracted from output land as Polarity::Unknown.
include_files: &'static [&'static str]Host-side file specs resolved at runtime. Each entry is
resolved through the framework’s include-file pipeline — the
same resolver used by CLI -i / --include-files arguments:
bare names are searched in the host’s PATH, explicit paths
(absolute, relative, or containing /) must exist on the
host, and directories are walked recursively. The entry’s
scheduler / payload / workloads / extra_include_files are
aggregated at test time via
KtstrTestEntry::all_include_files
and resolved through the same pipeline the ktstr shell -i
path uses. Populate via the
#[include_files("helper", ...)] attribute on
#[derive(Payload)] or by spelling the array in the struct
literal.
uses_parent_pgrp: boolWhen true, the payload’s spawn path does NOT place the
child into its own process group via
CommandExt::process_group(0). The child inherits the
parent ktstr process’s pgid. Default (false) keeps the
existing “fresh pgrp → killpg-reaches-descendants” model
— see src/scenario/payload_run.rs::build_command.
Opt-in for tty-dependent binaries: a shell-like tool that
uses the controlling terminal’s foreground process group
for signal delivery (job-control signals, SIGHUP on tty
close) reads a fresh pgrp as “no job control”, which
breaks interactive shells and less-style readers.
Payloads that need tty job-control semantics set this
true so they stay in the parent’s pgrp and keep the
inherited controlling-terminal association.
Trade-off on the true branch: multi-process payloads
can no longer be killed via killpg(child_pid, SIGKILL)
because the child is not a pgrp leader; the kill path
falls back to single-pid kill(pid, SIGKILL) and any
descendants that the payload forks must either react to
SIGHUP / pipe close or run the risk of orphaning. Most
payloads should leave this false.
known_flags: Option<&'static [&'static str]>When Some, the listed flag names form an allowlist that
Op::RunPayload validation checks against at scenario-
execution time (inside apply_ops, before the payload
spawn) — any user-supplied --flag whose name is not in
the allowlist produces an error surfaced through the step
executor, surfacing typos as loud errors instead of silent
no-ops that only manifest as “feature didn’t activate” in
the test output.
None (default) disables validation — the payload accepts
arbitrary flag sets. Use None for payloads that wrap
binaries with open-ended flag surfaces (stress-ng, fio,
schbench) where enumerating every accepted flag is either
impossible or high-churn.
Some(&[]) is legal but rarely intended: it rejects EVERY
long flag, including ones the wrapped binary legitimately
accepts. Use None for “no validation” and a non-empty
slice for “validate against this allowlist” — an empty
slice means “only positional args and short flags are
acceptable”, which is almost never what a Payload author
wants.
Flag names in the slice are bare (no leading --) and
match the syntax of Op::RunPayload’s per-flag slot.
Implementations§
Source§impl Payload
impl Payload
Sourcepub const KERNEL_DEFAULT: Payload
pub const KERNEL_DEFAULT: Payload
Placeholder payload that wraps the current kernel-default
scheduler — Scheduler::EEVDF on Linux 6.6+ (the “no scx
scheduler attached” case). Used as the default value of the
scheduler slot on
KtstrTestEntry so
tests without an explicit scheduler = ... attribute still
get a valid, non-optional reference. Wire name is
"kernel_default" — the Rust const and the serialized form
agree, so the const describes what it selects for (the
kernel’s default) rather than naming a specific scheduler that
a future kernel release could replace.
§kernel_default vs eevdf in sidecars
KERNEL_DEFAULT.name is "kernel_default" (the intent-level
label), while KERNEL_DEFAULT.scheduler_name() returns
"eevdf" (the inner Scheduler::EEVDF’s .name). The two
names answer different questions:
"kernel_default"answers “what did the test author select?” — a future kernel release replacing EEVDF keeps this label stable, so an in-memory match on author intent survives kernel upgrades."eevdf"answers “what scheduler actually ran?” — the concrete scheduling class in effect.
Sidecar serialization reads the scheduler-slot Scheduler
directly. The SidecarResult.scheduler field
(src/test_support/sidecar/mod.rs) is populated by reading
entry.scheduler.name — a field access on the
&'static Scheduler held in the entry’s scheduler slot, with
no Payload indirection. When the scheduler slot holds
&Scheduler::EEVDF (the framework default), the sidecar
records "eevdf". The outer KERNEL_DEFAULT.name
("kernel_default") is NOT written to the sidecar — it stays
in-memory only, used by logs, #[ktstr_test]-declaration
lookups, and Payload::display_name() on the payload-slot
surface. Cross-kernel-version comparisons via sidecar
scheduler therefore see "eevdf" today and whatever future
scheduling class replaces EEVDF tomorrow; author-intent
filtering on "kernel_default" requires consulting the
in-memory Payload::name directly, not the sidecar.
Sourcepub const fn display_name(&self) -> &'static str
pub const fn display_name(&self) -> &'static str
Short, human-readable name for logging and sidecar output.
Sourcepub const fn as_scheduler(&self) -> Option<&'static Scheduler>
pub const fn as_scheduler(&self) -> Option<&'static Scheduler>
Return the inner Scheduler reference when this payload
wraps one. Returns None for PayloadKind::Binary.
Sourcepub const fn is_scheduler(&self) -> bool
pub const fn is_scheduler(&self) -> bool
True when this payload wraps a Scheduler (scheduler
slot). False for binary payloads.
Sourcepub const fn new(
name: &'static str,
kind: PayloadKind,
output: OutputFormat,
default_args: &'static [&'static str],
default_checks: &'static [MetricCheck],
metrics: &'static [MetricHint],
include_files: &'static [&'static str],
uses_parent_pgrp: bool,
known_flags: Option<&'static [&'static str]>,
) -> Payload
pub const fn new( name: &'static str, kind: PayloadKind, output: OutputFormat, default_args: &'static [&'static str], default_checks: &'static [MetricCheck], metrics: &'static [MetricHint], include_files: &'static [&'static str], uses_parent_pgrp: bool, known_flags: Option<&'static [&'static str]>, ) -> Payload
Primary const constructor for a Payload.
Takes every field by position so the #[derive(Payload)]
macro can emit a single call instead of a struct-literal.
#[non_exhaustive] on the struct prevents out-of-crate
struct-literal construction; this constructor — defined in
the same crate as Payload — is not subject to that
restriction, so the macro-expanded tokens that reach
downstream crates compile cleanly.
For one-field constructions prefer Payload::binary — it
calls into this helper and pins the non-identity fields to
the exit-code-only defaults.
Sourcepub const fn binary(name: &'static str, binary: &'static str) -> Payload
pub const fn binary(name: &'static str, binary: &'static str) -> Payload
Minimal const constructor for a binary-kind Payload. Fills
the non-identity fields with the exit-code-only defaults — no
CLI args, no author-declared checks, no metric hints, and
OutputFormat::ExitCode — so a #[ktstr_test] entry or a
direct unit test can declare a runnable binary with one line
instead of spelling out the full struct literal.
The binary string is the executable name passed to
std::process::Command::new inside the guest. Supply it to
the guest via -i / --include-files for CLI invocations or
pre-install it in the initramfs for #[ktstr_test] entries —
see PayloadKind::Binary for the full packaging contract.
Sourcepub const fn scheduler_name(&self) -> &'static str
pub const fn scheduler_name(&self) -> &'static str
The scheduler’s display name.
Returns a compile-time-fixed LABEL, not a runtime reflection
of the scheduling class the live kernel is actually running.
A sidecar written on a kernel whose default is a successor
scheduling class still records whatever string this method
returns — the label comes from the Payload / inner
Scheduler definition, nothing queries /proc or the live
policy. Consumers that need to know the running kernel’s
scheduling class must cross-reference the sidecar’s
host.kernel_release with kernel-version-to-scheduler
knowledge maintained outside the sidecar.
Branch behavior:
PayloadKind::Scheduler(s)→s.name— the label attached to that specific scheduler, e.g."eevdf"forScheduler::EEVDFor"scx_rusty"for a scx_* scheduler. This is what scheduler-kind payloads (includingPayload::KERNEL_DEFAULT, which wrapsScheduler::EEVDF) surface.PayloadKind::Binary(_)→"kernel_default"— a binary payload runs under whatever scheduler the test declares elsewhere (or the kernel default if it declares none), so the binary-kind payload carries no scheduler identity of its own. The returned string is a LABEL (“test author did not pin a scheduler here”), NOT a statement about which scheduling class the VM actually ran under — the live kernel may be running EEVDF, a successor class, or an scx scheduler the binary’s test harness attached separately;scheduler_name()does not observe any of that. Only a scheduler-kind payload explicitly wrappingScheduler::EEVDFreturns the"eevdf"label; every binary-kind payload returns"kernel_default"regardless of what class is running.
Sourcepub const fn scheduler_binary(&self) -> Option<&'static SchedulerSpec>
pub const fn scheduler_binary(&self) -> Option<&'static SchedulerSpec>
The scheduler’s binary spec when scheduler-kind; None for
binary-kind payloads. Consumers that dispatch on the
SchedulerSpec variant (e.g. KernelBuiltin { enable, disable }
hook invocation) use this rather than the scheduler_name
shortcut.
Sourcepub const fn has_active_scheduling(&self) -> bool
pub const fn has_active_scheduling(&self) -> bool
True when this payload drives an active scheduling policy
(anything other than the kernel default EEVDF). Forwards to
SchedulerSpec::has_active_scheduling for scheduler-kind
payloads; binary-kind payloads always return false — a
binary runs under whatever scheduler the test declares, and
does not itself impose one.
Returns true for KernelBuiltin scheduler-kind payloads.
See Self::has_bpf_scheduler for the narrower gate that
excludes them.
Sourcepub const fn has_bpf_scheduler(&self) -> bool
pub const fn has_bpf_scheduler(&self) -> bool
True when this payload drives a userspace BPF scheduler
binary. Forwards to SchedulerSpec::has_bpf_scheduler for
scheduler-kind payloads; binary-kind payloads always return
false.
Distinct from Self::has_active_scheduling: this excludes
KernelBuiltin scheduler-kind payloads (in-kernel policy,
no userspace BPF binary). Use whenever the caller assumes a
BPF binary is attached — verifier_stats wiring, BPF-attach
monitor thresholds, or auto-repro probe gating.
Sourcepub const fn sysctls(&self) -> &'static [Sysctl]
pub const fn sysctls(&self) -> &'static [Sysctl]
Guest sysctls applied before the scheduler starts. Empty slice for binary-kind payloads.
Sourcepub const fn kargs(&self) -> &'static [&'static str]
pub const fn kargs(&self) -> &'static [&'static str]
Extra guest kernel command-line arguments appended when booting the VM. Empty slice for binary-kind payloads.
Sourcepub const fn sched_args(&self) -> &'static [&'static str]
pub const fn sched_args(&self) -> &'static [&'static str]
Scheduler CLI args prepended before per-test extra_sched_args.
Empty slice for binary-kind payloads.
Sourcepub const fn cgroup_parent(&self) -> Option<CgroupPath>
pub const fn cgroup_parent(&self) -> Option<CgroupPath>
Cgroup parent path. None for binary-kind payloads and for
scheduler-kind payloads that did not set one.
Sourcepub const fn config_file(&self) -> Option<&'static str>
pub const fn config_file(&self) -> Option<&'static str>
Host-side path to the scheduler config file. None for
binary-kind payloads and for scheduler-kind payloads that
did not set one.
Sourcepub const fn config_file_def(&self) -> Option<(&'static str, &'static str)>
pub const fn config_file_def(&self) -> Option<(&'static str, &'static str)>
Inline config file definition. None for binary-kind payloads
and for scheduler-kind payloads that did not set one.
Sourcepub const fn assert(&self) -> &'static Assert
pub const fn assert(&self) -> &'static Assert
Scheduler-wide assertion overrides. For binary-kind payloads
returns Assert::NO_OVERRIDES — the default identity value
merge that leaves per-entry assertions untouched.
Sourcepub const fn topology(&self) -> Topology
pub const fn topology(&self) -> Topology
Default VM topology for this payload. Scheduler-kind payloads
expose the topology declared on the inner Scheduler so tests
that inherit from the scheduler slot stay consistent with the
rest of the scheduler’s test surface; binary-kind payloads
return a minimal placeholder
(Topology::DEFAULT_FOR_PAYLOAD)
— a pure binary workload has no scheduler-level topology
opinion, so per-entry #[ktstr_test(...)] overrides are what
actually drive the VM shape.
Sourcepub const fn constraints(&self) -> TopologyConstraints
pub const fn constraints(&self) -> TopologyConstraints
Gauntlet topology constraints. Scheduler-kind payloads forward
to the inner Scheduler::constraints; binary-kind payloads
return TopologyConstraints::DEFAULT.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Payload
impl RefUnwindSafe for Payload
impl Send for Payload
impl Sync for Payload
impl Unpin for Payload
impl UnwindSafe for Payload
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
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§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