Example Workflow Input Output Cfg

"""Auto-generated example: InputCfg/OutputCfg — separated input and output classes."""

import math
import bencher as bn

class ServerMetrics(bn.ParametrizedSweep):
    """Output metrics from the server benchmark."""

    throughput = bn.ResultFloat(
        units="req/s", direction=bn.OptDir.maximize, doc="Request throughput"
    )
    latency = bn.ResultFloat(
        units="ms", direction=bn.OptDir.minimize, doc="Response latency"
    )


class ServerConfig(bn.ParametrizedSweep):
    """Server configuration parameters.

    The static bench_function method takes a ServerConfig instance and
    returns a ServerMetrics instance. This separation makes it clear
    which variables are inputs and which are outputs.
    """

    worker_count = bn.FloatSweep(
        default=4, bounds=[1, 32], doc="Number of worker threads"
    )
    cache_size = bn.StringSweep(
        ["small", "medium", "large"], doc="Cache tier size"
    )

    @staticmethod
    def bench_function(cfg: "ServerConfig") -> ServerMetrics:
        """Simulate a server benchmark with the given configuration."""
        output = ServerMetrics()
        size_factor = {"small": 0.7, "medium": 1.0, "large": 1.3}[cfg.cache_size]
        output.throughput = 100 * math.sqrt(cfg.worker_count) * size_factor
        output.latency = 500 / max(output.throughput, 1)
        return output


def example_workflow_input_output_cfg(run_cfg: bn.BenchRunCfg | None = None) -> bn.Bench:
    """InputCfg/OutputCfg — separated input and output classes."""
    # The Bench constructor accepts the static function and the ServerConfig class.
    # This is an alternative to the ParametrizedSweep.benchmark() pattern.
    bench = bn.Bench("input_output_example", ServerConfig.bench_function, ServerConfig, run_cfg)
    bench.plot_sweep(
        input_vars=[ServerConfig.param.worker_count],
        result_vars=[ServerMetrics.param.throughput, ServerMetrics.param.latency],
        description="The InputCfg/OutputCfg pattern separates input parameters from "
        "result metrics into distinct classes. The benchmark function is a static "
        "method on ServerConfig that returns a ServerMetrics instance.",
    )
    bench.plot_sweep(
        input_vars=[ServerConfig.param.worker_count, ServerConfig.param.cache_size],
        result_vars=[ServerMetrics.param.throughput],
        description="A 2D sweep combining a continuous and categorical input. "
        "Each cache size produces a different throughput curve over worker counts.",
    )

    return bench


if __name__ == "__main__":
    bn.run(example_workflow_input_output_cfg, subsampling_divisions=3)