pub struct Config {Show 118 fields
pub virtualize_time: bool,
pub virtualize_cpuid: bool,
pub cpu_profile: CpuProfile,
pub cpu_profile_host: Option<HostXstate>,
pub cpu_profile_source: Option<usize>,
pub backend: BackendCapabilities,
pub guest_may_inherit_a_terminal: bool,
pub in_guest_detlog_forward_policy: Option<String>,
pub in_guest_site_patching_off: bool,
pub in_guest_reserved_signals: u64,
pub in_guest_refuses_host_timed_producers: bool,
pub launch_image: Option<LaunchImage>,
pub inherited_seccomp: InheritedSeccomp,
pub epoch: DateTime<Utc>,
pub seed: u64,
pub rng_seed: Option<u64>,
pub fuzz_seed: Option<u64>,
pub clock_multiplier: Option<f64>,
pub virtualize_metadata: bool,
pub mountinfo_root_rewrites: Vec<MountInfoRootRewrite>,
pub mountinfo_device_rewrites: Vec<(u64, u64)>,
pub mountinfo_mount_ids: Vec<u64>,
pub mountinfo_mount_ids_captured: bool,
pub mountinfo_mount_namespace: Option<MountNamespaceIdentity>,
pub mount_id_assignment_order: Vec<u64>,
pub container_mount_table: Option<ContainerMountTable>,
pub directory_placeholder: Option<PathBuf>,
pub container_procfs: bool,
pub sequentialize_threads: bool,
pub runs_post_fork: RunsPostFork,
pub passthru_opt: bool,
pub imprecise_timers: bool,
pub eager_lone_preemptions: bool,
pub signal_state_copy: bool,
pub signal_delivery_check_fatal: bool,
pub chaos: bool,
pub chaos_timeslice_range: Option<TimesliceRange>,
pub chaos_timeslice_draw: ChaosTimesliceDraw,
pub chaos_timeslice: Option<NonZeroU64>,
pub fuzz_futexes: bool,
pub chaos_target_races: bool,
pub chaos_per_thread_slowdown: bool,
pub chaos_slowdown_max_factor: f64,
pub chaos_epoch_length_ns: u64,
pub record_preemptions: bool,
pub strict_schedule_boundaries: bool,
pub record_preemptions_to: Option<PathBuf>,
pub replay_preemptions_from: Option<PathBuf>,
pub replay_schedule_from: Option<PathBuf>,
pub replay_exhausted_panic: bool,
pub die_on_desync: bool,
pub replay_edited_preemptions: bool,
pub replay_continue_fairly: bool,
pub stacktrace_event: Vec<(u64, Option<PathBuf>)>,
pub stacktrace_signal: Option<SigWrapper>,
pub access_trace: Option<PathBuf>,
pub access_trace_from: u64,
pub access_trace_max_records: Option<u64>,
pub access_trace_max_bytes: Option<u64>,
pub preemption_stacktrace: bool,
pub preemption_stacktrace_log_file: Option<PathBuf>,
pub deterministic_io: bool,
pub panic_on_unsupported_syscalls: bool,
pub exit_on_unsupported_syscall: bool,
pub shutdown_on_unsupported_syscall: bool,
pub unsupported_syscall_report_fd: Option<i32>,
pub panic_on_rcb_overshoot: bool,
pub has_uts_namespace: bool,
pub notice_host_network_abstract_binds: bool,
pub guest_ids: GuestIds,
pub standard_stream_aliases: Option<[u8; 3]>,
pub replay_data: Option<PathBuf>,
pub kill_daemons: bool,
pub gdbserver: bool,
pub gdbserver_port: u16,
pub max_timeslice: MaybeTimeslice,
pub target_timeslice: Option<NonZeroU64>,
pub target_timeslice_syscalls_only: bool,
pub futex_wake_yields: bool,
pub pipe_wake_latency: Option<u64>,
pub expired_wait_charge: Option<ExpiredWaitCharge>,
pub work_span_report: Option<PathBuf>,
pub scheduler_turn_cost: Option<NonZeroU64>,
pub cap_preemption_charge: bool,
pub virtual_timeout: Option<NonZeroU64>,
pub sigint_instakill: bool,
pub warn_non_zero_binds: bool,
pub sched_heuristic: SchedHeuristic,
pub sched_seed: Option<u64>,
pub network_trace: NetworkTraceConfig,
pub sched_sticky_random_param: f64,
pub recordreplay_modes: bool,
pub replaying: bool,
pub stop_after_turn: Option<u64>,
pub stop_after_iter: Option<u64>,
pub signal_at: Option<SignalAt>,
pub debug_externalize_sockets: bool,
pub debug_futex_mode: BlockingMode,
pub no_rcb_time: bool,
pub detlog_heap: bool,
pub detlog_stack: bool,
pub detlog_anon: Option<DetlogAnon>,
pub detlog_regs: bool,
pub detlog_io_buffers: bool,
pub detlog_regs_cadence: u64,
pub sysinfo_uptime_offset: u64,
pub memory: u64,
pub virtual_cpus: Option<NonZeroU32>,
pub proc_level: ProcLevel,
pub interrupt_at: Vec<(DetTid, u64)>,
pub happens_before: Option<HappensBeforeProgram>,
pub record_host_inputs: bool,
pub host_input_log: Option<PathBuf>,
pub host_input_snapshots: Vec<HostInputSnapshot>,
pub untraced_code_range: Option<(u64, u64)>,
pub fatal_core_capture: Option<FatalCoreCapture>,
pub in_guest_signal_delivery: bool,
pub annotated_priority_replay: bool,
}Expand description
Configuration options for detcore.
Fields§
§virtualize_time: boolDisable virtual/logical time. Note that virtual time is required for virtual metadata.
virtualize_cpuid: boolDisable virtual cpuid
cpu_profile: CpuProfileThe CPU the guest sees: virtual x86-64-v2/v3 or intercepted host features without hardware randomness. The long help states each profile’s host requirements and determinism limits. Like HERMIT_EPOCH, HERMIT_CPU_PROFILE supplies the value when the flag is absent; an explicit flag wins, unset means x86-64-v2, and a value that names no profile is refused. Admission is the same either way.
cpu_profile_host: Option<HostXstate>The host facts a v3 guest’s leaf 0xD and xstate answers come from, set
by the CLI after the host qualifies; None under v2. Neither profile
field enters the legacy form the DBT runtime reads (DBT refuses v3).
cpu_profile_source: Option<usize>Native CPUID source for host-no-rdrand, selected during admission from the caller’s original allowed CPU set, before container placement. The ptrace launch pins its actual tracer to this CPU. Never restored from recording metadata: host-profile recording/replay is refused.
backend: BackendCapabilitiesHow the execution backend runs the guest, as the backend reports it
through Reverie (reverie::Backend::capabilities).
Detcore reads facts about the backend only from here, never from the
backend’s name, so a new backend is modelled correctly by reporting its
capabilities. The host copies the running backend’s answer into this
field before the run starts. The default,
DEFAULT_BACKEND_CAPABILITIES, describes a ptrace-hosted guest, the
backend Detcore’s own tests use, with the three host-set facts and
reports_sigreturns off.
JSON that the guest can see is written by to_legacy_backend_json,
which carries this field as the separate keys used before it existed;
from_legacy_backend_json reads them back.
guest_may_inherit_a_terminal: boolThe guest may start with a terminal: one of the launcher’s standard
descriptors is a terminal, the launcher has a controlling terminal that
the guest inherits with its session, or the launcher could not tell.
Such a terminal makes Linux send signals at moments the host sets:
SIGHUP and SIGCONT when it hangs up, SIGINT, SIGQUIT and SIGTSTP for its
interrupt, quit and suspend characters, SIGWINCH when it is resized, and
SIGTTIN and SIGTTOU for a background process group’s reads and writes.
The guest makes no traced call that arms them, so where Detcore treats
such signals as reaching the guest from the host
(BackendCapabilities::host_timed_signals_are_physical)
the scheduler records all eight as host-timed for every process before the
guest’s first instruction, and no gated wait ends for them
(https://github.com/rrnewton/hermit/issues/3146).
The host sets it while it prepares the backend configuration. It has no
legacy key: to_legacy_backend_json leaves it out and
from_legacy_backend_json reads it back as false.
in_guest_detlog_forward_policy: Option<String>The forwarding policy (detcore::detlog::ForwardPolicy::encode) every
in-guest Tool must forward its DETLOG records with, on the socket Hermit
passed it (hermit run --verify under SaBRe or in-guest LiteInst);
None when no socket is passed.
The host sets it, not a flag, and every Tool image receives it in the
configuration handshake on its coordinator connection, which guest code
cannot change. A Tool image whose forwarder is missing, or forwards by
another policy (guest code that ran first changed its private
forwarding variables, so some records would be dropped before they are
counted), then reports every forwarded-record count as UNCOUNTED
(detcore::detlog::require_forwarding), so verification refuses the run
instead of accepting a log without those records. Like
guest_may_inherit_a_terminal, it has no legacy key.
in_guest_site_patching_off: boolWhether every in-guest Tool image must run with syscall site patching
off and collect its exit statistics (hermit --backend=in-guest-trap).
The host sets it, not a flag, and every Tool image receives it in the
configuration handshake on its coordinator connection, which guest code
cannot change. The in-guest LiteInst runtime takes both settings from
the guest environment, which guest code running before or during its
installation could change, so once installation returns a Tool image
compares the settings the runtime actually captured with this one and
refuses to run the program when they differ
(detcore::in_guest_site_patching). Like
in_guest_detlog_forward_policy, it has no legacy key.
in_guest_reserved_signals: u64The signals an in-guest runtime keeps for itself, which a guest may
not send to another process or arm as a notification signal: bit
n - 1 for signal n, as Detcore’s other signal sets are kept.
Such a signal sent from one process to another would run the target’s
runtime handler on a thread that does not hold the scheduler’s turn
(A5 step 3c, design section 16.30,
https://github.com/rrnewton/hermit/issues/4485). So Detcore answers a
send of one of these signals to a process other than the caller’s own
(kill, tkill, tgkill, rt_sigqueueinfo, rt_tgsigqueueinfo,
pidfd_send_signal), and any arming of one (fcntl(F_SETSIG),
timer_create, prctl(PR_SET_PDEATHSIG)), with EPERM and a WARN
(Config::reserves_in_guest_signal). A send to the caller’s own
process is unchanged. Empty (0), the default, changes nothing.
The host sets it, not a flag, when it prepares an in-guest run on the
default route: SIGSYS, SIGSEGV while the runtime subscribes
instructions, and SIGTRAP while LiteInst’s guard router may be
installed: on --backend=liteinst, never with
in_guest_site_patching_off (a liteinst image whose environment turns
patching off has no router but keeps SIGTRAP reserved, a known
over-refusal).
Every other backend, and the in-guest loader route, leave it empty.
Every Tool image receives it in the configuration handshake, which
guest code cannot change. Like in_guest_site_patching_off, it has no
legacy key.
in_guest_refuses_host_timed_producers: boolWhether Detcore refuses the guest calls that would let the kernel send a guest process a signal at a moment host timing decides (A5 step 3c, slice 0b; design sections 16.30, D28 and D28a, https://github.com/rrnewton/hermit/issues/4485).
While the in-guest runtime runs its own code, ordinary signals are
blocked, and Linux keeps a blocked signal pending even under
SIG_IGN, so such a signal could become pending at a host-timed
moment whatever the guest’s action. So where this is set, Detcore
answers with EPERM and a WARN the operation that completes such a
producer: an owner for a socket or for a descriptor with O_ASYNC
(F_SETOWN, F_SETOWN_EX, FIOSETOWN, SIOCSPGRP), O_ASYNC for a
descriptor with an owner (F_SETFL, FIOASYNC), a lease
(F_SETLEASE) and a directory notification (F_NOTIFY). It holds a
parent-death signal it can send itself, as it does on ptrace, and
refuses the run by name (pdeathsig-would-fire) if one would fire; it
refuses with EPERM one it cannot hold. A SIGKILL parent-death signal
keeps the kernel’s path. False, the default, changes nothing.
The host sets it, not a flag, when it prepares an in-guest run on the
default route, where it also clears the physical RLIMIT_CPU soft
limit and refuses an inherited descriptor that is already such a
producer (D25). Every other backend, and the in-guest loader route,
leave it false. Every Tool image receives it in the configuration
handshake, which guest code cannot change. Like
in_guest_site_patching_off, it has no legacy key.
launch_image: Option<LaunchImage>The guest’s first image, as its /proc/self/exe link names it, and
the image the kernel exec’d in its place where a launcher loads the
guest (LaunchImage). Detcore answers that link from it until the
guest’s next exec, which Detcore resolves itself. None leaves the
first image’s link to the kernel.
The host sets it, not a flag, from the program it launches. Like
in_guest_detlog_forward_policy it has no legacy key, so DBT’s
legacy form never carries it.
inherited_seccomp: InheritedSeccompThe seccomp state the guest inherits from the thread that starts it
(InheritedSeccomp). The caller that starts the guest states it, as
only the caller knows the filters its launch installs, such as those of
a pre_exec callback; hermit run measures it. Not stated, it is
unknown. Nothing reads it. Whether a guest may start under an inherited
filter is decided by the hermit command, before it starts the guest,
from its own reading of /proc/self/status (host_seccomp::admit).
It has no legacy key:
to_legacy_backend_json leaves it out and
from_legacy_backend_json reads it back as unknown.
epoch: DateTime<Utc>Epoch of the logical time.
This is the datetime from which all time and date modtimes begin and
monotonically increase. It is in RFC3339 format such as 2026-01-01T00:00:00Z.
The stable default here is for library callers and wire-format fixtures;
the hermit run and hermit oci run commands replace an omitted CLI
default with one host wall-clock sample taken before backend dispatch.
A guest that checks TLS certificates over the host network (--network=host or
--record-networking) checks them against this clock, so an epoch outside a server
certificate’s validity fails the HTTPS connections to that server: curl exits 60 with “SSL
certificate problem: certificate is not yet valid” (or “certificate has expired”), and a
libcurl caller sees “SSL peer certificate or SSH remote key was not OK”. For such a run omit
--epoch: hermit run then starts the clock at the current time and saves it in the run’s
manifest, and hermit run --from last-run repeats the run with that epoch.
seed: u64Use this number to seed the PRNG randomness for both RNG and scheduler.
This acts as a global fallback in case either sched_seed or rng-seed
are not explicitly specified
rng_seed: Option<u64>Use this number to seed the PRNG that supplies randomness to the guest.
This supplies guest system calls that expose randomness, as well as
the /dev/[u]random files. It does not affect the rdrand instruction,
which is disabled in the guest.
fuzz_seed: Option<u64>Seeds the PRNG which drives syscall response fuzzing (i.e. chaotically exercising syscall
nondeterminism). Like other seeds, this is initialized from the --seed if not
specifically provided.
clock_multiplier: Option<f64>Logical clock multiplier. Values above one make time appear to go faster within the sandbox.
virtualize_metadata: boolDisable substitution of virtual (deterministic) file metadata in lieu
of the real metadata returned by stat/statx. This also preserves raw
mountinfo device numbers so those interfaces continue to agree. Raw
device values are host/filesystem observations and are not promised to
reproduce across machines. Virtual metadata implies virtualize_time.
mountinfo_root_rewrites: Vec<MountInfoRootRewrite>Proven Hermit-owned mount roots to hide from /proc/*/mountinfo.
This is runtime provenance, not a user option. serde(default) keeps
older serialized configurations compatible and makes backends which do
not use the common container setup explicitly receive no rewrite claim.
mountinfo_device_rewrites: Vec<(u64, u64)>Backend-proven pairs of (mountinfo raw device, stat/statx raw device).
A backend may synthesize mountinfo independently from its pathname metadata implementation. These pairs state that the two raw numbers describe the same filesystem, so Detcore can feed both surfaces through one device identity. The pairs are runtime provenance, not a user option; an absent pair must never be inferred from numeric coincidence.
mountinfo_mount_ids: Vec<u64>Recording/container namespace mount IDs in canonical row order.
Detcore validates every /proc/*/mountinfo view against this order.
It does not number mount IDs by position in it; see
mount_id_assignment_order. It is runtime provenance rather than a
user option; replay retains recording-time raw IDs because its read
events contain recording-time kernel bytes.
mountinfo_mount_ids_captured: boolWhether mountinfo_mount_ids is an exact producer-owned snapshot.
The distinction matters for an empty mountinfo file: an absent snapshot asks Detcore to observe the completed guest namespace, while a captured empty snapshot must remain empty during replay.
mountinfo_mount_namespace: Option<MountNamespaceIdentity>The mount namespace mountinfo_mount_ids was captured in
(MountNamespaceIdentity). A backend that checks its provenance
(KVM) requires its own namespace to be this one, instead of
recapturing the namespace’s rows: a host can detach a copied host mount
from a private namespace at any time by removing that mount’s
directory, so two captures of one namespace need not agree. None
when nothing was captured, and in recordings. Runtime provenance, not a
user option.
mount_id_assignment_order: Vec<u64>Raw mount IDs in the order Detcore numbered them for the guest.
Detcore numbers a raw mount ID when the guest first observes it through
/proc/*/mountinfo or /proc/*/fdinfo/*; mountinfo_mount_ids only
validates mountinfo views. A live run starts empty. Recording persists
the completed order so replay gives every raw ID its recorded number
rather than deriving one from its fresh namespace or launch descriptor
shape.
container_mount_table: Option<ContainerMountTable>The guest’s container mount table, which Detcore renders as every
spelling of /proc/<pid>/mountinfo and /proc/<pid>/mounts on every
backend (crate::container_mounts,
https://github.com/rrnewton/hermit/issues/4213). hermit-cli builds it
once, in the completed container namespace before the guest starts,
or, for --no-namespace and a library caller on KVM that built no
container, in the namespace the guest runs in (its launch mounts and
base mountpoints); a recording carries it, so its replay renders the
recorded table. None (a library caller on a backend other than KVM,
whose command may chroot or mount where Hermit cannot see, and every
older configuration) leaves both files to the kernel, sanitized as
before. Runtime provenance, not a user option.
directory_placeholder: Option<PathBuf>The guest path of the empty, read-only directory hermit-cli mounted in
the guest’s container for Detcore’s placeholder directories where the
guest’s procfs is not the kernel’s (KVM: the backend provides process
signal control, procfs_inode::tool_can_name_guest_descriptors): a
tmpfs at /proc/fs/nfsd, procfs’s own permanently empty mount point,
which Detcore’s --proc level table hides from the guest at every
level, and which the guest’s mount table leaves out. Each descriptor
Detcore serves there for /proc itself or the caller’s own
/proc/<pid>/fd is open on this directory, and Detcore answers every
call through it from its model; an open, stat or statx of the guest’s
that reaches the directory otherwise fails as /proc/fs does. None
where the guest’s procfs is the kernel’s (ptrace, the in-guest
backends: nothing is mounted, see Self::container_procfs), and
where hermit-cli mounted none or a later mount covers it:
--no-namespace, --namespace-only, record and replay, a user mount
over the placeholder, every library caller, and every older
configuration. On KVM, Detcore then serves no placeholder directory,
and an open of /proc or a descriptor directory is refused (EACCES).
Runtime provenance, not a user option.
container_procfs: boolWhether the guest runs in hermit-cli’s container, whose procfs mount
at /proc is its own (every container hermit-cli runs a guest in, not
--no-namespace, not a library caller, not an older configuration).
Where the guest’s procfs is the kernel’s (ptrace), Detcore serves
/proc itself and the caller’s own /proc/<pid>/fd then, each on a
descriptor on that procfs’s root, and serves neither without it.
Runtime provenance, not a user option.
sequentialize_threads: boolSequentialize thread execution deterministically.
runs_post_fork: RunsPostForkChoose which side of an ordinary fork/clone runs first after the child is registered.
Random choices are deterministic under --sched-seed.
passthru_opt: boolUse the optimized partial syscall subscription set instead of intercepting every syscall. This permits unlisted syscalls to bypass Detcore and therefore weakens deterministic accounting; leave it disabled for fail-closed execution.
imprecise_timers: boolIn chaos mode, uses much cheaper approximate preemption timers. Only makes sense when recording preemptions for later (precise) replay.
eager_lone_preemptions: boolStop the guest at every timeslice end, including one where no other
guest thread could run. By default Hermit does not stop a thread that
is the only one able to run before it next enters Detcore (every other
thread waits on a futex without a timeout, on a child or in
rt_sigsuspend; no timer, sleeper, poll deadline or host call is
pending): it processes those timeslice ends when the thread next
enters Detcore, at the same branch counts and in the same order, so the
schedule, the virtual clock and the chaos draws are the same either
way and only the stops are saved. This option turns that off, for
comparison.
signal_state_copy: boolTurn off Detcore’s own copy of each guest thread’s signal dispositions
and masks (A5, docs/SIGNAL_STATE_CHECK.md). The copy is on by default
where it can run (ptrace with serialized threads): it is checked
against the kernel, and decisions A5 converted read it in place of the
kernel’s /proc view. With it off, those decisions read /proc, and
no handler return is reported. A recorded schedule states the setting
it ran under, and replaying it under the other setting is refused.
signal_delivery_check_fatal: boolWhether a signal delivery that the kernel contradicts, where Detcore’s
copy and the kernel are both certain (A5 step 3.2), ends the run as an
internal failure (HERMIT_INTERNAL_FAILURE class=signal-delivery-check)
rather than being logged as a divergence that drops the copy. It is a
Detcore defect either way. hermit run --strict sets it; nothing else
does, and it changes nothing while the copy matches the kernel.
The host sets it. It has no legacy key: to_legacy_backend_json
leaves it out and from_legacy_backend_json reads it back as false.
chaos: boolSchedule threads chaotically.
The behavior of this flag is subject to change. Current behavior is to randomize thread
priorities at every logical timeslice. Other randomization strategies are possible with
--sched-heuristic.
Thread scheduling remains deterministic, determined by the random seed.
chaos_timeslice_range: Option<TimesliceRange>Draw the mean of each chaos slice from MIN..MAX virtual nanoseconds (both included),
log-uniformly, instead of using --max-timeslice as every slice’s mean, and cap every
slice at MAX. Slices stay exponentially distributed around the drawn mean, so some fall
below MIN. Races differ in the slice scale they need: some
need a preemption in a short window, others a long uninterrupted run of one thread, and a
seed sweep under one timeslice explores only one scale. Under a range every run mixes all
the scales in it. The draws come from the scheduler seed’s chaos stream, so a seed
reproduces them, and a preemption record pins every slice end as usual. Sets the run’s
--max-timeslice to MAX: requires --chaos and PMU-backed preemption, and conflicts
with an explicit --max-timeslice, with --target-timeslice and with hermit run --chaos-seeded-timeslice. A small MIN makes runs slower. Example: 1000..200000000.
chaos_timeslice_draw: ChaosTimesliceDrawHow --chaos-timeslice-range draws. slice (the default) draws each slice’s mean from
the range. run instead draws the run’s --max-timeslice once, log-uniformly from the
range as a pure function of the scheduler seed, and the run is then an ordinary chaos run
under it: a sweep’s seeds spread over the scales of the range, each seed at one scale.
That reaches a race needing one scale throughout in more seeds, at a higher cost per run
for the fine draws. The drawn value is printed in --summary-json
(preemption.max_timeslice_ns) and stored in a --record-preemptions-to record, from
which a replay takes it. Without an explicit range, run uses
RECOMMENDED_CHAOS_TIMESLICE_RANGE; slice still requires a range.
chaos_timeslice: Option<NonZeroU64>The --max-timeslice this run drew under --chaos-timeslice-draw=run, or took from the
preemption record it replays. hermit run sets it, and max_timeslice to the same
value, before the run starts; the run’s own preemption record stores it. When set, no
slice draws its mean from --chaos-timeslice-range.
fuzz_futexes: boolUses the --fuzz-seed to generate randomness and fuzz nondeterminism in the futex semantics.
chaos_target_races: boolTargeted chaos: bias scheduling toward known concurrency race patterns
instead of exploring interleavings uniformly. At the scheduler’s existing
nondeterminism points it uses --fuzz-seed to (a) deliver a
process-directed signal to a randomly chosen thread in the group (signal
timing races) and (b) randomize the requeue position of a force-unblocked
thread (lock-ordering / wakeup races). Only takes effect with --chaos;
like the rest of chaos mode it remains reproducible under a fixed seed.
chaos_per_thread_slowdown: boolReproducible per-thread slowdown factors for chaos mode. A factor greater than one makes each RCB consume proportionally more virtual time, while a factor below one makes it consume less. Thus scheduling deadlines and the guest-visible virtual clock describe the same slowed execution rather than applying an out-of-band scheduling bias. The factor is a pure function of scheduler seed, stable deterministic thread id, and chaos epoch. A fixed seed therefore reproduces both timing and interleavings.
chaos_slowdown_max_factor: f64Maximum ratio between the slowest and fastest per-thread slowdown factor
for --chaos-per-thread-slowdown. Each thread’s factor is drawn
log-uniformly from [1/R, R] where R is this value. Must fit the Q32
virtual-time representation and be >= 1.0; 1.0 disables the spread.
chaos_epoch_length_ns: u64Length of a deterministic slowdown epoch in elapsed per-thread logical
nanoseconds. At the first scheduler commit at or after each boundary the
factor is redrawn as factor(seed, stable_dettid, epoch). This is never
wall time. 0 means one epoch for the entire run, making constant slowdown
the single-epoch special case. Recorded preemption artifacts carry exact
epoch transitions and factors for replay. Inert without chaos slowdown.
record_preemptions: boolRecord the timing of preemption events for future replay or experimentation. This is only useful in chaos modes.
strict_schedule_boundaries: boolRecord and replay the complete slice-boundary protocol used by strict trace verification. This mode refuses mismatches, extra observations, incomplete replay and legacy schedule files; it does not resynchronize. Ordinary recording/replay and schedule editing retain their legacy mode.
record_preemptions_to: Option<PathBuf>File to write the record of preemptions (in JSON). Implies --record-preemptions.
replay_preemptions_from: Option<PathBuf>JSON file to read recorded preemptions from. When --chaos mode is activated, these
recorded preemption points take the place of randomized scheduling decisions.
replay_schedule_from: Option<PathBuf>File to read recorded schedule trace from. This execution will replay the schedule verbatim from the file.
replay_exhausted_panic: boolIf we run out of events while replaying a schedule, treat that as a fatal event and panic, rather than continuing execution.
die_on_desync: boolWhen playing a schedule trace from disk, bail out on the first time we desynchronize from the event sequence specified in the trace.
replay_edited_preemptions: boolThe preemption record --replay-preemptions-from reads is not the recording of this
run’s schedule but an edited one, for example one hermit analyze knocked preemptions
out of. A thread then can reach recorded slices that have already ended, which a faithful
replay never does: the replay skips them and goes on with the first recorded slice still
ahead, at its priority, instead of stopping the run. (At a thread’s start the record’s
first priority, which the scheduler has already applied, holds until that slice ends.)
replay_continue_fairly: boolOnce the schedule replayed from --replay-schedule-from runs out,
order the threads queued in turn at each priority by the virtual time
each has run since then, least first, and equal run times by least
recent selection, instead of in queue order. A thread’s run time is
what its own clock has advanced since that point; a thread seen for
the first time, or runnable again after it was not, starts at no less
than the least run time of the runnable threads. That is all it
changes: a selected thread still runs until its slice ends, there is no
preemption on wakeup, and threads pushed to the front of the queue (a
timed wake) and pollers keep their places. Without it threads of equal
priority take turns, so a thread that only computes or reads the clock
keeps the CPU for a whole timeslice at each committing call of another.
It reads nothing from the recording and draws nothing at random, so
the rest of the run is as neutral as without it: what happens there
depends only on the replayed prefix.
stacktrace_event: Vec<(u64, Option<PathBuf>)>Given schedule events traced on recording or replaying, print the stack trace at the moment
after the Nth event in the trace. Optionally, provide an output file into which the stack
trace will be printed, otherwise it goes to stderr. With a recorded or replayed schedule, N
counts every traced event, polling retries and events the schedule does not hold included,
as the desync and missed-stack-trace lines do; the event number a schedule release reports
leaves polling retries out, so it is not such an index. Under
--strict-schedule-boundaries, N is instead a position in the complete boundary stream,
TimesliceEnd records included: a replay requires it to lie inside the stored stream,
while a recording counts the stream as it writes it.
stacktrace_signal: Option<SigWrapper>Internal feature used to signal the guest with SIGINT at every --stacktrace-event, this is
in-lieu of using hermit’s internal stacktrace printing facility, to instead have an external
debugger handle it. Accepts either signal names or numbers.
access_trace: Option<PathBuf>Write an access trace to this path as the run records its schedule; its end line is written
when the run ends, and a trace without it was cut short. The trace is JSON Lines with one
record per syscall (its prehook and posthook positions in the recorded schedule, the thread,
the thread’s syscall count, the arguments, the result, and the resources it used: descriptor
slots and the open files behind them, file contents, pipes, sockets, futex words, memory
ranges, timers, threads and processes), one per signal delivery (its code, fault address and
sender), and the first 256 bytes of each write to fd 1 or 2. It records resource accesses
beside the schedule for inspection and comparison. An observer: it adds no scheduler request and
moves no virtual time, so the schedule and the guest’s results are those of a run without
it, except that Hermit’s own command line, which a guest can read as PID 1’s, shows the
option, and that the trace file itself is inside the container: it exists from before the
guest’s first instruction and grows during the run, so a guest that lists or watches its
directory sees it. Needs a recorded schedule (--record-preemptions-to or --record-preemptions),
whose positions the records name, sequentialized threads and the ptrace backend. The format
is detcore_model::access_trace.
access_trace_from: u64With --record-access-trace-to, leave out the records whose last schedule event comes
before this position. 0, the default, keeps every record. Resource state from before
the position, such as which open file a descriptor number names, is then only partly
visible in the trace.
access_trace_max_records: Option<u64>With --record-access-trace-to, write at most this many records from
--access-trace-from on. Past it the trace stops, without its end line, so a reader
sees it cut short; a run whose records all fit still ends with it. Unlimited by
default.
access_trace_max_bytes: Option<u64>With --record-access-trace-to, write at most this many bytes of header and records.
The record that would pass it is not written: the trace stops there, without its end
line, so a reader sees it cut short, and Hermit says so once on stderr. Defaults to
1073741824 (1 GiB, detcore_model::access_trace::ACCESS_TRACE_DEFAULT_MAX_BYTES), about
three million records at their typical 350 bytes, so a long run cannot fill the disk by
default; pass a larger count for a longer trace.
preemption_stacktrace: boolDeprecated: Print a stacktrace each time the program is preempted. Only makes sense in --chaos mode
and typically goes with preemption recording/replaying.
preemption_stacktrace_log_file: Option<PathBuf>File to write preemption stacktraces to. Implies --preemption-stacktrace. If a
log file is not specified, preemption stacktraces are printed to stderr by default.
deterministic_io: boolEnable deterministic IO by reassuring we always read/write the maximum possible bytes from IO syscalls. There might be cases that read/write syscalls return less bytes than requests. Detcore, makes an effort to request additional bytes until we reach the ones requested or EOF.
panic_on_unsupported_syscalls: boolFail immediately on unsupported syscalls instead of forwarding them.
Ordinary hermit run enables this policy; compatibility requires the
explicit --allow-unsupported-syscalls opt-out.
exit_on_unsupported_syscall: boolReturn a typed Tool error instead of unwinding through a backend callback.
shutdown_on_unsupported_syscall: boolTerminate the whole tracer when an unsupported syscall is observed.
unsupported_syscall_report_fd: Option<i32>Internal inherited file descriptor used to aggregate unsupported syscalls.
panic_on_rcb_overshoot: boolPanic when a precise PMU timer overshoots its expected RCB target instead of logging an error and continuing through normal timer handling. Intended for Detcore debugging.
has_uts_namespace: boolInternal: Set to true if we’re inside a UTS namespace.
notice_host_network_abstract_binds: boolInternal: Print a one-time notice on Hermit’s standard error when the guest binds an
abstract AF_UNIX name, or fails to with EADDRINUSE. hermit run sets it for a run that
asked for --network=host on the ptrace backend: the guest then shares the host’s network
namespace, and with it the abstract names of every program on the host, other Hermit runs
included, and Detcore runs in Hermit’s own process, so the notice reaches Hermit’s stderr
and never the guest’s. Nothing the guest observes depends on it. The DBT backend’s runtime
reads the frozen legacy form (to_legacy_backend_json), which leaves this field out.
guest_ids: GuestIdsHow the guest’s process and thread IDs are numbered
(GuestIds). The host sets it, not a flag:
hermit run from --no-namespace and --pid-base. Recorded schedules
store it, and a replay under another numbering is refused.
standard_stream_aliases: Option<[u8; 3]>Internal: For each of the guest’s standard streams 0, 1 and 2, the lowest of them that
is one open file description with it, as kcmp(KCMP_FILE) answered for the descriptors
the launcher hands the guest (Hermit’s KVM launch, where the guest’s output is not
captured: the stdin it reserved, and its own standard output and error, which the
executor passes through). None where that is not known (any other launch, a captured or
replaced stream, or a kernel that refuses kcmp): each stream is then a description of its
own. Detcore’s lock ledger takes the streams of one group as the one description they are
(package K slice K8-h). The backend’s own answer, a provider query naming which guest
descriptors are one host description, would also cover descriptors no launcher hands
over; no backend offers one yet. The DBT backend’s runtime reads the frozen legacy form
(to_legacy_backend_json), which leaves this field out.
replay_data: Option<PathBuf>Internal: Path to the replay data folder.
kill_daemons: boolKill all remaining tasks iff daemons are the only ones left. Disabled by default.
gdbserver: boolServe the guest to one gdb client on 127.0.0.1:--gdbserver-port, and
wait for it before the guest runs; attach with
gdb -ex 'target remote 127.0.0.1:PORT' PROGRAM. The port is bound in the
host’s network namespace, so the guest keeps the network --network
gives it, and a --strict run can be debugged with every strict refusal
in force. The debugger is an input of the run: breakpoints, writes to the
guest’s memory or registers and the signals it sends all change it. With
a gdbserver, Detcore also takes no reports of the guest’s signal-handler
returns, so a multithreaded guest whose handlers take scheduler turns can
be scheduled differently than without one (docs/SIGNAL_STATE_CHECK.md).
Only the ptrace backend (the default, and --backend=e9patch, whose
rewritten guest runs under it) serves gdb: --backend=kvm, dbt,
sabre, liteinst and in-guest-trap, and --namespace-only, refuse
--gdbserver and --dap-listen.
gdbserver_port: u16The loopback TCP port --gdbserver serves on; 0 lets the system pick a
free one, which the run prints.
max_timeslice: MaybeTimesliceConfigure the maximum time a guest thread may run without returning to Detcore. This is
measured in virtual nanoseconds and enforced with retired conditional branch (RCB)
counting. --preemption-timeout is retained as a deprecated alias.
Set this to disabled or 0 to disable PMU-backed preemption. Positive values must be at
least one RCB (10 virtual nanoseconds at the default clock multiplier) and require
user-space hardware performance counters.
Small values are expensive. A thread that computes without returning to Detcore is stopped
by a PMU timer event at the end of every timeslice, and on the ptrace backend a precise
timer (the default) is placed by stepping the guest through up to the last skid margin of
the slice: 100 to 10000 RCBs depending on the processor, or the --skid-margin override. A
slice no longer than the margin is stepped through whole. A CPU-bound guest can run
thousands of times slower than at the default (a pipeline test took 0.3 s at the default and
994 s at 1000), and a --timeout that expires may mean a slow run rather than a hung one.
hermit run, hermit analyze and hermit bisect say so on stderr when a slice is at most
ten skid margins long, so that at least a tenth of it is stepped (1000000 virtual
nanoseconds at the default clock multiplier on a processor with a 10000-RCB margin); a
preemption replay, whose recording sets the slices, and --imprecise-timers, which steps
nothing, say nothing. --summary reports how many timeslices the run had.
target_timeslice: Option<NonZeroU64>Target logical timeslice, in virtual nanoseconds, checked at syscall boundaries and the
other points where the guest returns control to Detcore: signals, timer events, and
trapped rdtsc and cpuid instructions unless --target-timeslice-syscalls-only is given.
This avoids PMU preemption for workloads that enter the kernel frequently. Omit this option
to use only --max-timeslice.
target_timeslice_syscalls_only: boolDo not end an expired --target-timeslice at a trapped rdtsc or cpuid while a PMU
maximum (--max-timeslice) is armed; end it at the next syscall, signal or timer event,
or at the PMU maximum. A trapped instruction can sit inside a user-space spinlock: QEMU’s
multi-threaded TCG reads the host TSC while holding its vm_clock_lock, and a vCPU that
yields there leaves the other vCPUs spinning for whole PMU slices. Has no effect without
--target-timeslice, or with --max-timeslice disabled, where the trap is the only way
out of a busy-wait on the TSC.
futex_wake_yields: boolAfter a FUTEX_WAKE or FUTEX_WAKE_BITSET that woke at least one waiter, move the waker to
the back of its priority band and have it yield, so that woken threads of its priority run
before it continues. Without
it, a thread that releases a contended lock keeps running until its slice ends and can
re-take the lock many times before the waiter is scheduled: QEMU’s multi-threaded TCG vCPUs
starve its main loop of the big QEMU lock this way. The yield is a scheduler turn of its
own: the waker’s timeslice keeps its deadlines. Each extra thread switch is charged
scheduler time that the guest can observe (see --scheduler-turn-cost), and costs wall
time: a two-vCPU QEMU boot took 5% to 48% longer with it. The waker keeps its priority, so a
woken thread of a lower priority still runs after it; --chaos redraws threads’ priorities
from their chaos PRNG, which can put a woken thread in a lower band; and a random
--sched-heuristic does not select first in, first out. In those cases a woken thread is not
guaranteed to run first. Applies to the precise futex mode while threads are sequentialized,
on the ptrace backend (including e9patch preprocessing, which runs on it); replay applies it
as the recorded run did.
pipe_wake_latency: Option<u64>Hand the turn to a thread polling a pipe or FIFO once another thread’s action has readied it
(https://github.com/rrnewton/hermit/issues/4380), within this many virtual nanoseconds of
the acting thread’s own time. A write that moves bytes into a scheduler-managed pipe, a read
that makes room in one, an explicit close of one end, or an open of a FIFO end readies the
threads polling for that: the scheduler restores their priority, and once the acting
thread’s time is this far past its first readying action, at the next point where it
returns to Detcore (a syscall’s entry or exit, or a signal or trapped instruction), it is
moved behind them and yields, so they run before it continues. A poller is restored to its
own priority and the acting thread moves only within its band, so where --chaos has drawn
a poller a lower priority than the acting thread, that poller still runs after it and is
not guaranteed to run first. 0 hands off at the end of
the readying syscall. Unset (the default), nothing changes: a polled thread whose peer is
ready waits for the acting thread’s slice to end, as before. Each hand-off adds at least two
charged scheduler turns that the guest can observe as time (see --scheduler-turn-cost).
A thread that computes after its write without returning to Detcore delays the hand-off
until it next does, or its slice ends; an implicit close (an exit, an O_CLOEXEC exec)
readies nothing; and an end reopened by path (/proc/self/fd/N, as /dev/fd/N process
substitution does) is a channel of its own, so the other side’s actions do not ready it. Recorded
schedules store the value, and a replay under another value is refused. Refused without
sequentialized threads, on the DBT, KVM and LiteInst backends, with --namespace-only,
--strace-only or --debug-externalize-sockets, and
under a --sched-heuristic that does not select by priority; never applied in record mode.
expired_wait_charge: Option<ExpiredWaitCharge>How a run of consecutive scheduler turns that each end an expired timed wait (a futex wait
answered ETIMEDOUT, or a sleep already due) is charged while another thread is queued:
once, one scheduler turn for the whole run, or each, a turn per wait. Unset, each
under --chaos or a --sched-heuristic that does not select by priority, where the time
each charge adds stretches short waits as race search relies on, and once otherwise, so
that a thread polling with waits shorter than a turn charge blocks and lets other threads
run. A replay of a schedule or of preemptions that leaves this unset takes the value its
record stores (a record that stores none, written before the option existed or by an
each run, charged each wait), and an explicit value that disagrees with the record is
refused. hermit analyze and hermit bisect run every trial under the value of the
recording they start from, or each when analyze records its own chaos target. Under
hermit record and hermit replay every wait is charged, whatever the value.
work_span_report: Option<PathBuf>Write a work/span report of the run’s schedule to this path as JSON when the run ends
normally: work (the sum of every thread’s guest CPU time, in virtual nanoseconds), a
lower span over the scheduler’s certain happens-before edges (program order, spawn, a
child’s exit to the wait that reaps it, conflicting resources), and an upper span that
also orders a thread that waited after everything other threads did meanwhile. The
report lists the dependencies it does not model: what a wait waited for and who sent a
signal, so the lower span can be optimistic; and what passes without a wait (data, an end
of file or a peer’s close found on a channel, a pending signal taken by sigtimedwait,
shared memory, files and devices), which neither span orders; and the CPU time of a call a
thread was running outside the schedule when it was killed. An observer: no scheduling
decision reads it, so the schedule
and the guest’s results are those of a run without it, except that Hermit’s own command
line, which a guest can read as PID 1’s, shows the option. Needs sequentialized threads
and the ptrace backend. Unset (the default), nothing is gathered.
scheduler_turn_cost: Option<NonZeroU64>Virtual nanoseconds that each committed scheduler turn adds to the global clock, before
--clock-multiplier (default 500000). The charge keeps time moving while threads take
turns without running. Every thread observes it as a jump in time across a thread switch,
so a guest that times short intervals while another thread runs, such as a QEMU guest
kernel calibrating its TSC against the emulated PIT, can see a gap far larger than any
work done. A smaller charge makes those jumps smaller; a finite poll or futex timeout then
takes more turns to expire. The charge, after the multiplier, must be between 1 and
1000000000. If a charged turn would pass the end of representable virtual time, the run
stops with HERMIT_VIRTUAL_CLOCK_EXHAUSTED and exit status 125.
cap_preemption_charge: boolCharge a scheduler turn that ends a timeslice because its time ran out (a preemption)
at most the virtual time its thread ran since its previous turn, instead of the full
turn charge (--scheduler-turn-cost, default 500000 virtual nanoseconds). Without it,
every preemption adds the full charge however short the slice was, so a small
--max-timeslice, or a short --chaos draw, multiplies the guest-visible time of
CPU-bound work by about 1 + charge / slice: 501 times at --max-timeslice=1000,
enough for a test’s own timeouts to expire before it reaches the code under test. With
it the factor is at most 2, what a slice one full charge long already costs. A
preemption whose thread ran at least one full charge since its previous turn is
charged as before; a thread’s turns include its syscalls, so one that follows a syscall
by less is charged only the time since that syscall, however long the slice. A capped
turn is charged at least one virtual nanosecond, unless its full charge after
--clock-multiplier is zero. An explicit sched_yield, and every
turn that does not end a timeslice, keep the full charge. This changes what the guest
reads from clock_gettime(CLOCK_MONOTONIC) and the other virtual clocks, and so when
its timers and timeouts expire: recorded schedules store the setting, and a replay
under the other is refused.
Refused where no timeslice ends by expiry (--max-timeslice=disabled without
--target-timeslice) or no Detcore scheduler orders the threads (--namespace-only,
--strace-only, --no-sequentialize-threads), and with the DBT backend; never applied
in record mode.
virtual_timeout: Option<NonZeroU64>End the run in virtual time: once the run’s virtual clock is more than this many virtual
nanoseconds past the run’s start, Hermit grants no further scheduler turn and the run ends
with exit status 124 and the stderr line HERMIT_RUN_TIMEOUT class=virtual-timeout bound_ns=N. The clock is Detcore’s global virtual time since the run began, the same
virtual time --summary reports as elapsed (virttime_elapsed in --summary-json); it is
checked each time the scheduler commits it at the start of a turn, before the turn’s thread
runs, and the check never moves it. A guest that has already exited, or whose remaining
processes a committed exit, kill, in-flight exec or fatal signal has marked doomed, is not
stopped by it. A failed exec clears its in-flight mark before the old image resumes.
Process-group SIGKILL marks are conservative: if a marked process survives a failed group
kill, the bound does not stop it. Unlike --timeout, a
wall-clock bound in seconds that fires wherever the guest has got to when the host’s clock
runs out (class=run-timeout), for a guest whose input all comes from inside the
container this bound fires at the same point of the same schedule on every host and in
every run, so the output written before it, --summary and a --verify comparison are
reproducible. A stopped run is not a guest result, so --verify compares it only under
--verify-allow=failure or both; the default success refuses run 1, as it refuses a
deadlock under Hermit’s model. A thread that polls something outside the container, such
as a pipe a host process feeds, advances virtual time with each retry, and the number of
retries depends on the host, so such a run can stop at another turn; --verify --verify-strict reports that as a divergence. Virtual time does not pass while every thread is blocked in a call
outside the container, so bound such a wait with --timeout. On the ptrace backend the
run is then finished as for a guest that exited: its output is kept and --summary says
the bound fired. On the kvm backend the run exits 124 without a summary, and --verify
with the bound is refused there. Needs sequentialized threads and virtual time: refused
with --no-sequentialize-threads, --namespace-only, --strace-only or
--no-virtualize-time, and on the dbt, liteinst, in-guest-trap and sabre backends, where
it has not been qualified. Also refused before guest or debugger startup with
--gdbserver or --dap-listen: a debugger can suppress a fatal signal after Detcore
marks its process doomed, leaving a survivor outside the bound. Remove the debugger
option or the virtual bound, or use --timeout for a wall-clock bound instead.
sigint_instakill: boolShut down immediately upon SIGINT, rather than letting the guest handle it.
warn_non_zero_binds: boolWarn if binds are non-zero.
sched_heuristic: SchedHeuristicApply a specialized scheduling heuristic which may help exercise certain bugs.
sched_seed: Option<u64>Use this number to seed the PRNG that supplies randomness to the scheduler.
network_trace: NetworkTraceConfigExternal network record or replay, set by hermit run --record-networking
or --replay-networking; Off otherwise, in which case Detcore never
consults it. Its perturbation seed has no fallback to seed or
sched_seed.
sched_sticky_random_param: f64Configure the probability for the Sticky Random scheduler to stay in a thread. For value 0.0, we are behaving like Random. For value 1.0, we are behaving like a DFS, where the same thread is always picked as long as it is available in the Run queue. After this thread is exhausted, the next thread will be chosen randomly. For value 0.5, we have a 50/50 chance to pick the same thread.
recordreplay_modes: boolInternal: An internal flag for indicating to Detcore whether we are in hermit record or
hermit replay mode. This is necessary because there are DIFFERENT global
invariants in record mode (e.g. files dont exist). If we move to a chroot model
and reproduce more, recording less, then this flag should become obsolete.
replaying: boolInternal: Set only by hermit replay, alongside recordreplay_modes. Replay serves
socket reads, writes, accepts and connects, and poll, ppoll, select and
pselect6, from the recording, so they cannot block. They still run as backgrounded
blocking I/O, as during recording, but Detcore’s scheduler commits no other turn until
they finish. Otherwise the descriptor-table changes of different threads could
interleave differently from one replay to the next.
It never enters the legacy form (to_legacy_backend_json), so a standalone DBT
run’s HERMIT_DBT_DETCONFIG reads it as false. Record and replay run only on the
ptrace backend.
stop_after_turn: Option<u64>Internal: debugging option to stop execution after a specific scheduler commit, aka turn number
(non-negative integer). This only makes sense if --sequentialize-threads is specified, as the scheduler is otherwise not engaged.
stop_after_iter: Option<u64>Internal: debugging option to stop execution after a scheduler loop iteration (non-negative integer).
This only makes sense if --sequentialize-threads is specified, as the scheduler is otherwise not engaged.
signal_at: Option<SignalAt>Send SIGNAL to the run’s root process once the scheduler has committed
turn N, as a timer expiry is sent (turn=N:SIGNAL, SIGNAL a name such
as SIGUSR1 or a number, not SIGKILL or SIGSTOP). It is sent before
the next turn is selected, after the first COMMIT turn M with M >= N:
turn numbers also count the turns the scheduler skips, so if turn N
was skipped, after the next commit. The turn is a deterministic point
of the run, so a process in the run that waits for the signal acts at
the same point every time: for example a controller that stops QEMU and
saves a snapshot there. The run itself goes on. Only with
--sequentialize-threads, where the scheduler numbers turns.
debug_externalize_sockets: boolInternal: Debugging option to treat all sockets as mysterious external, nondeterministic entities, rather than container-internal and determinstically scheduled.
debug_futex_mode: BlockingModeInternal: Debugging option to change how futexes are implemented, either precisely modeled by hermit, by polling the kernel with non-blocking futex operations, or treated as external (nondeterministic) operations which unblock at imprecise times.
no_rcb_time: boolDo not count the retired conditional branches (RCBs) of each thread towards its logical time. Instead, count each checkin with the scheduler as a fixed increment to logical time. Even when this option is set, HW RCB performance counters may still be enabled if a max-timeslice is specified.
detlog_heap: boolAn option to enable logging the hash of heap memory maps for the purpose of determinism checking
detlog_stack: boolAn option to enable logging the hash of stack memory maps for the purpose of determinism checking
THIS HASH COVERS argv AND THE ENVIRONMENT, which the kernel places at the top of the initial process stack. Two runs whose command lines differ by a single character therefore produce different stack hashes from the first sample, even when the command lines are the same LENGTH and every stack address matches. Measured: equal-length-but-different argv diverged the hash 14 records in, while byte-identical argv held it for 5023 records.
Holding a run-directory name to a fixed WIDTH is a sufficient control when only addresses matter, and is NOT sufficient here. Comparing two runs under this flag requires byte-identical argv and environment; otherwise the first divergence you find is your own input.
detlog_anon: Option<DetlogAnon>Log a hash of every private, writable anonymous mapping at each syscall, for memory
determinism checking: allocator arenas (scudo’s, jemalloc’s, glibc’s mmap chunks), thread
stacks and TLS blocks, none of which --detlog-heap (the brk heap) or --detlog-stack
(the main thread’s stack) covers. A mapping named by PR_SET_VMA_ANON_NAME
([anon:<name>]) counts as anonymous. --detlog-anon=pages adds a short digest for each
4 KiB page that is not all zero, to find the page where two runs part.
ptrace backend only (also with e9patch preprocessing): the mappings come from the guest
task’s own /proc/<tid>/maps, which an in-guest tool shares and a VMM’s does not hold.
Other backends refuse the flag. EXPENSIVE: every byte of every such mapping is read at
every syscall, in 1 MiB pieces, so a guest with a large heap pays for its whole size each
time; a mapping over 256 MiB (a sanitizer’s shadow, a heap reserved up front) is recorded
by its size alone. Reading an untouched page maps the shared zero page there, which
mincore then reports resident, as with --detlog-heap and --detlog-stack. A thread
stack holds thread IDs and, below its stack pointer, the scratch Hermit writes when it
injects a call, so runs whose IDs differ differ there legitimately. Page indices count
from the mapping’s start, so a mapping that merges or moves renumbers its pages.
detlog_regs: boolLog a hash of the guest REGISTER FILE at guest-logical-control points, for determinism checking. stdout, the INFO log, the stack and the heap are all hashed today; the register file is not, so two backends can differ in register state and every existing check still reports parity.
SAMPLED ONLY AT GUEST-LOGICAL-CONTROL POINTS – see Detcore::detlog_registers. Registers
are NOT sampled inside a tool handler: a backend running its handler in-guest executes code
the ptrace reference never executes, so a difference there is correct behaviour, not a
determinism bug.
detlog_io_buffers: boolLog a hash of each syscall’s OUTPUT BUFFER, taken at the syscall boundary from the address and length in the syscall’s own arguments.
WHAT IT SEES THAT THE MAPPING HASHES DO NOT. --detlog-heap and --detlog-stack hash a
whole named mapping, so their coverage is decided by where the guest happened to ALLOCATE
a buffer. Measured, three runs per cell, same netlink exchange with only the receive
buffer’s home changed: a [stack] buffer is missed by --detlog-heap, a [heap] buffer
is missed by --detlog-stack, and a BSS/static or anonymous-mmap buffer is missed by
BOTH even with both enabled. Anonymous mmap is where glibc puts any malloc above the
128 KiB M_MMAP_THRESHOLD. Reading the extent out of the syscall arguments makes the
buffer’s home irrelevant.
WHY IT IS NOT REDUNDANT WITH --verify. A syscall whose buffer is a bare pointer in
Reverie prints the ADDRESS, not the contents, so a recvmsg returning a stable
Ok(1468) whose payload varies produces a character-identical record and --verify
reports bitwise_parity: true. 44.1% of the syscalls in a QEMU/Linux boot move bytes
through such a buffer.
COST is proportional to bytes actually moved, NOT to syscall count or mapping size:
~0.75 s per GB of guest I/O. A QEMU/Linux boot moves 139.1 MB through these buffers,
against the 10.9 TB --detlog-heap hashes over the same run.
NAME IS PROVISIONAL: io-buffers is the owner’s candidate and is not settled.
ON BY DEFAULT. It was opt-in until 2026-08-24, and opt-in made the
determinism gate weaker than its name: with the hash absent, the netlink
recvmsg above compares equal and --verify reports success. A check
that must be requested is not a standard. The opt-out exists for the
deliberate case (bulk I/O where the cost matters and content parity is
not the question), not as the ordinary setting.
COST OF THE DEFAULT, measured 2026-08-24 on a 316-core x86_64 Linux
build host: a typical small test guest pays about ONE MILLISECOND
(/bin/true 0.029s -> 0.030s, /bin/ls 0.041s -> 0.041s, 8 runs each).
64 MiB through cat costs +0.07-0.10s in a RELEASE build, which is the
~1.1-1.6 s/GB matching the figure quoted above. The same workload in a
DEBUG build costs +3.4s, roughly 50x more, because the hash loop is
unoptimized – so a debug-built node moving tens of megabytes is the one
place the default is felt.
detlog_regs_cadence: u64Sampling cadence for --detlog-regs: hash every Nth guest-logical-control point.
COST TIER. 1 (the default) is the FULL tier – every control point hashed – and is what a
short test should use. Measured cost at this scale is within run-to-run noise: /bin/true
(49 control points), wc -l /etc/passwd (135) and a 5-iteration shell loop (195) were
0.04-0.07s with the flag on and the same with it off. A larger N is the SPOT-CHECK tier for
runs where full hashing is too expensive; it trades detection latency for cost, since a
divergence is only seen at the next sampled point. Every emitted line records the tier it
was produced under, so a cell can state which tier it met instead of leaving it implicit.
sysinfo_uptime_offset: u64Configure a time offset (in seconds) between a container OS considered booted and a guest is executed This primarily affects ‘sysinfo’ syscall’s ‘uptime’ field reporting
memory: u64Configure memory available for the container. Takes a number of bytes, or shorthand (e.g. “1GB”). Right now this doesn’t enforce an upper bound, but does affect the amount of memory reported to the guest.
virtual_cpus: Option<NonZeroU32>Present a machine with this many CPUs, 1 to 128, so that nproc,
sysconf(_SC_NPROCESSORS_ONLN/CONF) and thread pools size themselves
to it. Threads still run one at a time. The affinity mask,
getcpu, CPUID’s APIC IDs, /proc/cpuinfo, /proc/stat, a task’s
Cpus_allowed and /sys/devices/system/cpu (its CPU lists, cpuN
directories, topology and cache files) all describe the same N
single-core sockets on one NUMA node. sched_setaffinity follows
Linux: a mask with none of the N CPUs is EINVAL. The host must list
at least N CPUs under /sys/devices/system/cpu. Without this flag the
guest sees Hermit’s historical single CPU, whose sched_setaffinity
accepts any mask.
proc_level: ProcLevelHow much of /proc the guest sees. Every level is the same on every
backend and host. minimal (the default) shows a small set, modelled
on gVisor’s; standard shows every system-wide name Detcore serves or
plans to serve. A system-wide or /proc/sys name outside the chosen level
does not exist: lookups give ENOENT and listings leave it out. So does
a name in a process’s or a thread’s directory, except a few that Hermit
still leaves to the kernel (mem, uid_map, gid_map, setgroups),
as are whether a process exists and the entries of its fd,
fdinfo, ns and net. A spelling through a symbolic link or .. is
checked only when it opens a file.
interrupt_at: Vec<(DetTid, u64)>Configure extra interrupt points based on thread id and rcb counter. Detcore will raise a precise timer for this RCB whenever it detects that current current thread timeslice intercects any of the interrupt points specified
happens_before: Option<HappensBeforeProgram>Resolved happens-before program: deterministic ordering edges between
anchored events (see detcore_model::happens_before). This is populated
programmatically by hermit-cli after loading and resolving a
--happens-before spec against the guest binary; it is not a direct CLI
flag and is not serialized (it is reconstructed from the spec file each
run, so #[serde(skip)] avoids requiring serde on Sysno-bearing
positions and keeps save-config output stable). The scheduler enforces
these edges only when sequentialize_threads is set.
record_host_inputs: boolWhether Detcore records the host identity of each file the guest
opens, sending each record to the global state, which writes the run’s
records to Self::host_input_log when the run ends (see
crate::host_input). hermit run --verify sets it, so that a
divergence caused by a host file replaced during a run can be named.
The records are never part of the compared log. Serialized, so that it
reaches the Detcore tool on every backend, including one that runs
inside the guest and receives this Config over RPC; never a CLI flag.
host_input_log: Option<PathBuf>Where the global state writes the run’s host-input records, one
crate::host_input::HostInputRecord JSON line each and a
crate::host_input::HostInputLogEnd line, when the run ends.
hermit run --verify sets a private file. A host path, read only by
the global state, which every backend that hosts it builds from this
Config in-process; so set programmatically, like happens_before,
and never serialized.
host_input_snapshots: Vec<HostInputSnapshot>Captured inputs that the launcher copied into private container files.
Only the host global state consumes these identities, just like
host_input_log; guest-side tools still report the actual open’s stat.
Never serialized: every backend constructs that global state from this
in-process config. Physical identities remain necessary for deferred
content checks even when records publish the captured input’s origin.
untraced_code_range: Option<(u64, u64)>A guest address range, [start, end), holding code whose syscalls
the backend lets through without Detcore seeing them, which the guest
cannot otherwise use without faulting. With
Self::record_host_inputs set, a guest call that may change the
memory there (a fixed mapping over it, a protection or advice change
or unmapping that covers it, an open of a process-memory file for
writing) is reported as a change at /, so no host input change is
named in that run (see crate::host_input). The backend that hosts
Detcore in-process sets it, so set programmatically, like
happens_before, and never serialized.
fatal_core_capture: Option<FatalCoreCapture>Opt-in capture of a core file for a guest thread killed by a signal
whose default action dumps core; None, the default, writes nothing.
A host path and host-side limits, read only by the global state at a
fatal exit stop, so set programmatically, like host_input_log, and
never serialized.
in_guest_signal_delivery: boolWhether the in-guest runtime delivers the guest’s signals through
Detcore’s schedule (A5 step 3c.1, gate D35 of the design,
https://github.com/rrnewton/hermit/issues/4485): while its code runs
it blocks every signal it does not reserve, and at each return to
guest code it predicts the kernel’s deliveries, reports them in two
phases, and makes a predicted death a scheduled one. Detcore answers
Reverie’s Tool::in_guest_signal_delivery from it.
The host sets it, not a flag, when it prepares an in-guest run on the
default route, and only where every condition of the gate holds:
site patching off, sequentialized threads, no configuration in which
the two-phase protocol cannot be kept (detcore::two_phase_refusal),
and a scheduler that runs as the init of the guest’s PID namespace,
which only hermit run’s container launch knows. Preparing any run
clears it first, so a caller’s configuration cannot carry it in; the
in-guest loader route never sets it. Every Tool image receives it in
the configuration handshake, which guest code cannot change. False,
the default, changes nothing. Like in_guest_reserved_signals, it
has no legacy key.
annotated_priority_replay: boolWhether --replay-preemptions-from names a record that carries
callback checkpoints, so priority-history replay ends each annotated
row at its recorded callback endpoint instead of at the first stop that
reaches the row’s RCB count
(https://github.com/rrnewton/hermit/issues/4082).
The host sets it, not a flag, from the validated record before the
scheduler or any Tool reads the configuration, and refuses a
configuration it does not qualify for such a record
(preemption_admission::refuse_unqualified_annotated_replay). Preparing
any run sets it from the record, so a caller’s configuration cannot
carry it in; Detcore refuses a record whose checkpoints disagree with
it. A record so annotated was made with --record-preemptions, so the
replay observes schedule events as its recording did
(observes_schedevents). False, the default, changes nothing. Like
in_guest_signal_delivery, it has no legacy key.
Implementations§
Source§impl Config
impl Config
Sourcepub fn virtual_cpu_count(&self) -> u32
pub fn virtual_cpu_count(&self) -> u32
How many CPUs the guest sees: --virtual-cpus, or Hermit’s
historical one.
Sourcepub fn models_signal_targets(&self) -> bool
pub fn models_signal_targets(&self) -> bool
Whether the scheduler models which thread the kernel gives a signal,
from the signal masks it reads from the kernel, and keeps the
per-process ledger of signals discarded at send time; the guest side
publishes a waiting thread’s mask and records handler-restored
real-time signals for it (publish_wait_mask,
record_handler_restore_mask). It needs serialized threads, so that a
mask it reads cannot change before the kernel acts on it, and a backend
whose kernel signal targets a tool can predict
(BackendCapabilities::kernel_signal_targets_are_predictable).
Sourcepub fn reserves_in_guest_signal(&self, signal: i64) -> bool
pub fn reserves_in_guest_signal(&self, signal: i64) -> bool
Whether signal is one of Config::in_guest_reserved_signals. Never
signal 0 (an existence check sends nothing), nor a number outside 1 to
64, which Linux refuses with EINVAL before any target is named. Always
false while the set is empty, which it is on every backend but the
in-guest ones’ default route.
Sourcepub fn with_backend(self, change: impl FnOnce(&mut BackendCapabilities)) -> Self
pub fn with_backend(self, change: impl FnOnce(&mut BackendCapabilities)) -> Self
This configuration with change applied to its backend capabilities.
[BackendCapabilities] cannot be built field by field outside Reverie,
so a caller that needs to adjust individual facts starts from the value
already here.
Sourcepub fn has_default_epoch(&self) -> bool
pub fn has_default_epoch(&self) -> bool
Whether the epoch is the stable library default omitted by Display.
Sourcepub fn capture_epoch_from_host_time(&mut self, now: SystemTime)
pub fn capture_epoch_from_host_time(&mut self, now: SystemTime)
Replace the stable library/test default with the host wall clock captured
by the outer hermit run invocation. The caller owns the single
host-clock read boundary; all guest clock and metadata observations
consume the resulting concrete epoch.
Sourcepub fn largest_nanos_per_rcb(&self) -> f64
pub fn largest_nanos_per_rcb(&self) -> f64
Virtual nanoseconds one RCB takes at this clock multiplier and, under a
chaos per-thread slowdown, at its largest factor: the most any thread’s
RCB takes, so a timeslice of n virtual nanoseconds is at least
n / largest_nanos_per_rcb() RCBs for every thread.
The two multipliers are combined first and then applied to
NANOS_PER_RCB, the order of the one-RCB PMU epsilon that Detcore’s
post-hook compares with the end of the maximum
(post_handler_hook_observed and callback_checkpoint_expiry_due in
detcore/src/lib.rs), which Self::minimum_max_timeslice_nanos
bounds. Floating-point multiplication is not associative: at a clock
multiplier of 2.5 and a largest factor of 4.4, (10 * 2.5) * 4.4 is one
unit in the last place above 110, which would raise that minimum to 111.
Sourcepub fn minimum_max_timeslice_nanos(&self) -> u64
pub fn minimum_max_timeslice_nanos(&self) -> u64
Smallest PMU-backed maximum representable by one RCB at this clock multiplier.
Sourcepub fn validate_invariants(&self)
pub fn validate_invariants(&self)
Check invariants that must hold at every execution boundary without mutating the config.
Sourcepub fn validate(&mut self)
pub fn validate(&mut self)
Sanity check the flags, and update any wherever flag B is implied by A.
Sourcepub fn use_preemption_timer(&self) -> bool
pub fn use_preemption_timer(&self) -> bool
Whether configured preemption can use this backend’s timer mechanism.
This is independent of RCB accounting and does not certify a clock.
Sourcepub fn replays_lone_preemptions(&self) -> bool
pub fn replays_lone_preemptions(&self) -> bool
Whether a thread that is the only one able to run may skip its
timeslice-end stops and have them processed when it next enters
Detcore (see Config::eager_lone_preemptions). Only where a
timeslice end reads nothing from the guest but its branch count, and
nothing but the thread’s next entry could act before the next one:
precise PMU timers keyed to retired branches at one virtual-time rate,
no recorded or replayed schedule or preemptions (they capture guest
state at each end), no slice-boundary protocol, no stack traces at
preemptions or events, no turn-numbered triggers (--stop-after-turn,
--stop-after-iter, --signal-at), no happens-before program, no
manual interrupt points and no syscall-boundary deadline
(--target-timeslice). Never with a gdbserver either: a debugger is
served at the stops, and between skipped ends it would see Detcore’s
slice bookkeeping lag the guest’s program counter.
Sourcepub fn use_rcb_time(&self) -> bool
pub fn use_rcb_time(&self) -> bool
Should we use RCB in computing logical time?
The answer is NO either if --no-rcb-time is specified or if HW counters are disabled by
setting --max-timeslice=disabled.
Sourcepub fn yields_after_futex_wake(&self, woken: u64) -> bool
pub fn yields_after_futex_wake(&self, woken: u64) -> bool
Whether a FUTEX_WAKE that woke woken waiters makes the waker yield
to them (--futex-wake-yields).
A thread that releases a contended lock usually keeps running: the
waiter it woke is queued behind it, and the waker can re-take the lock,
uncontended, many times before that waiter runs.
glibc and Rust mutexes both let a releasing thread barge back in, and on
real hardware the woken thread wins on another CPU within the release
window. Under sequentialized threads it never gets one, so QEMU’s
multi-threaded TCG vCPUs starved its main loop of the big QEMU lock for
whole PMU slices at a time
(https://github.com/rrnewton/hermit/issues/3874). When this holds, the
scheduler moves the waker to the back of its priority band, and the
waker takes a yield turn at the syscall’s post-hook, so woken threads
of its priority run before it continues (it keeps its band; --chaos
can redraw priorities, and a random heuristic does not select first
in, first out). The yield leaves the waker’s timeslice alone.
A thread switch is not free in virtual time: every scheduler decision is charged, so a policy that switches more often moves time that the guest observes. A QEMU guest kernel that calibrates its TSC against the emulated PIT failed that calibration with this policy, because the main loop now ran in the middle of it.
The decision reads only the configuration and the wake’s result, the number of waiters the scheduler took off the futex in the waker’s turn, which is already deterministic. A wake that woke no one keeps the slice. Replay applies the policy exactly as the recorded run did: a preemption record holds slice ends but not this queue order, so the requeue and the yield must happen again for the replayed run to reach the same schedule. Because the yield consumes no slice end and draws nothing from the thread’s chaos PRNG, making it again keeps the replay aligned with its record.
Sourcepub fn scheduler_turn_charge(&self) -> Result<u64, String>
pub fn scheduler_turn_charge(&self) -> Result<u64, String>
The virtual nanoseconds each committed scheduler turn adds to the
global clock: --scheduler-turn-cost (default NANOS_PER_SCHED)
times --clock-multiplier, truncated as it always was. A configured
cost must give a charge of at least one nanosecond, because the charge
is what advances the clock through turns that run no guest code, such
as the retries of a finite poll; a scaled charge of zero would leave
such a timeout unable to expire. A configured cost, or its scaled
charge, above MAX_SCHEDULER_TURN_COST is refused too, so that a
configured charge never exceeds one second per turn.
Sourcepub fn pipe_wake_latency_in_effect(&self) -> Option<u64>
pub fn pipe_wake_latency_in_effect(&self) -> Option<u64>
The --pipe-wake-latency in effect (https://github.com/rrnewton/hermit/issues/4380): the
option’s value in run mode, with sequentialized threads and a heuristic that selects by
priority; None everywhere else, so nothing of the hand-off runs.
Sourcepub fn expired_wait_runs_charged_once(&self) -> bool
pub fn expired_wait_runs_charged_once(&self) -> bool
Whether a run of consecutive turns that each end an expired timed wait is charged one
scheduler turn (--expired-wait-charge): the explicit value, or by default outside race
search (--chaos, or a --sched-heuristic that does not select by priority). Never under
hermit record and hermit replay. A replay that leaves the option unset takes its
record’s value instead (Scheduler::new).
Sourcepub fn use_nonblocking_sockets(&self) -> bool
pub fn use_nonblocking_sockets(&self) -> bool
Should we convert sockets to SOCK_NONBLOCK?
Sourcepub fn should_trace_schedevent(&self) -> bool
pub fn should_trace_schedevent(&self) -> bool
Should we call trace_schedevent to trace each SchedEvent? This applies to both record and replay for scheduled events.
Sourcepub fn observes_schedevents(&self) -> bool
pub fn observes_schedevents(&self) -> bool
Whether this run produces and traces schedule events: the decision
should_trace_schedevent makes for recording and schedule replay, and
also replay of a callback-annotated priority history
(annotated_priority_replay). Such a record was made with
--record-preemptions, so its replay makes every decision this gates
as its recording did, whether or not it writes a record, and its
callback checkpoints compare against the progress those events count.
Sourcepub fn annotated_priority_replay_unqualified(&self) -> Option<&'static str>
pub fn annotated_priority_replay_unqualified(&self) -> Option<&'static str>
Why this effective configuration cannot replay a callback-annotated
priority history, or None when it can. Its row ends are actual
callback endpoints at exact RCB counts, guarded one RCB past each: that
needs the backend’s own Detcore preemption timer events
(delivers_preemption_timer_events), sequentialized threads (the
scheduler that grants each history and acknowledges each row), an
active maximum timeslice, precise timers and RCB time. The answer
names the first unmet requirement. It reads capabilities, never a
backend’s name, and never changes the configuration.
Sourcepub fn interrupts_for_thread(&self, thread_id: DetTid) -> BTreeSet<u64>
pub fn interrupts_for_thread(&self, thread_id: DetTid) -> BTreeSet<u64>
Returns manual interuption points for a given thread
Source§impl Config
impl Config
Sourcepub fn rng_seed(&self) -> u64
pub fn rng_seed(&self) -> u64
Returns effective “rng-seed” parameter taking in account “seed” parameter if former isn’t specified
Sourcepub fn fuzz_seed(&self) -> u64
pub fn fuzz_seed(&self) -> u64
Returns the fuzz_seed, as specified by the user or defaulting to the primary seed if unspecified.
Sourcepub fn sched_seed(&self) -> u64
pub fn sched_seed(&self) -> u64
Returns effective “sched-seed” parameter taking in account “seed” parameter if former isn’t specified
Trait Implementations§
Source§impl Args for Config
impl Args for Config
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<'de> Deserialize<'de> for Config
impl<'de> Deserialize<'de> for Config
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl FromArgMatches for Config
impl FromArgMatches for Config
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 Config
impl Parser for Config
§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 Config
impl RefUnwindSafe for Config
impl Send for Config
impl Sync for Config
impl Unpin for Config
impl UnsafeUnpin for Config
impl UnwindSafe for Config
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> Conv for T
impl<T> Conv for T
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
§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>
§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> 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.