Skip to main content

Module memory

Module memory 

Source
Expand description

Peak memory for stuffr bench, measured in untimed child processes.

After a row’s timed runs, the parent runs the row once more, once for compression and once for decompression, each in a child: bench’s own executable re-run as stuffr __bench-memory-child <job> (see ChildJob::to_args). getrusage’s ru_maxrss is a per-process high-water mark, which is why each measurement needs a fresh process, and why one per file in --per-file mode (the row reports the largest).

What a child measures. Its 64 KiB read buffer, its 64 KiB output buffer and its open files (the compress child’s output file included) are made first; then it samples its peak resident set as the baseline (the high-water so far, which is its current size, since nothing has run yet), runs the codec to the end, and reports the peak minus that baseline, saturating at 0. So the number is the codec’s resident working memory plus a few small fixed buffers; memory reserved but never touched does not count. The compress child streams the input from the files (each read stops at the length snapshotted at load, as in the timed runs), so an encoder that buffers its whole input (the pure-tier zstd encoder) shows memory growing with the input: that is what using it costs. The compress child writes its compressed output to a guarded temp file the parent created and armed, stuffr-bench-<pid>-<n>; the decompress child then reads that file through the same 64 KiB buffered source the timed runs use. So the row is compressed once more, not twice (ruling F8), and a compress child that fails leaves nothing for the decompress side, which then shows - too.

Same conditions as the timed runs: level, --threads (through governor_for) and --memory-limit. The backend is not sent: the child is the same executable, so it has the same one.

The wire. The child prints one line on stdout, ok <bytes> or err <text>, and exits 0 or 1 to match. Anything else (a crash, a signal, no line) is a failed measurement. A failure never fails the row: its cell is - and the text goes to Memory::error. A refusal by --memory-limit (an Error::ResourceLimit) reads refused by --memory-limit: …, so it is told apart from a crash.

A debug build’s child refuses, as bench does, so this path is not reachable from the CLI tests; Runner lets the parent’s logic be tested with a fake, and child_main is tested in-process.

Structs§

ChildJob
What one child runs. Compress: files concatenated as one stream, written to out (discarded when None). Decompress: exactly one file, the compressed copy; out is None.
ProcessRunner
Runs each job as <this executable> __bench-memory-child …, with stdin closed and stdout and stderr captured, keeping its pid in RUNNING_CHILD while it runs. The executable is resolved once, when the runner is made at the start of the run, and reused for every child.

Enums§

Side
Which half of the round trip a child measures.

Constants§

CHILD_ARG
The hidden first argument that makes the binary a memory child. Not a clap subcommand: main checks for it before clap parses, so it is in no help text and the examples page’s guard (which walks clap) never sees it.
MEASURES
Whether this platform’s memory figures have been verified: macOS (ru_maxrss) and Linux (/proc/self/status). Elsewhere (the BSDs, and off unix) bench reports memory as not measured (ruling F9).

Statics§

RUNNING_CHILD
The pid of the memory child the parent is waiting for, 0 when none. Set once the child is spawned, cleared once it has been waited for; the signal cleanup reads it to kill the child before bench dies.

Traits§

Runner
Runs one child job and returns its reply. The real one spawns a process (ProcessRunner); tests inject a fake.

Functions§

child_entry
The hidden entry main calls first: None unless args[1] is CHILD_ARG; otherwise runs the child, prints its reply line and returns its exit code. A debug build refuses.
child_main
The child: runs job and returns its peak resident memory above the baseline (see the module doc), in bytes.
describe
How a measurement failure reads in mem_error: a refusal by --memory-limit (ResourceLimit, which is also what an allocation failure becomes) says so; everything else is its own message.
interpret
A finished child: its reply when it gave a well-formed one and its exit status agrees (0 for ok, failure for err); otherwise a failure naming status and the first line of its stderr, if any.
measure_memory
measure_memory_with with real child processes (runner). Only where MEASURES: elsewhere the caller reports memory as not measured.
measure_memory_with
One row’s memory under plan: a compress child and a decompress child per stream (plan.mode: one stream over every file, or one per file), reporting each side’s largest peak. Per stream the parent creates an armed temp file, the compress child writes the compressed stream into it, and the decompress child reads it back; it is removed before the next stream begins. Strictly after the row’s timed runs.
parse_reply
A child’s stdout line: Some(Ok(n)) for ok <n>, Some(Err(text)) for err <text> (text not empty), None for anything else.