#[non_exhaustive]pub struct Ctx<'a> {
pub cgroups: &'a dyn CgroupOps,
pub topo: &'a TestTopology,
pub duration: Duration,
pub workers_per_cgroup: usize,
pub sched_pid: Option<pid_t>,
pub settle: Duration,
pub work_type_override: Option<WorkType>,
pub assert: Assert,
pub wait_for_map_write: bool,
pub current_step: Arc<AtomicU16>,
pub entry_name: Option<&'static str>,
pub variant_hash: u64,
}Expand description
Runtime context passed to scenario functions.
Provides access to cgroup management, topology information, and
test configuration. Custom scenarios are functions receiving this
Ctx as their sole parameter (e.g. the custom_* fns in
crate::scenario::nested / crate::scenario::stress).
§Method groups
§Time helpers
Self::settled_hold—HoldSpec::fixed(settle + duration * f)sugar for the dominant Step hold-time pattern.
§Cgroup construction
Self::cgroup_def—CgroupDef::named(name).workers(workers_per_cgroup)sugar that pins the default-worker-count shape across 40+ call sites.
§Topology accessors
Self::cpuset_cpus— resolve aCpusetSpecagainst this context’s topology and return the CPU count.
§Constructors
Self::builder— start aCtxBuilderwith sane defaults for unit-test scenarios.Self::payload— start aPayloadRunfor a givenPayload.
§Field groups
Each pub field’s doc is prefixed with its sub-concern label so the rustdoc table groups visibly. The six groups are:
- VM environment —
cgroups,topo. The host-side filesystem + topology handles the scenario interacts with. - Test timing —
duration,settle. The wall-clock budgets that shape every Step’s hold-time math. - Cgroup defaults —
workers_per_cgroup,work_type_override. The merge-time defaultsCgroupDef::merged_worksapplies when aWorkSpecleaves them unset. - Scheduler state —
sched_pid. Liveness-probe target for inter-step scheduler-death detection. - Assertion policy —
assert. The merged default+scheduler+per-test verdict checksrun_scenario/execute_stepsapply. - Runtime coordination —
wait_for_map_write. Framework-set gate that custom scenarios typically do not flip.
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.cgroups: &'a dyn CgroupOpsVM environment. Cgroup filesystem operations. &dyn CgroupOps
(not &CgroupManager) so scenario code can be driven by an
in-memory test double without touching /sys/fs/cgroup.
Production callers pass &CgroupManager and the auto-coercion
is transparent at the call site — ctx.cgroups.set_cpuset(...)
works unchanged.
topo: &'a TestTopologyVM environment. VM CPU topology.
duration: DurationTest timing. How long to run the workload.
workers_per_cgroup: usizeCgroup defaults. Default number of workers per cgroup.
sched_pid: Option<pid_t>Scheduler state. PID of the running scheduler (for liveness
checks), or None when no scheduler is attached. Stored as
Option<pid_t> so the “no scheduler” state is a distinct
variant rather than a 0-sentinel — run_scenario and
step-level liveness probes destructure via if let Some(pid)
instead of != 0 guards.
settle: DurationTest timing. Time to wait after cgroup creation for scheduler stabilization.
work_type_override: Option<WorkType>Cgroup defaults. Override work type for scenarios that use
SpinWait by default.
assert: AssertAssertion policy. Merged assertion config (default_checks +
scheduler + per-test). Used by run_scenario for data-driven
scenarios and by execute_steps as the default when no explicit
checks are passed to execute_steps_with.
wait_for_map_write: boolRuntime coordination. When true, execute_steps blocks after
writing the scenario start marker until the host confirms its BPF
map write is complete — waiting on the bpf_map_write_done latch
that hvc0_poll_loop sets when the host pushes
SIGNAL_BPF_WRITE_DONE over the virtio-console RX queue. Set
automatically by the framework when a KtstrTestEntry declares
bpf_map_write; custom scenarios typically do not flip this
manually.
current_step: Arc<AtomicU16>Phase coordination. Per-VM atomic publishing the current
scenario step index. Written by the scenario driver immediately
before each run_step call and read by three stamping sites
so each captured sample carries the step it belongs to:
(1) the host-side freeze-coordinator periodic-capture path
stamps at periodic-fire time;
(2) the on-demand Op::CaptureSnapshot apply arm stamps at
apply time (the apply happens in the same phase as the
capture);
(3) the host-side user-watchpoint trip handler stamps at
TRIP time, not at registration — the user issues
Op::WatchSnapshot from some Step k, but the actual write
that fires the watchpoint and triggers the snapshot can
happen at any later phase, so the trip-time stamp pins the
sample to the bucket matching when the observation actually
occurred.
Encoded per the framework’s 1-indexed phase convention: 0 is
the BASELINE settle window (the initial value), 1..=N align
with scenario Step ordinals (step_idx + 1). This matches
crate::assert::PhaseBucket::step_index so a phase-aware
sample drops directly into the correct bucket without a
reindex.
Stored as AtomicU16 because the wire StimulusPayload
step-index field is also u16, so a single shared width
keeps the host-side bridge map and the guest-published wire
value type-compatible without narrowing.
Wrapped in Arc so the same per-VM publisher can be cloned
into every consumer thread (scenario driver, freeze-coord,
on-demand-capture apply arms) without a process-global
static — multiple in-process VMs (e.g. parallel gauntlet
variants) each get an independent atomic instead of racing
on shared global state.
entry_name: Option<&'static str>Drift-safe path derivation. The &'static str name of
the KtstrTestEntry
the running test body was dispatched as, stamped by the
guest-side maybe_dispatch_vm_test_with_args and the
host-only dispatch path before the test body runs. Drives
the body-side path-derivation methods
failure_dump_path
(and wprof_pb_path / repro_wprof_pb_path when the
wprof feature is enabled) — the
drift-safe replacement for the legacy pattern of
hardcoding the test fn name as a string literal at the
callsite. When Some(name), those methods derive the
sidecar paths from the macro-stamped value at call time,
so a future test rename surfaces the resulting
Result<PathBuf> bail at compile-time-equivalent-failure
(a deterministic Err) rather than as a runtime ENOENT
against a stale literal.
None is the manually-constructed-Ctx escape hatch — ad-hoc
scenario tests that build Ctx via
CtxBuilder::build without calling
CtxBuilder::entry_name get
None and a path-derivation method invocation bails with an
actionable diagnostic naming the missing-stamp scenario.
Sibling to crate::vmm::VmResult::entry_name which carries
the same &'static str on the post-VM result struct (the
two ends of the test-name chain — pre-VM body context vs
post-VM result — store the same shape so the body-side
ctx.failure_dump_path() and the host-side
result.failure_dump_path() resolve to identical paths).
variant_hash: u64The run’s variant hash (see variant_hash_from_parts),
stamped at the macro dispatch site alongside Self::entry_name.
The body-side failure_dump_path / wprof_pb_path derivations
embed it as the -{16-hex} filename suffix so a gauntlet test’s
per-preset dumps don’t clobber and each matches its sidecar’s
variant hash. 0 on a manually-built fixture (which has
entry_name = None and thus bails before reading this).
Implementations§
Source§impl Ctx<'_>
impl Ctx<'_>
Sourcepub fn current_scheduler(&self) -> Option<&'static SchedulerSpec>
pub fn current_scheduler(&self) -> Option<&'static SchedulerSpec>
Read the live scheduler identity published by the
Op::AttachScheduler / Op::ReplaceScheduler /
Op::DetachScheduler dispatch arms. Returns None when no
scheduler is currently attached (the pre-attach state at
process start and the post-Op::DetachScheduler state).
Distinct from entry.scheduler (the boot-time descriptor
from the #[ktstr_test] macro): entry.scheduler stays
the same across Op::ReplaceScheduler swaps, while
ctx.current_scheduler() reflects the LIVE identity after
any runtime swap. Consumer sites that care about the
currently-attached BPF binary (verifier_stats wiring,
monitor thresholds, auto-repro probe gates) want this
method; sites that care about the test’s declared
scheduler (test-runner skip/include filtering, sidecar
scheduler_name metadata) want entry.scheduler.
v0 limitation: the boot path does not publish the boot
scheduler into the side channel, so the first observable
Some arrives after the first Op::AttachScheduler /
Op::ReplaceScheduler runs. Consumer sites that want a
fallback should call .unwrap_or(&entry.scheduler.binary)
to combine the live view with the boot descriptor.
Sourcepub fn cpuset_cpus(&self, spec: &CpusetSpec) -> usize
pub fn cpuset_cpus(&self, spec: &CpusetSpec) -> usize
Resolve a CpusetSpec against this context’s topology and
return the CPU count. Convenience accessor for tests that need
to size work counts proportional to a cpuset without computing
the topology denominator by hand. Mirrors the framework’s own
resolution: the count is exactly the size of the BTreeSet
spec.resolve(self) returns, so any
CpusetSpec-aware code path (cgroup cpuset assignment,
affinity intent resolution, WorkSpec::workers_pct) sees the
same denominator. Uses the TOPOLOGY-level cpuset, not the
currently-effective cgroup cpuset — narrowing via mid-scenario
Op::SetCpuset does not change the value this returns.
Sourcepub fn settled_hold(&self, fraction_of_duration: f64) -> HoldSpec
pub fn settled_hold(&self, fraction_of_duration: f64) -> HoldSpec
HoldSpec::fixed(settle + duration * fraction_of_duration) —
the dominant Step hold-time pattern across scenarios. A Step
typically holds for the settle window (so the scheduler can
reach steady state) plus some fraction of the workload
duration (often 1.0 for whole-test Steps, or 0.5/1.0/3.0
for multi-Step scenarios that subdivide the duration budget).
The multiplication routes through Duration::mul_f64, so a
fraction like 1.0 / 3.0 may yield a Duration that differs
from an integer-division formulation by ≤1 nanosecond — below
Linux thread sleep granularity and so unobservable at the
hold-evaluation boundary, but worth noting if a test ever
byte-pins a Duration value.
§Panics
When fraction_of_duration is NaN, infinite, or negative
(per the Duration::mul_f64 contract).
§Examples
Step::new(vec![], ctx.settled_hold(0.5)); // settle + half duration
Step::new(vec![], ctx.settled_hold(1.0)); // settle + full durationSourcepub fn cgroup_def(&self, name: impl Into<Cow<'static, str>>) -> CgroupDef
pub fn cgroup_def(&self, name: impl Into<Cow<'static, str>>) -> CgroupDef
Construct a CgroupDef with self.workers_per_cgroup
workers — the most common scenario shape, dedupe of 40+
CgroupDef::named(name).workers(ctx.workers_per_cgroup) call
sites across src/scenario/ and tests/.
Equivalent to:
CgroupDef::named(name).workers(ctx.workers_per_cgroup)Returns a fresh CgroupDef so the test author can chain
further builders (.cpuset, .work, etc.) on the
result. For non-default worker counts call
CgroupDef::named(name).workers(N) directly — the helper
pins ONLY the ctx.workers_per_cgroup default path.
§Examples
// Before (42+ sites):
vec![CgroupDef::named("cg_0").workers(ctx.workers_per_cgroup)].into()
// After:
vec![ctx.cgroup_def("cg_0")].into()
// With additional builders:
ctx.cgroup_def("cg_0").cpuset(...)Sourcepub fn failure_dump_path(&self) -> Result<PathBuf>
pub fn failure_dump_path(&self) -> Result<PathBuf>
Per-test failure-dump sidecar path. Derives
{sidecar_dir()}/{entry_name}-{variant_hash:016x}.failure-dump.json
from the macro-stamped Self::entry_name — the drift-safe
replacement for the legacy pattern of hardcoding the test
fn name as a string literal at the callsite.
§Sibling to crate::vmm::VmResult::failure_dump_path
The post-VM result struct carries its own copy of the
macro-stamped entry name + computes the same path string.
A test body invocation ctx.failure_dump_path() and a
post-VM result.failure_dump_path() resolve to identical
paths because both stamp from the same
entry.name: &'static str source — proc-macro emission at
the #[ktstr_test] site.
§Errors
Bails when self.entry_name is None. The None shape is
the manually-constructed-Ctx escape hatch — ad-hoc scenario
unit tests build Ctx via CtxBuilder::build without
calling CtxBuilder::entry_name; such a context cannot
compute a drift-safe path. The bail diagnostic names the
missing-stamp scenario explicitly so test authors who hit it
know exactly which builder method to call.
Sourcepub fn wprof_pb_path(&self) -> Result<PathBuf>
pub fn wprof_pb_path(&self) -> Result<PathBuf>
Per-test wprof Perfetto-trace sidecar path. Mirror of
Self::failure_dump_path for the wprof artifact —
derives {sidecar_dir()}/{entry_name}-{variant_hash:016x}.wprof.pb
from the macro-stamped Self::entry_name.
Sibling to crate::vmm::VmResult::wprof_pb_path —
the post-VM and pre-VM derivations produce identical paths.
See Self::failure_dump_path for the broader contract +
the manually-constructed-Ctx None-bail diagnostic.
§Errors
Bails when self.entry_name is None per the same shape
as Self::failure_dump_path.
pub fn repro_wprof_pb_path(&self) -> Result<PathBuf>
Source§impl<'a> Ctx<'a>
impl<'a> Ctx<'a>
Sourcepub fn builder(
cgroups: &'a dyn CgroupOps,
topo: &'a TestTopology,
) -> CtxBuilder<'a>
pub fn builder( cgroups: &'a dyn CgroupOps, topo: &'a TestTopology, ) -> CtxBuilder<'a>
Start a new CtxBuilder with required cgroups and topo
borrows and sane defaults for every other field. See
CtxBuilder for the full default set.
Sourcepub fn payload(&'a self, p: &'static Payload) -> PayloadRun<'a>
pub fn payload(&'a self, p: &'static Payload) -> PayloadRun<'a>
Start a PayloadRun
builder for the given Payload.
The builder inherits payload.default_args and
payload.default_checks; chained .arg(...) / .check(...)
calls extend them; .clear_args() / .clear_checks() wipe
both defaults and prior appends. Terminal .run() blocks and
returns Result<(AssertResult, PayloadMetrics)>.
Only PayloadKind::Binary payloads are runnable here;
.run() on a PayloadKind::Scheduler payload returns Err.
Trait Implementations§
Auto Trait Implementations§
impl<'a> Freeze for Ctx<'a>
impl<'a> !RefUnwindSafe for Ctx<'a>
impl<'a> !Send for Ctx<'a>
impl<'a> !Sync for Ctx<'a>
impl<'a> Unpin for Ctx<'a>
impl<'a> !UnwindSafe for Ctx<'a>
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> 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