Subprocesses and isolation¶
BenchBro supports two related tools: subprocess benchmarks for external commands, and process isolation for Python benchmarks.
Benchmark a command¶
Return a CommandSpec from a @case.subprocess() function:
import sys
from benchbro import Case, CommandSpec
case = Case(name="cli", metric_type="time")
@case.subprocess()
def startup() -> CommandSpec:
return CommandSpec(
argv=[sys.executable, "-c", "pass"],
timeout_s=2.0,
expected_exit_codes=(0,),
)
Commands use an explicit argument vector, never a shell command string. This avoids shell parsing differences and accidental interpolation. Unexpected exit codes and timeouts fail the benchmark run.
CommandSpec also supports:
cwdfor the working directory;- an
envmapping merged into the child environment; stdin_bytesfor fixed input;stdoutandstderrset to"devnull"or"inherit".
Subprocess benchmarks are time-only. Start long-lived services in a session-scoped system, then inject that system into the benchmark.
Isolate a Python benchmark¶
Run every selected Python benchmark in its own worker process:
Or make isolation part of one case:
Isolation prevents state and interpreter effects from leaking between benchmarks. It also gives timeouts a hard process boundary. The tradeoff is additional startup cost and stricter importability requirements.
Note
On platforms without fork, isolated benchmark functions must be importable
from their defining module. Avoid local functions and lambdas.
Timeout behavior¶
- Subprocess commands and isolated workers are terminated at their hard timeout.
- In-process synchronous callables are checked immediately after each invocation; they cannot be interrupted halfway through a Python call.
- Async callables run on BenchBro's managed event loop.