Skip to content

Extending microbench

Writing a mixin

A mixin is simply a class with one or more capture_ or capturepost_ methods. Define it as a standalone class, then combine it with MicroBench via multiple inheritance:

class MBMachineType:
    """Capture the machine architecture (e.g. x86_64, arm64)."""

    def capture_machine_type(self, bm_data):
        import platform
        bm_data['machine_type'] = platform.machine()


class MyBench(MicroBench, MBMachineType, MBPythonInfo):
    pass

Mixins have no required base class. Python's Method Resolution Order (MRO) determines the order in which base classes are searched for methods — a deterministic left-to-right traversal that visits each class exactly once. Because every capture_ method has a unique name, all of them are found and called regardless of MRO order. The MRO only matters if two mixins define a method with the same name, in which case the leftmost class in the inheritance list wins.

Making a mixin CLI-compatible

Document CLI compatibility in the docstring, and add it to cli/registry.py

class MBMachineType:
    """Capture the machine architecture (e.g. x86_64, arm64).

    Note:
        CLI compatible.
    """

    def capture_machine_type(self, bm_data):
        import platform
        bm_data['machine_type'] = platform.machine()

To expose configurable attributes as CLI flags, add a cli_args list of CLIArg instances. The CLI picks them up automatically — no changes to __main__.py are needed:

from microbench import CLIArg

class MBOutputDir:
    """Record the output directory for this run."""

    cli_args = [
        CLIArg(
            flags=['--output-dir'],
            dest='output_dir',
            metavar='DIR',
            help='Output directory to record. CLI default: current working directory.',
            cli_default=lambda cmd: os.getcwd(),
        ),
    ]

    def capture_output_dir(self, bm_data):
        bm_data['output_dir'] = getattr(self, 'output_dir', None)

CLIArg parameters:

Parameter Description
flags Flag strings, e.g. ['--output-dir'].
dest Mixin attribute name to set, e.g. 'output_dir'.
help Help text shown in --help and --show-mixins.
metavar Display name for the value in help (e.g. 'DIR').
type Callable to convert and validate the raw string. Defaults to str. Raise ValueError to reject a value.
nargs Number of arguments, e.g. '+' for one or more.
cli_default Default when the flag is not supplied on the CLI. A callable receives the command list (cmd) and returns the default value. Use _UNSET (the default) to fall back to the mixin's own Python-API default logic instead.

If a cli_default differs from the Python API default — for example because sys.argv[0] points to a different file in CLI context — document both defaults in the help string and in the mixin's docstring.

Mixin flags are only accepted when their mixin is active. Passing a flag without --mixin <name> (or --all) is an error.

Custom capture methods

Add methods prefixed with capture_ to run before the function starts, or capturepost_ to run after it returns. Each receives bm_data, the dictionary that will be serialised as the result record.

from microbench import MicroBench
import platform

class MyBench(MicroBench):
    def capture_machine_type(self, bm_data):
        bm_data['machine'] = platform.machine()  # e.g. 'x86_64'

    def capturepost_slow_call(self, bm_data):
        # call.durations and call.finish_time are available in capturepost_ methods
        if sum(bm_data['call']['durations']) > 1.0:
            bm_data['slow_call'] = True

Avoid key names that clash with built-in fields (e.g. call.start_time, call.name). The mb and call top-level keys are reserved for microbench internals.

For more advanced extension patterns — custom JSON encoding, writing reusable mixins, and tools for consuming benchmark output — see Advanced usage.