Skip to content

guidellm.benchmark

Benchmark execution and performance analysis framework.

Provides comprehensive benchmarking capabilities for LLM inference workloads, including profile-based execution strategies, metrics collection and aggregation, progress tracking, and multi-format output generation. Supports synchronous, asynchronous, concurrent, sweep, and throughput-based benchmarking profiles for evaluating model performance under various load conditions.

BenchmarkAccumulatorT = TypeVar('BenchmarkAccumulatorT', bound='BenchmarkAccumulator[Any, Any]') module-attribute

Generic type variable for benchmark accumulator implementations

BenchmarkT = TypeVar('BenchmarkT', bound='Benchmark') module-attribute

Generic type variable for benchmark result implementations

AsyncProfile

Bases: Profile

Schedule requests at specified rates using constant or Poisson patterns.

Schedules requests at specified rates using either constant interval or Poisson distribution patterns for realistic load simulation.

Source code in src/guidellm/benchmark/profiles/asynchronous.py
@ProfileFactory.register(["async", "constant", "poisson"])
class AsyncProfile(Profile):
    """
    Schedule requests at specified rates using constant or Poisson patterns.

    Schedules requests at specified rates using either constant interval or
    Poisson distribution patterns for realistic load simulation.
    """

    args: AsyncProfileArgs

    def __init__(
        self,
        args: AsyncProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
        **kwargs: Any,
    ):
        super().__init__(args, random_seed, constraints, **kwargs)
        self.args = args
        if args.kind in ("async", "constant"):
            self._strategy_type: Literal["constant", "poisson"] = "constant"
        elif args.kind == "poisson":
            self._strategy_type = "poisson"
        else:
            raise ValueError(f"Invalid profile kind: {args.kind}")

    @property
    def strategy_types(self) -> list[str]:
        """
        :return: Async strategy types for each configured rate
        """
        return [self._strategy_type] * len(self.args.rate)

    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> AsyncConstantStrategy | AsyncPoissonStrategy | None:
        """
        Generate async strategy for next configured rate.

        If a previous rate was terminated by a constraint with
        stopping_scope='all', remaining rates are skipped.

        :param prev_strategy: Previously completed strategy
        :param prev_benchmark: Benchmark results from previous execution
        :return: AsyncConstantStrategy or AsyncPoissonStrategy for next rate,
            or None if all rates completed or escalation halted
        :raises ValueError: If strategy_type is neither 'constant' nor 'poisson'
        """
        _ = prev_strategy

        if len(self.completed_strategies) >= len(self.args.rate):
            return None

        if prev_benchmark is not None and self._should_stop_escalating(prev_benchmark):
            return None

        current_rate = self.args.rate[len(self.completed_strategies)]

        if self._strategy_type == "constant":
            return AsyncConstantStrategy(
                rate=current_rate,
                max_concurrency=self.args.max_concurrency,
                rampup_duration=self.args.rampup_duration,
            )
        if self._strategy_type == "poisson":
            return AsyncPoissonStrategy(
                rate=current_rate,
                max_concurrency=self.args.max_concurrency,
                random_seed=self.random_seed,
            )
        raise ValueError(f"Invalid strategy type: {self._strategy_type}")

strategy_types property

Returns:

Type Description
list[str]

Async strategy types for each configured rate

next_strategy(prev_strategy, prev_benchmark)

Generate async strategy for next configured rate.

If a previous rate was terminated by a constraint with stopping_scope='all', remaining rates are skipped.

Parameters:

Name Type Description Default
prev_strategy SchedulingStrategy | None

Previously completed strategy

required
prev_benchmark Benchmark | None

Benchmark results from previous execution

required

Returns:

Type Description
AsyncConstantStrategy | AsyncPoissonStrategy | None

AsyncConstantStrategy or AsyncPoissonStrategy for next rate, or None if all rates completed or escalation halted

Raises:

Type Description
ValueError

If strategy_type is neither 'constant' nor 'poisson'

Source code in src/guidellm/benchmark/profiles/asynchronous.py
def next_strategy(
    self,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> AsyncConstantStrategy | AsyncPoissonStrategy | None:
    """
    Generate async strategy for next configured rate.

    If a previous rate was terminated by a constraint with
    stopping_scope='all', remaining rates are skipped.

    :param prev_strategy: Previously completed strategy
    :param prev_benchmark: Benchmark results from previous execution
    :return: AsyncConstantStrategy or AsyncPoissonStrategy for next rate,
        or None if all rates completed or escalation halted
    :raises ValueError: If strategy_type is neither 'constant' nor 'poisson'
    """
    _ = prev_strategy

    if len(self.completed_strategies) >= len(self.args.rate):
        return None

    if prev_benchmark is not None and self._should_stop_escalating(prev_benchmark):
        return None

    current_rate = self.args.rate[len(self.completed_strategies)]

    if self._strategy_type == "constant":
        return AsyncConstantStrategy(
            rate=current_rate,
            max_concurrency=self.args.max_concurrency,
            rampup_duration=self.args.rampup_duration,
        )
    if self._strategy_type == "poisson":
        return AsyncPoissonStrategy(
            rate=current_rate,
            max_concurrency=self.args.max_concurrency,
            random_seed=self.random_seed,
        )
    raise ValueError(f"Invalid strategy type: {self._strategy_type}")

Benchmark

Bases: StandardBaseDict, ABC, Generic[BenchmarkAccumulatorT]

Compile and expose final benchmark execution metrics.

Defines the interface for benchmark result implementations capturing comprehensive performance metrics including latency distributions, throughput measurements, and concurrency patterns. Subclasses implement compilation logic to transform accumulated metrics and scheduler state into structured results with statistical summaries.

Source code in src/guidellm/benchmark/schemas/base.py
class Benchmark(StandardBaseDict, ABC, Generic[BenchmarkAccumulatorT]):
    """
    Compile and expose final benchmark execution metrics.

    Defines the interface for benchmark result implementations capturing
    comprehensive performance metrics including latency distributions, throughput
    measurements, and concurrency patterns. Subclasses implement compilation
    logic to transform accumulated metrics and scheduler state into structured
    results with statistical summaries.
    """

    @property
    @abstractmethod
    def start_time(self) -> float:
        """
        :return: Benchmark start timestamp in seconds since epoch
        """

    @property
    @abstractmethod
    def end_time(self) -> float:
        """
        :return: Benchmark completion timestamp in seconds since epoch
        """

    @property
    @abstractmethod
    def duration(self) -> float:
        """
        :return: Benchmark execution duration in seconds
        """

    @property
    @abstractmethod
    def request_latency(self) -> StatusDistributionSummary:
        """
        :return: Statistical distribution of request latencies
        """

    @property
    @abstractmethod
    def request_throughput(self) -> StatusDistributionSummary:
        """
        :return: Statistical distribution of throughput measurements
        """

    @property
    @abstractmethod
    def request_concurrency(self) -> StatusDistributionSummary:
        """
        :return: Statistical distribution of concurrent request counts
        """

    @classmethod
    @abstractmethod
    def compile(
        cls, accumulator: BenchmarkAccumulatorT, scheduler_state: SchedulerState
    ) -> Any:
        """
        Transform accumulated metrics into final benchmark results.

        :param accumulator: Accumulator instance with collected metrics and state
        :param scheduler_state: Scheduler's final state after execution completion
        :return: Compiled benchmark instance with complete statistical results
        """

duration abstractmethod property

Returns:

Type Description
float

Benchmark execution duration in seconds

end_time abstractmethod property

Returns:

Type Description
float

Benchmark completion timestamp in seconds since epoch

request_concurrency abstractmethod property

Returns:

Type Description
StatusDistributionSummary

Statistical distribution of concurrent request counts

request_latency abstractmethod property

Returns:

Type Description
StatusDistributionSummary

Statistical distribution of request latencies

request_throughput abstractmethod property

Returns:

Type Description
StatusDistributionSummary

Statistical distribution of throughput measurements

start_time abstractmethod property

Returns:

Type Description
float

Benchmark start timestamp in seconds since epoch

compile(accumulator, scheduler_state) abstractmethod classmethod

Transform accumulated metrics into final benchmark results.

Parameters:

Name Type Description Default
accumulator BenchmarkAccumulatorT

Accumulator instance with collected metrics and state

required
scheduler_state SchedulerState

Scheduler's final state after execution completion

required

Returns:

Type Description
Any

Compiled benchmark instance with complete statistical results

Source code in src/guidellm/benchmark/schemas/base.py
@classmethod
@abstractmethod
def compile(
    cls, accumulator: BenchmarkAccumulatorT, scheduler_state: SchedulerState
) -> Any:
    """
    Transform accumulated metrics into final benchmark results.

    :param accumulator: Accumulator instance with collected metrics and state
    :param scheduler_state: Scheduler's final state after execution completion
    :return: Compiled benchmark instance with complete statistical results
    """

BenchmarkAccumulator

Bases: StandardBaseDict, ABC, Generic[RequestT, ResponseT]

Track and accumulate benchmark metrics during scheduler execution.

Maintains incremental metric estimates as requests are processed, enabling real-time progress monitoring and efficient metric compilation. Subclasses implement specific metric calculation strategies based on request/response characteristics and scheduler state evolution.

Source code in src/guidellm/benchmark/schemas/base.py
class BenchmarkAccumulator(StandardBaseDict, ABC, Generic[RequestT, ResponseT]):
    """
    Track and accumulate benchmark metrics during scheduler execution.

    Maintains incremental metric estimates as requests are processed, enabling
    real-time progress monitoring and efficient metric compilation. Subclasses
    implement specific metric calculation strategies based on request/response
    characteristics and scheduler state evolution.
    """

    config: BenchmarkConfig = Field(
        description="Benchmark execution configuration and constraints",
    )

    @abstractmethod
    def update_estimate(
        self,
        response: ResponseT | None,
        request: RequestT,
        info: RequestInfo,
        scheduler_state: SchedulerState,
    ):
        """
        Incrementally update metrics with completed request data.

        :param response: Backend response data if request succeeded
        :param request: Request instance submitted to backend
        :param info: Request timing, status, and execution metadata
        :param scheduler_state: Current scheduler state with queue and concurrency info
        """
        ...

update_estimate(response, request, info, scheduler_state) abstractmethod

Incrementally update metrics with completed request data.

Parameters:

Name Type Description Default
response ResponseT | None

Backend response data if request succeeded

required
request RequestT

Request instance submitted to backend

required
info RequestInfo

Request timing, status, and execution metadata

required
scheduler_state SchedulerState

Current scheduler state with queue and concurrency info

required
Source code in src/guidellm/benchmark/schemas/base.py
@abstractmethod
def update_estimate(
    self,
    response: ResponseT | None,
    request: RequestT,
    info: RequestInfo,
    scheduler_state: SchedulerState,
):
    """
    Incrementally update metrics with completed request data.

    :param response: Backend response data if request succeeded
    :param request: Request instance submitted to backend
    :param info: Request timing, status, and execution metadata
    :param scheduler_state: Current scheduler state with queue and concurrency info
    """
    ...

BenchmarkArgs

Bases: ReloadableBaseModel

Common benchmark configuration arguments.

Source code in src/guidellm/benchmark/schemas/entrypoints.py
class BenchmarkArgs(ReloadableBaseModel):
    """Common benchmark configuration arguments."""

    model_config = args_model_config()

    backend: BackendArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("openai_http"),
        description=(
            "Backend configuration to define how to send requests to the model."
        ),
        examples=[
            {
                "kind": "openai_http",
                "target": "http://localhost:8000/v1",
            }
        ],
        json_schema_extra={"argument_alias": "backend"},
    )
    profile: ProfileArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("sweep"),
        description="Profile configuration to control benchmark execution.",
        examples=[{"kind": "sweep", "sweep_size": [10.0]}],
        json_schema_extra={"argument_alias": "profile"},
    )
    constraints: list[ConstraintArgs] = Field(  # type: ignore[assignment]
        description="Execution constraints to enforce during benchmark execution",
        examples=[{"kind": "max_requests", "value": 10}],
        default_factory=list,
        json_schema_extra={"argument_alias": "constraint"},
    )
    tokenizer: DataTokenizerArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("huggingface_auto"),
        description="Tokenizer configuration",
        examples=[{"kind": "huggingface_auto"}],
        json_schema_extra={"argument_alias": "tokenizer"},
    )
    data: list[DataArgs] = Field(  # type: ignore[assignment]
        description="List of dataset sources to use in the benchmarks",
        examples=[
            {"kind": "synthetic_text", "prompt_tokens": 100, "output_tokens": 100},
            {
                "kind": "huggingface",
                "source": "my/dataset",
                "load_kwargs": {"split": "test", "name": "my_dataset"},
            },
        ],
        min_length=1,
        json_schema_extra={"argument_alias": "data"},
    )
    data_column_mapper: DataPreprocessorArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("generative_column_mapper"),
        description="Specify how to map dataset columns into prompts and outputs.",
        examples=[{"kind": "generative_column_mapper"}],
        json_schema_extra={"argument_alias": "data_column_mapper"},
    )
    data_preprocessors: list[DataPreprocessorArgs] = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind_list("encode_media"),  # type: ignore[arg-type]
        description="List of dataset preprocessors to apply to the datasets.",
        examples=[{"kind": "encode_media"}],
        json_schema_extra={"argument_alias": "data_preprocessor"},
    )
    data_finalizer: DataFinalizerArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("generative"),
        description="Finalizer for preparing data samples into requests",
        examples=[{"kind": "generative"}],
        json_schema_extra={"argument_alias": "data_finalizer"},
    )
    data_loader: DataLoaderArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("pytorch"),
        description="Specify how to load the datasets into memory.",
        examples=[{"kind": "pytorch"}],
        json_schema_extra={"argument_alias": "data_loader"},
    )
    seed: RandomArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("static"),
        description="Random configuration for reproducibility (e.g., seed value)",
        examples=[{"kind": "static", "value": 42}],
        json_schema_extra={"argument_alias": "seed"},
    )
    outputs: list[BenchmarkOutputArgs] = Field(
        default_factory=lambda: default_kind_list("json", "csv"),  # type: ignore[arg-type]
        description="Benchmark output formats and paths.",
        examples=[
            {"kind": "json", "filename": "benchmarks.json"},
        ],
        json_schema_extra={"argument_alias": "output"},
    )
    metrics: MetricsArgs = Field(  # type: ignore[assignment]
        default_factory=lambda: default_kind("generative"),
        description="Configuration for metrics collection and request sampling.",
        json_schema_extra={"argument_alias": "metrics"},
    )

BenchmarkConfig

Bases: StandardBaseDict

Encapsulate execution parameters and constraints for benchmark runs.

Defines comprehensive configuration including scheduler strategy, constraint sets, transient phase handling, metric sampling preferences, and execution metadata. Coordinates profile, request, backend, and environment configurations to enable reproducible benchmark execution with precise control over metric collection.

Source code in src/guidellm/benchmark/schemas/base.py
class BenchmarkConfig(StandardBaseDict):
    """
    Encapsulate execution parameters and constraints for benchmark runs.

    Defines comprehensive configuration including scheduler strategy, constraint
    sets, transient phase handling, metric sampling preferences, and execution
    metadata. Coordinates profile, request, backend, and environment configurations
    to enable reproducible benchmark execution with precise control over metric
    collection.
    """

    id_: str = Field(
        default_factory=lambda: str(uuid.uuid4()),
        description="Unique identifier for this benchmark execution",
    )
    run_id: str = Field(
        description="Identifier grouping related benchmark runs in a series",
    )
    run_index: int = Field(
        description="Zero-based index of this run within the benchmark series",
    )
    strategy: SchedulingStrategy = Field(
        description="Scheduler strategy controlling request execution patterns",
    )
    constraints: dict[str, dict[str, Any]] = Field(
        description="Constraint definitions applied to scheduler strategy execution",
    )
    sample_size: int | None = Field(
        default=None,
        description=(
            "Maximum number of requests per status group to retain full data for. "
            "None keeps all, 0 strips all, N > 0 uses reservoir sampling."
        ),
    )
    warmup: TransientPhaseConfig = Field(
        default_factory=TransientPhaseConfig,
        description="Warmup phase configuration excluding initial transient period",
    )
    cooldown: TransientPhaseConfig = Field(
        default_factory=TransientPhaseConfig,
        description="Cooldown phase configuration excluding final transient period",
    )
    prefer_response_metrics: bool = Field(
        default=True,
        description="Prioritize response-based metrics over request-based metrics",
    )
    profile: dict[str, Any] = Field(
        description="Profile instance coordinating multi-strategy execution",
    )
    requests: dict[str, Any] = Field(
        description="Request generation configuration and dataset metadata",
    )
    backend: dict[str, Any] = Field(
        description="Backend connection parameters and service configuration",
    )
    environment: dict[str, Any] = Field(
        description="Execution environment details and system metadata",
    )

BenchmarkScenario

Bases: ReloadableBaseModel, BaseSettings

Configuration arguments for generative text benchmark execution.

Defines all parameters for benchmark setup including target endpoint, data sources, backend configuration, processing pipeline, output formatting, and execution constraints. Supports loading from scenario files and merging with runtime overrides for flexible benchmark construction from multiple sources.

Example::

# Load from built-in scenario with overrides
args = BenchmarkScenario.create(
    scenario="chat",
    spec={"backend": {"kind": "openai_http", "target": "http://localhost:8000/v1"}},
)

# Create from keyword arguments only
args = BenchmarkScenario(
    spec=BenchmarkArgs(
        backend={"kind": "openai_http", "target": "http://localhost:8000/v1"},
        data=[{"kind": "synthetic_text"}],
    ),
)
Source code in src/guidellm/benchmark/schemas/entrypoints.py
class BenchmarkScenario(ReloadableBaseModel, BaseSettings):
    """
    Configuration arguments for generative text benchmark execution.

    Defines all parameters for benchmark setup including target endpoint, data
    sources, backend configuration, processing pipeline, output formatting, and
    execution constraints. Supports loading from scenario files and merging with
    runtime overrides for flexible benchmark construction from multiple sources.

    Example::

        # Load from built-in scenario with overrides
        args = BenchmarkScenario.create(
            scenario="chat",
            spec={"backend": {"kind": "openai_http", "target": "http://localhost:8000/v1"}},
        )

        # Create from keyword arguments only
        args = BenchmarkScenario(
            spec=BenchmarkArgs(
                backend={"kind": "openai_http", "target": "http://localhost:8000/v1"},
                data=[{"kind": "synthetic_text"}],
            ),
        )
    """

    model_config = SettingsConfigDict(
        env_prefix="GUIDELLM__",
        env_nested_delimiter="__",
        validate_default=True,
    )

    @classmethod
    def create(cls, scenario: Path | str | None, **kwargs: Any) -> BenchmarkScenario:
        """
        Create benchmark args from scenario file and keyword arguments.

        Loads base configuration from scenario file (built-in or custom) and merges
        with provided keyword arguments. Arguments explicitly set via kwargs override
        scenario values, while defaulted kwargs are ignored to preserve scenario
        settings.

        :param scenario: Path to scenario file, built-in scenario name, or None
        :param kwargs: Keyword arguments to override scenario values
        :return: Configured benchmark args instance
        :raises ValueError: If scenario is not found or file format is unsupported
        """
        constructor_kwargs = {}

        if scenario is not None:
            if isinstance(scenario, str) and scenario in (
                builtin_scenarios := get_builtin_scenarios()
            ):
                scenario_path = builtin_scenarios[scenario]
            elif Path(scenario).exists() and Path(scenario).is_file():
                scenario_path = Path(scenario)
            else:
                raise ValueError(f"Scenario '{scenario}' not found.")

            with scenario_path.open() as file:
                if scenario_path.suffix == ".json":
                    scenario_data = json.load(file)
                elif scenario_path.suffix in {".yaml", ".yml"}:
                    scenario_data = yaml.safe_load(file)
                else:
                    raise ValueError(
                        f"Unsupported scenario file format: {scenario_path.suffix}"
                    )
            # NOTE: If the scenario file is a report, it contains a "config" key with
            # the benchmark configuration. This is a hack and should be replaced.
            if "config" in scenario_data:
                # loading from a report file
                scenario_data = scenario_data["config"]
            constructor_kwargs.update(scenario_data)

        # NOTE In the future replace deep_update with a more intelligent merging
        #      strategy that accounts for changes to `kind`.
        # Apply overrides from kwargs
        deep_update(constructor_kwargs, kwargs)

        return cls.model_validate(constructor_kwargs)

    def get_benchmarks(self) -> list[BenchmarkArgs]:
        """
        Get list of benchmark argument instances for each individual benchmark.

        Combines global arguments with individual benchmark overrides to produce a
        list of fully configured benchmark argument instances for execution.

        :return: List of benchmark argument instances
        """
        parser = ArgStringParser(allow_overwrite=True)
        benchmarks = []
        for benchmark_override in self.benchmarks:
            if benchmark_override is None:
                benchmarks.append(self.spec.model_copy(deep=True))
            else:
                # Create a copy of the common args to apply overrides to
                benchmark_args = self.spec.model_dump(mode="python")
                for key, value in benchmark_override.items():
                    parser.set(benchmark_args, key, value)
                benchmarks.append(BenchmarkArgs.model_validate(benchmark_args))

        return benchmarks

    metadata: BenchmarkMetadata = Field(
        default_factory=BenchmarkMetadata,
        description=(
            "User metadata to describe the benchmark run. This data is written "
            "to the output file but not otherwise used by GuideLLM)."
        ),
        examples=[
            {"labels": {"name": "benchmark", "description": "Benchmark description"}}
        ],
    )
    spec: BenchmarkArgs = Field(
        default_factory=BenchmarkArgs,  # type: ignore[arg-type]
        description="Global configuration parameters for benchmark execution.",
        examples=[
            {
                "backend": {
                    "kind": "openai_http",
                    "target": "http://localhost:8000/v1",
                },
                "data": [{"kind": "synthetic_text"}],
            }
        ],
    )
    benchmarks: list[dict[str, Any] | None] = Field(
        default_factory=lambda: [None],  # type: ignore[arg-type]
        description=(
            "Individual benchmark parameter overrides. This allows overriding "
            "parameters and constraints for each benchmark run by a profile."
        ),
        min_length=1,
        examples=[
            {"profile.rate": 10.0, "constraints[0].seconds": 10},
            {"profile.rate": 20.0, "constraints[0].seconds": 20},
        ],
    )

    @model_validator(mode="before")
    @classmethod
    def insert_first_benchmark(cls, data: Any) -> Any:
        """
        Inserts the first benchmark into the common args.

        This allows users to ommit fields from the common args if they have overrides
        in the first benchmark.
        """
        if not isinstance(data, dict):
            return data

        if "benchmarks" not in data or not data["benchmarks"]:
            # No benchmarks provided, insert a blank one
            data["benchmarks"] = [None]

        first_benchmark: dict[str, Any] | None = data["benchmarks"][0]
        if isinstance(first_benchmark, dict) and first_benchmark:
            # Ensure "spec" field exists for the parser to insert into
            data["spec"] = data.get("spec", {})
            parser = ArgStringParser(allow_overwrite=True)

            # Insert the first benchmark into the common args
            # Create fields recursively.
            for key, value in first_benchmark.items():
                parser.set(data["spec"], key, value)

        return data

create(scenario, **kwargs) classmethod

Create benchmark args from scenario file and keyword arguments.

Loads base configuration from scenario file (built-in or custom) and merges with provided keyword arguments. Arguments explicitly set via kwargs override scenario values, while defaulted kwargs are ignored to preserve scenario settings.

Parameters:

Name Type Description Default
scenario Path | str | None

Path to scenario file, built-in scenario name, or None

required
kwargs Any

Keyword arguments to override scenario values

{}

Returns:

Type Description
BenchmarkScenario

Configured benchmark args instance

Raises:

Type Description
ValueError

If scenario is not found or file format is unsupported

Source code in src/guidellm/benchmark/schemas/entrypoints.py
@classmethod
def create(cls, scenario: Path | str | None, **kwargs: Any) -> BenchmarkScenario:
    """
    Create benchmark args from scenario file and keyword arguments.

    Loads base configuration from scenario file (built-in or custom) and merges
    with provided keyword arguments. Arguments explicitly set via kwargs override
    scenario values, while defaulted kwargs are ignored to preserve scenario
    settings.

    :param scenario: Path to scenario file, built-in scenario name, or None
    :param kwargs: Keyword arguments to override scenario values
    :return: Configured benchmark args instance
    :raises ValueError: If scenario is not found or file format is unsupported
    """
    constructor_kwargs = {}

    if scenario is not None:
        if isinstance(scenario, str) and scenario in (
            builtin_scenarios := get_builtin_scenarios()
        ):
            scenario_path = builtin_scenarios[scenario]
        elif Path(scenario).exists() and Path(scenario).is_file():
            scenario_path = Path(scenario)
        else:
            raise ValueError(f"Scenario '{scenario}' not found.")

        with scenario_path.open() as file:
            if scenario_path.suffix == ".json":
                scenario_data = json.load(file)
            elif scenario_path.suffix in {".yaml", ".yml"}:
                scenario_data = yaml.safe_load(file)
            else:
                raise ValueError(
                    f"Unsupported scenario file format: {scenario_path.suffix}"
                )
        # NOTE: If the scenario file is a report, it contains a "config" key with
        # the benchmark configuration. This is a hack and should be replaced.
        if "config" in scenario_data:
            # loading from a report file
            scenario_data = scenario_data["config"]
        constructor_kwargs.update(scenario_data)

    # NOTE In the future replace deep_update with a more intelligent merging
    #      strategy that accounts for changes to `kind`.
    # Apply overrides from kwargs
    deep_update(constructor_kwargs, kwargs)

    return cls.model_validate(constructor_kwargs)

get_benchmarks()

Get list of benchmark argument instances for each individual benchmark.

Combines global arguments with individual benchmark overrides to produce a list of fully configured benchmark argument instances for execution.

Returns:

Type Description
list[BenchmarkArgs]

List of benchmark argument instances

Source code in src/guidellm/benchmark/schemas/entrypoints.py
def get_benchmarks(self) -> list[BenchmarkArgs]:
    """
    Get list of benchmark argument instances for each individual benchmark.

    Combines global arguments with individual benchmark overrides to produce a
    list of fully configured benchmark argument instances for execution.

    :return: List of benchmark argument instances
    """
    parser = ArgStringParser(allow_overwrite=True)
    benchmarks = []
    for benchmark_override in self.benchmarks:
        if benchmark_override is None:
            benchmarks.append(self.spec.model_copy(deep=True))
        else:
            # Create a copy of the common args to apply overrides to
            benchmark_args = self.spec.model_dump(mode="python")
            for key, value in benchmark_override.items():
                parser.set(benchmark_args, key, value)
            benchmarks.append(BenchmarkArgs.model_validate(benchmark_args))

    return benchmarks

insert_first_benchmark(data) classmethod

Inserts the first benchmark into the common args.

This allows users to ommit fields from the common args if they have overrides in the first benchmark.

Source code in src/guidellm/benchmark/schemas/entrypoints.py
@model_validator(mode="before")
@classmethod
def insert_first_benchmark(cls, data: Any) -> Any:
    """
    Inserts the first benchmark into the common args.

    This allows users to ommit fields from the common args if they have overrides
    in the first benchmark.
    """
    if not isinstance(data, dict):
        return data

    if "benchmarks" not in data or not data["benchmarks"]:
        # No benchmarks provided, insert a blank one
        data["benchmarks"] = [None]

    first_benchmark: dict[str, Any] | None = data["benchmarks"][0]
    if isinstance(first_benchmark, dict) and first_benchmark:
        # Ensure "spec" field exists for the parser to insert into
        data["spec"] = data.get("spec", {})
        parser = ArgStringParser(allow_overwrite=True)

        # Insert the first benchmark into the common args
        # Create fields recursively.
        for key, value in first_benchmark.items():
            parser.set(data["spec"], key, value)

    return data

Benchmarker

Bases: Generic[BenchmarkT, RequestT, ResponseT], ABC, ThreadSafeSingletonMixin

Orchestrates benchmark execution across scheduling strategies.

Coordinates benchmarking runs by managing request scheduling, metric aggregation, and result compilation. Implements a thread-safe singleton pattern to ensure consistent state management across concurrent operations while supporting multiple scheduling strategies and execution environments.

Source code in src/guidellm/benchmark/benchmarker.py
class Benchmarker(
    Generic[BenchmarkT, RequestT, ResponseT],
    ABC,
    ThreadSafeSingletonMixin,
):
    """
    Orchestrates benchmark execution across scheduling strategies.

    Coordinates benchmarking runs by managing request scheduling, metric aggregation,
    and result compilation. Implements a thread-safe singleton pattern to ensure
    consistent state management across concurrent operations while supporting multiple
    scheduling strategies and execution environments.
    """

    async def run(
        self,
        accumulator_class: type[BenchmarkAccumulatorT],
        benchmark_class: type[BenchmarkT],
        requests: DatasetIterT[RequestT],
        backend: BackendInterface[RequestT, ResponseT],
        profile: Profile,
        environment: Environment,
        warmup: TransientPhaseConfig,
        cooldown: TransientPhaseConfig,
        sample_size: int | None = None,
        prefer_response_metrics: bool = True,
        progress: (
            BenchmarkerProgress[BenchmarkAccumulatorT, BenchmarkT] | None
        ) = None,
    ) -> AsyncIterator[BenchmarkT]:
        """
        Execute benchmark runs across scheduling strategies in the profile.

        :param accumulator_class: Class for accumulating metrics during execution
        :param benchmark_class: Class for constructing final benchmark results
        :param requests: Request datasets to process across strategies
        :param backend: Backend interface for executing requests
        :param profile: Profile defining scheduling strategies and constraints
        :param environment: Environment for execution coordination
        :param warmup: Warmup phase configuration before benchmarking
        :param cooldown: Cooldown phase configuration after benchmarking
        :param sample_size: Maximum number of requests per status group
            (completed, errored, incomplete) to retain full data for.
            None keeps all, 0 strips all, N > 0 uses reservoir sampling.
        :param prefer_response_metrics: Whether to prefer response metrics over
            request metrics, defaults to True
        :param progress: Optional tracker for benchmark lifecycle events
        :yield: Compiled benchmark result for each strategy execution
        :raises Exception: If benchmark execution or compilation fails
        """
        with self.thread_lock:
            if progress:
                await progress.on_initialize(profile)

            run_id = str(uuid.uuid4())
            strategies_generator = profile.strategies_generator()
            strategy: SchedulingStrategy | None
            constraints: dict[str, Constraint] | None
            strategy, constraints = next(strategies_generator)

            while strategy is not None:
                if progress:
                    await progress.on_benchmark_start(strategy)

                config = BenchmarkConfig(
                    run_id=run_id,
                    run_index=len(profile.completed_strategies),
                    strategy=strategy,
                    constraints=(
                        {
                            key: InfoMixin.extract_from_obj(val)
                            for key, val in constraints.items()
                        }
                        if isinstance(constraints, dict)
                        else {"constraint": InfoMixin.extract_from_obj(constraints)}
                        if constraints
                        else {}
                    ),
                    sample_size=sample_size,
                    warmup=warmup,
                    cooldown=cooldown,
                    prefer_response_metrics=prefer_response_metrics,
                    profile=InfoMixin.extract_from_obj(profile),
                    requests=InfoMixin.extract_from_obj(requests),
                    backend=InfoMixin.extract_from_obj(backend),
                    environment=InfoMixin.extract_from_obj(environment),
                )
                accumulator = accumulator_class(config=config)
                scheduler_state = None
                scheduler: Scheduler[RequestT, ResponseT] = Scheduler()

                async for (
                    response,
                    request,
                    request_info,
                    scheduler_state,
                ) in scheduler.run(
                    requests=requests,
                    backend=backend,
                    strategy=strategy,
                    env=environment,
                    **constraints or {},
                ):
                    try:
                        accumulator.update_estimate(
                            response,
                            request,
                            request_info,
                            scheduler_state,
                        )
                        if progress:
                            await progress.on_benchmark_update(
                                accumulator, scheduler_state
                            )
                    except Exception as err:  # noqa: BLE001
                        logger.error(
                            "Error updating benchmark estimate/progress: {}", err
                        )

                benchmark = benchmark_class.compile(
                    accumulator=accumulator,
                    scheduler_state=scheduler_state,  # type: ignore[arg-type]
                )

                if progress:
                    await progress.on_benchmark_complete(benchmark)

                yield benchmark

                try:
                    strategy, constraints = strategies_generator.send(benchmark)
                except StopIteration:
                    strategy = None
                    constraints = None

            if progress:
                await progress.on_finalize()

run(accumulator_class, benchmark_class, requests, backend, profile, environment, warmup, cooldown, sample_size=None, prefer_response_metrics=True, progress=None) async

Execute benchmark runs across scheduling strategies in the profile.

:yield: Compiled benchmark result for each strategy execution

Parameters:

Name Type Description Default
accumulator_class type[BenchmarkAccumulatorT]

Class for accumulating metrics during execution

required
benchmark_class type[BenchmarkT]

Class for constructing final benchmark results

required
requests DatasetIterT[RequestT]

Request datasets to process across strategies

required
backend BackendInterface[RequestT, ResponseT]

Backend interface for executing requests

required
profile Profile

Profile defining scheduling strategies and constraints

required
environment Environment

Environment for execution coordination

required
warmup TransientPhaseConfig

Warmup phase configuration before benchmarking

required
cooldown TransientPhaseConfig

Cooldown phase configuration after benchmarking

required
sample_size int | None

Maximum number of requests per status group (completed, errored, incomplete) to retain full data for. None keeps all, 0 strips all, N > 0 uses reservoir sampling.

None
prefer_response_metrics bool

Whether to prefer response metrics over request metrics, defaults to True

True
progress BenchmarkerProgress[BenchmarkAccumulatorT, BenchmarkT] | None

Optional tracker for benchmark lifecycle events

None

Raises:

Type Description
Exception

If benchmark execution or compilation fails

Source code in src/guidellm/benchmark/benchmarker.py
async def run(
    self,
    accumulator_class: type[BenchmarkAccumulatorT],
    benchmark_class: type[BenchmarkT],
    requests: DatasetIterT[RequestT],
    backend: BackendInterface[RequestT, ResponseT],
    profile: Profile,
    environment: Environment,
    warmup: TransientPhaseConfig,
    cooldown: TransientPhaseConfig,
    sample_size: int | None = None,
    prefer_response_metrics: bool = True,
    progress: (
        BenchmarkerProgress[BenchmarkAccumulatorT, BenchmarkT] | None
    ) = None,
) -> AsyncIterator[BenchmarkT]:
    """
    Execute benchmark runs across scheduling strategies in the profile.

    :param accumulator_class: Class for accumulating metrics during execution
    :param benchmark_class: Class for constructing final benchmark results
    :param requests: Request datasets to process across strategies
    :param backend: Backend interface for executing requests
    :param profile: Profile defining scheduling strategies and constraints
    :param environment: Environment for execution coordination
    :param warmup: Warmup phase configuration before benchmarking
    :param cooldown: Cooldown phase configuration after benchmarking
    :param sample_size: Maximum number of requests per status group
        (completed, errored, incomplete) to retain full data for.
        None keeps all, 0 strips all, N > 0 uses reservoir sampling.
    :param prefer_response_metrics: Whether to prefer response metrics over
        request metrics, defaults to True
    :param progress: Optional tracker for benchmark lifecycle events
    :yield: Compiled benchmark result for each strategy execution
    :raises Exception: If benchmark execution or compilation fails
    """
    with self.thread_lock:
        if progress:
            await progress.on_initialize(profile)

        run_id = str(uuid.uuid4())
        strategies_generator = profile.strategies_generator()
        strategy: SchedulingStrategy | None
        constraints: dict[str, Constraint] | None
        strategy, constraints = next(strategies_generator)

        while strategy is not None:
            if progress:
                await progress.on_benchmark_start(strategy)

            config = BenchmarkConfig(
                run_id=run_id,
                run_index=len(profile.completed_strategies),
                strategy=strategy,
                constraints=(
                    {
                        key: InfoMixin.extract_from_obj(val)
                        for key, val in constraints.items()
                    }
                    if isinstance(constraints, dict)
                    else {"constraint": InfoMixin.extract_from_obj(constraints)}
                    if constraints
                    else {}
                ),
                sample_size=sample_size,
                warmup=warmup,
                cooldown=cooldown,
                prefer_response_metrics=prefer_response_metrics,
                profile=InfoMixin.extract_from_obj(profile),
                requests=InfoMixin.extract_from_obj(requests),
                backend=InfoMixin.extract_from_obj(backend),
                environment=InfoMixin.extract_from_obj(environment),
            )
            accumulator = accumulator_class(config=config)
            scheduler_state = None
            scheduler: Scheduler[RequestT, ResponseT] = Scheduler()

            async for (
                response,
                request,
                request_info,
                scheduler_state,
            ) in scheduler.run(
                requests=requests,
                backend=backend,
                strategy=strategy,
                env=environment,
                **constraints or {},
            ):
                try:
                    accumulator.update_estimate(
                        response,
                        request,
                        request_info,
                        scheduler_state,
                    )
                    if progress:
                        await progress.on_benchmark_update(
                            accumulator, scheduler_state
                        )
                except Exception as err:  # noqa: BLE001
                    logger.error(
                        "Error updating benchmark estimate/progress: {}", err
                    )

            benchmark = benchmark_class.compile(
                accumulator=accumulator,
                scheduler_state=scheduler_state,  # type: ignore[arg-type]
            )

            if progress:
                await progress.on_benchmark_complete(benchmark)

            yield benchmark

            try:
                strategy, constraints = strategies_generator.send(benchmark)
            except StopIteration:
                strategy = None
                constraints = None

        if progress:
            await progress.on_finalize()

BenchmarkerProgress

Bases: Generic[BenchmarkAccumulatorT, BenchmarkT], ABC

Abstract interface for tracking and displaying benchmark execution progress.

Provides lifecycle hooks for monitoring benchmark stages including initialization, execution start, progress updates, completion, and finalization. Implementations handle display updates, progress tracking, and resource management for benchmark monitoring.

Source code in src/guidellm/benchmark/progress.py
class BenchmarkerProgress(Generic[BenchmarkAccumulatorT, BenchmarkT], ABC):
    """
    Abstract interface for tracking and displaying benchmark execution progress.

    Provides lifecycle hooks for monitoring benchmark stages including initialization,
    execution start, progress updates, completion, and finalization. Implementations
    handle display updates, progress tracking, and resource management for benchmark
    monitoring.
    """

    def __init__(self):
        """Initialize progress tracker with default state."""
        self.profile: Profile | None = None
        self.current_strategy: SchedulingStrategy | None = None

    @abstractmethod
    async def on_initialize(self, profile: Profile):
        """
        Initialize progress tracking for the given benchmark profile.

        :param profile: Benchmark profile configuration defining execution parameters
        """

    @abstractmethod
    async def on_benchmark_start(self, strategy: SchedulingStrategy):
        """
        Handle benchmark strategy execution start event.

        :param strategy: Scheduling strategy configuration being executed
        """

    @abstractmethod
    async def on_benchmark_update(
        self, accumulator: BenchmarkAccumulatorT, scheduler_state: SchedulerState
    ):
        """
        Handle benchmark execution progress update with current metrics.

        :param accumulator: Current accumulated benchmark metrics and statistics
        :param scheduler_state: Current scheduler execution state and counters
        """

    @abstractmethod
    async def on_benchmark_complete(self, benchmark: BenchmarkT):
        """
        Handle benchmark strategy execution completion event.

        :param benchmark: Completed benchmark results with final metrics
        """

    @abstractmethod
    async def on_finalize(self):
        """Finalize progress tracking and release associated resources."""

__init__()

Initialize progress tracker with default state.

Source code in src/guidellm/benchmark/progress.py
def __init__(self):
    """Initialize progress tracker with default state."""
    self.profile: Profile | None = None
    self.current_strategy: SchedulingStrategy | None = None

on_benchmark_complete(benchmark) abstractmethod async

Handle benchmark strategy execution completion event.

Parameters:

Name Type Description Default
benchmark BenchmarkT

Completed benchmark results with final metrics

required
Source code in src/guidellm/benchmark/progress.py
@abstractmethod
async def on_benchmark_complete(self, benchmark: BenchmarkT):
    """
    Handle benchmark strategy execution completion event.

    :param benchmark: Completed benchmark results with final metrics
    """

on_benchmark_start(strategy) abstractmethod async

Handle benchmark strategy execution start event.

Parameters:

Name Type Description Default
strategy SchedulingStrategy

Scheduling strategy configuration being executed

required
Source code in src/guidellm/benchmark/progress.py
@abstractmethod
async def on_benchmark_start(self, strategy: SchedulingStrategy):
    """
    Handle benchmark strategy execution start event.

    :param strategy: Scheduling strategy configuration being executed
    """

on_benchmark_update(accumulator, scheduler_state) abstractmethod async

Handle benchmark execution progress update with current metrics.

Parameters:

Name Type Description Default
accumulator BenchmarkAccumulatorT

Current accumulated benchmark metrics and statistics

required
scheduler_state SchedulerState

Current scheduler execution state and counters

required
Source code in src/guidellm/benchmark/progress.py
@abstractmethod
async def on_benchmark_update(
    self, accumulator: BenchmarkAccumulatorT, scheduler_state: SchedulerState
):
    """
    Handle benchmark execution progress update with current metrics.

    :param accumulator: Current accumulated benchmark metrics and statistics
    :param scheduler_state: Current scheduler execution state and counters
    """

on_finalize() abstractmethod async

Finalize progress tracking and release associated resources.

Source code in src/guidellm/benchmark/progress.py
@abstractmethod
async def on_finalize(self):
    """Finalize progress tracking and release associated resources."""

on_initialize(profile) abstractmethod async

Initialize progress tracking for the given benchmark profile.

Parameters:

Name Type Description Default
profile Profile

Benchmark profile configuration defining execution parameters

required
Source code in src/guidellm/benchmark/progress.py
@abstractmethod
async def on_initialize(self, profile: Profile):
    """
    Initialize progress tracking for the given benchmark profile.

    :param profile: Benchmark profile configuration defining execution parameters
    """

ConcurrentProfile

Bases: Profile

Execute strategies with fixed concurrency levels for performance testing.

Executes requests with a fixed number of concurrent streams, useful for testing system performance under specific concurrency levels.

Source code in src/guidellm/benchmark/profiles/concurrent.py
@ProfileFactory.register("concurrent")
class ConcurrentProfile(Profile):
    """
    Execute strategies with fixed concurrency levels for performance testing.

    Executes requests with a fixed number of concurrent streams, useful for
    testing system performance under specific concurrency levels.
    """

    args: ConcurrentProfileArgs

    def __init__(
        self,
        args: ConcurrentProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
        **kwargs: Any,
    ):
        super().__init__(args, random_seed, constraints, **kwargs)
        self.args = args

    @property
    def strategy_types(self) -> list[str]:
        """
        :return: Concurrent strategy types for each configured stream count
        """
        return [self.kind] * len(self.args.streams)

    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> ConcurrentStrategy | None:
        """
        Generate concurrent strategy for next stream count.

        If a previous stream count was terminated by a constraint with
        stopping_scope='all', remaining stream counts are skipped.

        :param prev_strategy: Previously completed strategy
        :param prev_benchmark: Benchmark results from previous execution
        :return: ConcurrentStrategy with next stream count, or None if complete
            or escalation halted
        """
        _ = prev_strategy

        if len(self.completed_strategies) >= len(self.args.streams):
            return None

        if prev_benchmark is not None and self._should_stop_escalating(prev_benchmark):
            return None

        return ConcurrentStrategy(
            streams=self.args.streams[len(self.completed_strategies)],
            rampup_duration=self.args.rampup_duration,
        )

strategy_types property

Returns:

Type Description
list[str]

Concurrent strategy types for each configured stream count

next_strategy(prev_strategy, prev_benchmark)

Generate concurrent strategy for next stream count.

If a previous stream count was terminated by a constraint with stopping_scope='all', remaining stream counts are skipped.

Parameters:

Name Type Description Default
prev_strategy SchedulingStrategy | None

Previously completed strategy

required
prev_benchmark Benchmark | None

Benchmark results from previous execution

required

Returns:

Type Description
ConcurrentStrategy | None

ConcurrentStrategy with next stream count, or None if complete or escalation halted

Source code in src/guidellm/benchmark/profiles/concurrent.py
def next_strategy(
    self,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> ConcurrentStrategy | None:
    """
    Generate concurrent strategy for next stream count.

    If a previous stream count was terminated by a constraint with
    stopping_scope='all', remaining stream counts are skipped.

    :param prev_strategy: Previously completed strategy
    :param prev_benchmark: Benchmark results from previous execution
    :return: ConcurrentStrategy with next stream count, or None if complete
        or escalation halted
    """
    _ = prev_strategy

    if len(self.completed_strategies) >= len(self.args.streams):
        return None

    if prev_benchmark is not None and self._should_stop_escalating(prev_benchmark):
        return None

    return ConcurrentStrategy(
        streams=self.args.streams[len(self.completed_strategies)],
        rampup_duration=self.args.rampup_duration,
    )

GenerativeAudioMetricsSummary

Bases: StandardBaseDict

Audio-specific metric summaries for generative benchmarks.

Tracks token, sample count, duration, and byte-level metrics across input, output, and total usage for audio generation workloads.

Source code in src/guidellm/benchmark/schemas/metrics.py
class GenerativeAudioMetricsSummary(StandardBaseDict):
    """
    Audio-specific metric summaries for generative benchmarks.

    Tracks token, sample count, duration, and byte-level metrics across input,
    output, and total usage for audio generation workloads.
    """

    tokens: GenerativeMetricsSummary | None = Field(
        description="Audio token count metrics and distributions"
    )
    samples: GenerativeMetricsSummary | None = Field(
        description="Sample count metrics and distributions"
    )
    seconds: GenerativeMetricsSummary | None = Field(
        description="Duration metrics in seconds and distributions"
    )
    bytes: GenerativeMetricsSummary | None = Field(
        description="Byte size metrics and distributions"
    )

    @classmethod
    def compile(
        cls,
        successful: list[GenerativeRequestStats],
        incomplete: list[GenerativeRequestStats],
        errored: list[GenerativeRequestStats],
    ) -> GenerativeAudioMetricsSummary:
        """
        Compile audio metrics summary from request statistics.

        :param successful: Successfully completed request statistics
        :param incomplete: Incomplete/cancelled request statistics
        :param errored: Failed request statistics
        :return: Compiled audio metrics summary
        """
        return GenerativeAudioMetricsSummary(
            tokens=GenerativeMetricsSummary.compile(
                property_name="audio_tokens",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            samples=GenerativeMetricsSummary.compile(
                property_name="audio_samples",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            seconds=GenerativeMetricsSummary.compile(
                property_name="audio_seconds",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            bytes=GenerativeMetricsSummary.compile(
                property_name="audio_bytes",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
        )

compile(successful, incomplete, errored) classmethod

Compile audio metrics summary from request statistics.

Parameters:

Name Type Description Default
successful list[GenerativeRequestStats]

Successfully completed request statistics

required
incomplete list[GenerativeRequestStats]

Incomplete/cancelled request statistics

required
errored list[GenerativeRequestStats]

Failed request statistics

required

Returns:

Type Description
GenerativeAudioMetricsSummary

Compiled audio metrics summary

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile(
    cls,
    successful: list[GenerativeRequestStats],
    incomplete: list[GenerativeRequestStats],
    errored: list[GenerativeRequestStats],
) -> GenerativeAudioMetricsSummary:
    """
    Compile audio metrics summary from request statistics.

    :param successful: Successfully completed request statistics
    :param incomplete: Incomplete/cancelled request statistics
    :param errored: Failed request statistics
    :return: Compiled audio metrics summary
    """
    return GenerativeAudioMetricsSummary(
        tokens=GenerativeMetricsSummary.compile(
            property_name="audio_tokens",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        samples=GenerativeMetricsSummary.compile(
            property_name="audio_samples",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        seconds=GenerativeMetricsSummary.compile(
            property_name="audio_seconds",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        bytes=GenerativeMetricsSummary.compile(
            property_name="audio_bytes",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
    )

GenerativeBenchmark

Bases: Benchmark[GenerativeBenchmarkAccumulator]

Complete generative AI benchmark results with specialized metrics.

Encapsulates comprehensive performance data from scheduler-driven generative workload executions including request-level statistics, token/latency distributions, throughput analysis, and concurrency patterns. Provides computed fields for temporal analysis and status-grouped request details for detailed post-execution reporting.

Source code in src/guidellm/benchmark/schemas/benchmark.py
class GenerativeBenchmark(Benchmark[GenerativeBenchmarkAccumulator]):
    """Complete generative AI benchmark results with specialized metrics.

    Encapsulates comprehensive performance data from scheduler-driven generative
    workload executions including request-level statistics, token/latency distributions,
    throughput analysis, and concurrency patterns. Provides computed fields for temporal
    analysis and status-grouped request details for detailed post-execution reporting.
    """

    type_: Literal["generative_benchmark"] = "generative_benchmark"  # type: ignore[assignment]

    config: BenchmarkConfig = Field(
        description="Configuration parameters for this benchmark execution",
    )
    scheduler_state: SchedulerState = Field(
        description="Final state of the scheduler after benchmark completion",
    )
    scheduler_metrics: SchedulerMetrics = Field(
        description="Scheduler timing and performance statistics",
    )
    metrics: GenerativeMetrics = Field(
        description="Performance metrics and statistical distributions",
    )
    requests: StatusBreakdown[
        list[GenerativeRequestStats],
        list[GenerativeRequestStats],
        list[GenerativeRequestStats],
        None,
    ] = Field(
        description=(
            "Request details grouped by status: successful, incomplete, errored"
        ),
    )

    @computed_field  # type: ignore[prop-decorator]
    @property
    def start_time(self) -> float:
        """
        :return: Benchmark start time in seconds since epoch
        """
        return self.scheduler_metrics.measure_start_time

    @computed_field  # type: ignore[prop-decorator]
    @property
    def end_time(self) -> float:
        """
        :return: Benchmark end time in seconds since epoch
        """
        return self.scheduler_metrics.measure_end_time

    @computed_field  # type: ignore[prop-decorator]
    @property
    def duration(self) -> float:
        """
        :return: Total benchmark execution duration in seconds
        """
        return self.end_time - self.start_time

    @computed_field  # type: ignore[prop-decorator]
    @property
    def warmup_duration(self) -> float:
        """
        :return: Warmup phase duration in seconds
        """
        return (
            self.scheduler_metrics.measure_start_time
            - self.scheduler_metrics.request_start_time
        )

    @computed_field  # type: ignore[prop-decorator]
    @property
    def cooldown_duration(self) -> float:
        """
        :return: Cooldown phase duration in seconds
        """
        return (
            self.scheduler_metrics.request_end_time
            - self.scheduler_metrics.measure_end_time
        )

    @property
    def request_latency(self) -> StatusDistributionSummary:
        """
        :return: Statistical distribution of request latencies across all requests
        """
        return self.metrics.request_latency

    @property
    def request_throughput(self) -> StatusDistributionSummary:
        """
        :return: Statistical distribution of throughput measured in requests per second
        """
        return self.metrics.requests_per_second

    @property
    def request_concurrency(self) -> StatusDistributionSummary:
        """
        :return: Statistical distribution of concurrent requests throughout execution
        """
        return self.metrics.request_concurrency

    @classmethod
    def compile(
        cls,
        accumulator: GenerativeBenchmarkAccumulator,
        scheduler_state: SchedulerState,
    ) -> GenerativeBenchmark:
        """
        Compile final benchmark results from accumulated execution state.

        :param accumulator: Accumulated benchmark state with request statistics
        :param scheduler_state: Final scheduler state after execution completion
        :return: Compiled generative benchmark instance with complete metrics
        """
        return GenerativeBenchmark(
            config=accumulator.config,
            scheduler_state=scheduler_state,
            scheduler_metrics=SchedulerMetrics.compile(accumulator, scheduler_state),
            metrics=GenerativeMetrics.compile(accumulator),
            requests=StatusBreakdown(
                successful=accumulator.completed.get_sampled(),
                incomplete=accumulator.incomplete.get_sampled(),
                errored=accumulator.errored.get_sampled(),
                total=None,
            ),
        )

cooldown_duration property

Returns:

Type Description
float

Cooldown phase duration in seconds

duration property

Returns:

Type Description
float

Total benchmark execution duration in seconds

end_time property

Returns:

Type Description
float

Benchmark end time in seconds since epoch

request_concurrency property

Returns:

Type Description
StatusDistributionSummary

Statistical distribution of concurrent requests throughout execution

request_latency property

Returns:

Type Description
StatusDistributionSummary

Statistical distribution of request latencies across all requests

request_throughput property

Returns:

Type Description
StatusDistributionSummary

Statistical distribution of throughput measured in requests per second

start_time property

Returns:

Type Description
float

Benchmark start time in seconds since epoch

warmup_duration property

Returns:

Type Description
float

Warmup phase duration in seconds

compile(accumulator, scheduler_state) classmethod

Compile final benchmark results from accumulated execution state.

Parameters:

Name Type Description Default
accumulator GenerativeBenchmarkAccumulator

Accumulated benchmark state with request statistics

required
scheduler_state SchedulerState

Final scheduler state after execution completion

required

Returns:

Type Description
GenerativeBenchmark

Compiled generative benchmark instance with complete metrics

Source code in src/guidellm/benchmark/schemas/benchmark.py
@classmethod
def compile(
    cls,
    accumulator: GenerativeBenchmarkAccumulator,
    scheduler_state: SchedulerState,
) -> GenerativeBenchmark:
    """
    Compile final benchmark results from accumulated execution state.

    :param accumulator: Accumulated benchmark state with request statistics
    :param scheduler_state: Final scheduler state after execution completion
    :return: Compiled generative benchmark instance with complete metrics
    """
    return GenerativeBenchmark(
        config=accumulator.config,
        scheduler_state=scheduler_state,
        scheduler_metrics=SchedulerMetrics.compile(accumulator, scheduler_state),
        metrics=GenerativeMetrics.compile(accumulator),
        requests=StatusBreakdown(
            successful=accumulator.completed.get_sampled(),
            incomplete=accumulator.incomplete.get_sampled(),
            errored=accumulator.errored.get_sampled(),
            total=None,
        ),
    )

GenerativeBenchmarkAccumulator

Bases: BenchmarkAccumulator[GenerationRequest, GenerationResponse]

Primary accumulator for generative benchmark execution metrics and statistics.

Orchestrates real-time metric collection across timing, scheduler, concurrency, and generative performance dimensions. Maintains separate accumulators for completed, errored, and incomplete requests while tracking overall metrics. Integrates with scheduler state to monitor warmup/cooldown phases and compute time-weighted statistics for throughput and latency analysis.

Source code in src/guidellm/benchmark/schemas/accumulator.py
class GenerativeBenchmarkAccumulator(
    BenchmarkAccumulator[GenerationRequest, GenerationResponse]
):
    """
    Primary accumulator for generative benchmark execution metrics and statistics.

    Orchestrates real-time metric collection across timing, scheduler, concurrency, and
    generative performance dimensions. Maintains separate accumulators for completed,
    errored, and incomplete requests while tracking overall metrics. Integrates with
    scheduler state to monitor warmup/cooldown phases and compute time-weighted
    statistics for throughput and latency analysis.
    """

    timings: GenerativeBenchmarkTimings = Field(
        default_factory=GenerativeBenchmarkTimings,
        description="Timing phases and transitions during benchmark execution",
    )
    completed: GenerativeRequestsAccumulator = Field(
        default_factory=GenerativeRequestsAccumulator,
        description="Accumulator for completed requests",
    )
    errored: GenerativeRequestsAccumulator = Field(
        default_factory=GenerativeRequestsAccumulator,
        description="Accumulator for errored requests",
    )
    incomplete: GenerativeRequestsAccumulator = Field(
        default_factory=GenerativeRequestsAccumulator,
        description="Accumulator for incomplete requests",
    )
    scheduler_metrics: SchedulerMetricsAccumulator = Field(
        default_factory=SchedulerMetricsAccumulator,
        description="Running metrics for scheduler state",
    )
    concurrency_metric: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated request concurrency statistics",
    )
    total_metrics: GenerativeMetricsAccumulator = Field(
        default_factory=GenerativeMetricsAccumulator,
        description="Running metrics for all requests",
    )
    completed_metrics: GenerativeMetricsAccumulator = Field(
        default_factory=GenerativeMetricsAccumulator,
        description="Running metrics for completed requests",
    )
    errored_metrics: GenerativeMetricsAccumulator = Field(
        default_factory=GenerativeMetricsAccumulator,
        description="Running metrics for errored requests",
    )
    incomplete_metrics: GenerativeMetricsAccumulator = Field(
        default_factory=GenerativeMetricsAccumulator,
        description="Running metrics for incomplete requests",
    )

    def model_post_init(self, __context):
        """
        Initialize child accumulators with config values after model construction.

        Propagates sample_size from config to child request accumulators to ensure
        consistent sampling behavior across completed, errored, and incomplete request
        collections. This ensures the --metrics-sample-size option functions correctly.
        """
        super().model_post_init(__context)

        # Propagate sample_size from config to child accumulators
        self.completed.sample_size = self.config.sample_size
        self.errored.sample_size = self.config.sample_size
        self.incomplete.sample_size = self.config.sample_size

    def update_estimate(
        self,
        response: GenerationResponse | None,
        request: GenerationRequest,
        info: RequestInfo,
        scheduler_state: SchedulerState,
    ):
        """
        Update all benchmark metrics with a completed request.

        Processes request completion by updating timing phases, concurrency metrics,
        scheduler statistics, and generative performance metrics. Routes request to
        appropriate status-specific accumulator (completed/errored/incomplete) and
        updates aggregate totals. Cancelled requests that never started are ignored.

        :param response: Generation response with output and metrics, or None
        :param request: Original generation request with input data
        :param info: Request execution information and timing
        :param scheduler_state: Current scheduler state for phase tracking
        """
        self.timings.update_estimate(info, scheduler_state, self.config)
        duration = self.timings.duration
        elapsed_time_last_update = self.timings.elapsed_time_last_update
        self.concurrency_metric.update_estimate(
            value=scheduler_state.processing_requests,
            duration=duration,
            elapsed=elapsed_time_last_update,
        )

        requests_accumulator: GenerativeRequestsAccumulator
        metrics_accumulator: GenerativeMetricsAccumulator

        if info.status == "completed":
            requests_accumulator = self.completed
            metrics_accumulator = self.completed_metrics
        elif info.status == "errored":
            requests_accumulator = self.errored
            metrics_accumulator = self.errored_metrics
        elif info.status == "cancelled" and info.timings.resolve_start is not None:
            requests_accumulator = self.incomplete
            metrics_accumulator = self.incomplete_metrics
        else:
            # Not a terminal status or cancelled before starting
            # Do not include in requests or metrics
            return

        stats = requests_accumulator.update_estimate(
            response, request, info, self.config.prefer_response_metrics
        )
        metrics_accumulator.update_estimate(stats, duration)
        self.total_metrics.update_estimate(stats, duration)
        self.scheduler_metrics.update_estimate(scheduler_state, stats)

model_post_init(__context)

Initialize child accumulators with config values after model construction.

Propagates sample_size from config to child request accumulators to ensure consistent sampling behavior across completed, errored, and incomplete request collections. This ensures the --metrics-sample-size option functions correctly.

Source code in src/guidellm/benchmark/schemas/accumulator.py
def model_post_init(self, __context):
    """
    Initialize child accumulators with config values after model construction.

    Propagates sample_size from config to child request accumulators to ensure
    consistent sampling behavior across completed, errored, and incomplete request
    collections. This ensures the --metrics-sample-size option functions correctly.
    """
    super().model_post_init(__context)

    # Propagate sample_size from config to child accumulators
    self.completed.sample_size = self.config.sample_size
    self.errored.sample_size = self.config.sample_size
    self.incomplete.sample_size = self.config.sample_size

update_estimate(response, request, info, scheduler_state)

Update all benchmark metrics with a completed request.

Processes request completion by updating timing phases, concurrency metrics, scheduler statistics, and generative performance metrics. Routes request to appropriate status-specific accumulator (completed/errored/incomplete) and updates aggregate totals. Cancelled requests that never started are ignored.

Parameters:

Name Type Description Default
response GenerationResponse | None

Generation response with output and metrics, or None

required
request GenerationRequest

Original generation request with input data

required
info RequestInfo

Request execution information and timing

required
scheduler_state SchedulerState

Current scheduler state for phase tracking

required
Source code in src/guidellm/benchmark/schemas/accumulator.py
def update_estimate(
    self,
    response: GenerationResponse | None,
    request: GenerationRequest,
    info: RequestInfo,
    scheduler_state: SchedulerState,
):
    """
    Update all benchmark metrics with a completed request.

    Processes request completion by updating timing phases, concurrency metrics,
    scheduler statistics, and generative performance metrics. Routes request to
    appropriate status-specific accumulator (completed/errored/incomplete) and
    updates aggregate totals. Cancelled requests that never started are ignored.

    :param response: Generation response with output and metrics, or None
    :param request: Original generation request with input data
    :param info: Request execution information and timing
    :param scheduler_state: Current scheduler state for phase tracking
    """
    self.timings.update_estimate(info, scheduler_state, self.config)
    duration = self.timings.duration
    elapsed_time_last_update = self.timings.elapsed_time_last_update
    self.concurrency_metric.update_estimate(
        value=scheduler_state.processing_requests,
        duration=duration,
        elapsed=elapsed_time_last_update,
    )

    requests_accumulator: GenerativeRequestsAccumulator
    metrics_accumulator: GenerativeMetricsAccumulator

    if info.status == "completed":
        requests_accumulator = self.completed
        metrics_accumulator = self.completed_metrics
    elif info.status == "errored":
        requests_accumulator = self.errored
        metrics_accumulator = self.errored_metrics
    elif info.status == "cancelled" and info.timings.resolve_start is not None:
        requests_accumulator = self.incomplete
        metrics_accumulator = self.incomplete_metrics
    else:
        # Not a terminal status or cancelled before starting
        # Do not include in requests or metrics
        return

    stats = requests_accumulator.update_estimate(
        response, request, info, self.config.prefer_response_metrics
    )
    metrics_accumulator.update_estimate(stats, duration)
    self.total_metrics.update_estimate(stats, duration)
    self.scheduler_metrics.update_estimate(scheduler_state, stats)

GenerativeBenchmarkMetadata

Bases: StandardBaseModel

Versioning and environment metadata for generative benchmark reports.

Source code in src/guidellm/benchmark/schemas/report.py
class GenerativeBenchmarkMetadata(StandardBaseModel):
    """
    Versioning and environment metadata for generative benchmark reports.
    """

    # Make sure to update version when making breaking changes to report schema
    version: Literal[2] = Field(
        description=(
            "Version of the benchmark report schema, increments "
            "whenever there is a breaking change to the output format"
        ),
        default=2,
    )
    guidellm_version: str = Field(
        description="Version of the guidellm package used for the benchmark",
        default_factory=lambda: version("guidellm"),
    )
    python_version: str = Field(
        description="Version of Python interpreter used during the benchmark",
        default_factory=platform.python_version,
    )
    platform: str = Field(
        description="Operating system platform where the benchmark was executed",
        default_factory=platform.platform,
    )

GenerativeBenchmarkTimings

Bases: StandardBaseModel

Tracks timing phases and transitions during benchmark execution.

Monitors timestamps throughout benchmark execution including request submission, measurement period boundaries (warmup/active/cooldown), and completion events. Provides duration calculations and phase status determination based on configured warmup and cooldown periods.

Source code in src/guidellm/benchmark/schemas/accumulator.py
class GenerativeBenchmarkTimings(StandardBaseModel):
    """
    Tracks timing phases and transitions during benchmark execution.

    Monitors timestamps throughout benchmark execution including request submission,
    measurement period boundaries (warmup/active/cooldown), and completion events.
    Provides duration calculations and phase status determination based on configured
    warmup and cooldown periods.
    """

    request_start: float | None = Field(
        description="Timestamp when the first request was sent", default=None
    )
    measure_start: float | None = Field(
        description="Timestamp when measurement period started", default=None
    )
    measure_end: float | None = Field(
        description="Timestamp when measurement period ended", default=None
    )
    request_end: float | None = Field(
        description="Timestamp when the last request was completed", default=None
    )
    current_update: float | None = Field(
        description="Most recent timestamp observed during execution", default=None
    )
    current_request: float | None = Field(
        description="Most recent request completion timestamp observed", default=None
    )
    last_update: float | None = Field(
        description="Previous timestamp observed before the current one", default=None
    )
    last_request: float | None = Field(
        description="Previous request completion timestamp before the current one",
        default=None,
    )

    @property
    def status(self) -> Literal["pending", "warmup", "active", "cooldown"]:
        """
        :return: Current execution phase based on timing thresholds
        """
        if self.request_start is None or self.current_update is None:
            return "pending"

        if self.measure_start is None or self.current_update <= self.measure_start:
            return "warmup"

        if self.measure_end is not None and self.current_update >= self.measure_end:
            return "cooldown"

        return "active"

    @property
    def duration(self) -> float:
        """
        :return: Elapsed time since measurement or request start in seconds
        """
        if self.request_start is None or self.current_update is None:
            return 0.0

        return self.current_update - self.request_start

    @property
    def elapsed_time_last_update(self) -> float:
        """
        :return: Time elapsed between the last two update timestamps in seconds
        """
        if self.current_update is None or self.last_update is None:
            return 0.0

        return self.current_update - self.last_update

    @property
    def elapsed_time_last_request(self) -> float:
        """
        :return: Time elapsed between the last two request completions in seconds
        """
        if self.current_request is None or self.last_request is None:
            return 0.0

        return self.current_request - self.last_request

    @property
    def finalized_request_start(self) -> float:
        """
        :return: Finalized timestamp from the current state for when requests started
        """
        return self.request_start or -1.0

    @property
    def finalized_measure_start(self) -> float:
        """
        :return: Finalized timestamp from the current state for when measurement started
        """
        return self.measure_start or self.finalized_request_start

    @property
    def finalized_measure_end(self) -> float:
        """
        :return: Finalized timestamp from the current state for when measurement ended
        """
        return self.measure_end or self.finalized_request_end

    @property
    def finalized_request_end(self) -> float:
        """
        :return: Finalized timestamp from the current state for when requests ended
        """
        return self.request_end or self.current_request or -1.0

    def update_estimate(
        self,
        info: RequestInfo,
        scheduler_state: SchedulerState,
        config: BenchmarkConfig,
    ):
        """
        Update timing estimates based on request info and scheduler state.

        Advances timing markers through benchmark phases (warmup to active to cooldown)
        based on configured thresholds. Updates current/last timestamps for updates and
        request completions, determining measurement period boundaries.

        :param info: Request information containing timing data
        :param scheduler_state: Current scheduler state with progress metrics
        :param config: Benchmark configuration with warmup/cooldown settings
        """
        # First update non terminal timestamps
        self.request_start = scheduler_state.start_requests_time
        self.last_update = self.current_update
        if (current_time := info.timings.last_reported) is not None:
            self.current_update = (
                current_time
                if self.current_update is None
                else max(self.current_update, current_time)
            )

        # Next update measurement period timestamps, if available and possible
        warmup_active, measure_start = config.warmup.compute_transition_time(
            info=info, state=scheduler_state, period="start"
        )
        if not warmup_active:
            # No warmup, set measure_start to first request start
            self.measure_start = self.request_start
        elif measure_start is not None:
            self.measure_start = measure_start
        cooldown_active, measure_end = config.cooldown.compute_transition_time(
            info=info, state=scheduler_state, period="end"
        )
        if cooldown_active and measure_end is not None:
            self.measure_end = measure_end

        # Update last request terminal timestamps, if request is terminal
        if info.status in {"completed", "errored", "cancelled"}:
            self.last_request = self.current_request
            if info.completed_at is not None and (
                self.current_request is None or info.completed_at > self.current_request
            ):
                self.current_request = info.completed_at

        # Finally, update request stop timestamps, if at that stage and available
        if scheduler_state.end_processing_time is not None and self.request_end is None:
            self.request_end = (
                scheduler_state.progress.stop_time
                or self.current_request
                or scheduler_state.end_processing_time
            )
            if self.measure_end is None:
                # No cooldown triggered, set measure_end to request_end
                self.measure_end = self.request_end

duration property

Returns:

Type Description
float

Elapsed time since measurement or request start in seconds

elapsed_time_last_request property

Returns:

Type Description
float

Time elapsed between the last two request completions in seconds

elapsed_time_last_update property

Returns:

Type Description
float

Time elapsed between the last two update timestamps in seconds

finalized_measure_end property

Returns:

Type Description
float

Finalized timestamp from the current state for when measurement ended

finalized_measure_start property

Returns:

Type Description
float

Finalized timestamp from the current state for when measurement started

finalized_request_end property

Returns:

Type Description
float

Finalized timestamp from the current state for when requests ended

finalized_request_start property

Returns:

Type Description
float

Finalized timestamp from the current state for when requests started

status property

Returns:

Type Description
Literal['pending', 'warmup', 'active', 'cooldown']

Current execution phase based on timing thresholds

update_estimate(info, scheduler_state, config)

Update timing estimates based on request info and scheduler state.

Advances timing markers through benchmark phases (warmup to active to cooldown) based on configured thresholds. Updates current/last timestamps for updates and request completions, determining measurement period boundaries.

Parameters:

Name Type Description Default
info RequestInfo

Request information containing timing data

required
scheduler_state SchedulerState

Current scheduler state with progress metrics

required
config BenchmarkConfig

Benchmark configuration with warmup/cooldown settings

required
Source code in src/guidellm/benchmark/schemas/accumulator.py
def update_estimate(
    self,
    info: RequestInfo,
    scheduler_state: SchedulerState,
    config: BenchmarkConfig,
):
    """
    Update timing estimates based on request info and scheduler state.

    Advances timing markers through benchmark phases (warmup to active to cooldown)
    based on configured thresholds. Updates current/last timestamps for updates and
    request completions, determining measurement period boundaries.

    :param info: Request information containing timing data
    :param scheduler_state: Current scheduler state with progress metrics
    :param config: Benchmark configuration with warmup/cooldown settings
    """
    # First update non terminal timestamps
    self.request_start = scheduler_state.start_requests_time
    self.last_update = self.current_update
    if (current_time := info.timings.last_reported) is not None:
        self.current_update = (
            current_time
            if self.current_update is None
            else max(self.current_update, current_time)
        )

    # Next update measurement period timestamps, if available and possible
    warmup_active, measure_start = config.warmup.compute_transition_time(
        info=info, state=scheduler_state, period="start"
    )
    if not warmup_active:
        # No warmup, set measure_start to first request start
        self.measure_start = self.request_start
    elif measure_start is not None:
        self.measure_start = measure_start
    cooldown_active, measure_end = config.cooldown.compute_transition_time(
        info=info, state=scheduler_state, period="end"
    )
    if cooldown_active and measure_end is not None:
        self.measure_end = measure_end

    # Update last request terminal timestamps, if request is terminal
    if info.status in {"completed", "errored", "cancelled"}:
        self.last_request = self.current_request
        if info.completed_at is not None and (
            self.current_request is None or info.completed_at > self.current_request
        ):
            self.current_request = info.completed_at

    # Finally, update request stop timestamps, if at that stage and available
    if scheduler_state.end_processing_time is not None and self.request_end is None:
        self.request_end = (
            scheduler_state.progress.stop_time
            or self.current_request
            or scheduler_state.end_processing_time
        )
        if self.measure_end is None:
            # No cooldown triggered, set measure_end to request_end
            self.measure_end = self.request_end

GenerativeBenchmarkerCSV

Bases: GenerativeBenchmarkerOutput

CSV output formatter for benchmark results.

Exports comprehensive benchmark data to CSV format with multi-row headers organizing metrics into categories including run information, timing, request counts, latency, throughput, modality-specific data, and scheduler state. Each benchmark run becomes a row with statistical distributions represented as mean, median, standard deviation, and percentiles.

Attributes:

Name Type Description
DEFAULT_FILE str

Default filename for CSV output

Source code in src/guidellm/benchmark/outputs/csv.py
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
@GenerativeBenchmarkerOutput.register("csv")
class GenerativeBenchmarkerCSV(GenerativeBenchmarkerOutput):
    """
    CSV output formatter for benchmark results.

    Exports comprehensive benchmark data to CSV format with multi-row headers
    organizing metrics into categories including run information, timing, request
    counts, latency, throughput, modality-specific data, and scheduler state. Each
    benchmark run becomes a row with statistical distributions represented as
    mean, median, standard deviation, and percentiles.

    :cvar DEFAULT_FILE: Default filename for CSV output
    """

    DEFAULT_FILE: ClassVar[str] = "benchmarks.csv"

    @classmethod
    def from_args(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerCSV:
        """
        Create a CSV output formatter from output arguments.

        :param args: Output configuration with path
        :return: Configured CSV output formatter
        """
        if not isinstance(args, CSVBenchmarkOutputArgs):
            raise ValueError(f"Expected CSVBenchmarkOutputArgs, got {type(args)}")

        return cls(output_path=args.path)

    output_path: Path = Field(
        default_factory=Path.cwd,
        description=(
            "Path where the CSV file will be saved, defaults to current directory"
        ),
    )

    async def finalize(self, report: GenerativeBenchmarksReport) -> Path:
        """
        Save the benchmark report as a CSV file.

        :param report: The completed benchmark report
        :return: Path to the saved CSV file
        """
        output_path = self.output_path
        if output_path.is_dir():
            output_path = output_path / GenerativeBenchmarkerCSV.DEFAULT_FILE
        output_path.parent.mkdir(parents=True, exist_ok=True)

        with output_path.open("w", newline="") as file:
            writer = csv.writer(file)

            all_headers: list[list[list[str]]] = []
            all_values: list[list[str | int | float]] = []

            for benchmark in report.benchmarks:
                benchmark_headers: list[list[str]] = []
                benchmark_values: list[str | int | float] = []

                self._add_run_info(benchmark, benchmark_headers, benchmark_values)
                self._add_benchmark_info(benchmark, benchmark_headers, benchmark_values)
                self._add_timing_info(benchmark, benchmark_headers, benchmark_values)
                self._add_request_counts(benchmark, benchmark_headers, benchmark_values)
                self._add_request_latency_metrics(
                    benchmark, benchmark_headers, benchmark_values
                )
                self._add_server_throughput_metrics(
                    benchmark, benchmark_headers, benchmark_values
                )
                for modality_name in ["text", "image", "video", "audio"]:
                    self._add_modality_metrics(
                        benchmark,
                        modality_name,  # type: ignore[arg-type]
                        benchmark_headers,
                        benchmark_values,
                    )
                self._add_scheduler_info(benchmark, benchmark_headers, benchmark_values)
                self._add_runtime_info(report, benchmark_headers, benchmark_values)

                all_headers.append(benchmark_headers)
                all_values.append(benchmark_values)

            headers, data_rows = self._align_columns(all_headers, all_values)

            self._write_multirow_header(writer, headers)
            for row in data_rows:
                writer.writerow(row)

        return output_path

    @staticmethod
    def _align_columns(
        all_headers: list[list[list[str]]],
        all_values: list[list[str | int | float]],
    ) -> tuple[list[list[str]], list[list[str | int | float]]]:
        """
        Align columns across multiple benchmarks that may have different column sets.

        Builds a unified header list from all benchmarks (preserving first-seen order)
        and pads each row with empty strings for columns it doesn't have.

        :param all_headers: Per-benchmark list of column header hierarchies
        :param all_values: Per-benchmark list of column values
        :return: Tuple of (unified headers, aligned data rows)
        """
        ordered_headers: dict[tuple[str, ...], None] = {}
        row_maps: list[dict[tuple[str, ...], str | int | float]] = []

        for benchmark_headers, benchmark_values in zip(
            all_headers, all_values, strict=True
        ):
            row_map: dict[tuple[str, ...], str | int | float] = {}
            for header_parts, value in zip(
                benchmark_headers, benchmark_values, strict=False
            ):
                header_key = tuple(header_parts)
                row_map[header_key] = value
                if header_key not in ordered_headers:
                    ordered_headers[header_key] = None
            row_maps.append(row_map)

        header_keys = list(ordered_headers.keys())
        headers = [list(k) for k in header_keys]
        data_rows: list[list[str | int | float]] = [
            [row_map.get(k, "") for k in header_keys] for row_map in row_maps
        ]
        return headers, data_rows

    def _write_multirow_header(self, writer: Any, headers: list[list[str]]) -> None:
        """
        Write multi-row header to CSV for hierarchical metric organization.

        :param writer: CSV writer instance
        :param headers: List of column header hierarchies as string lists
        """
        max_rows = max((len(col) for col in headers), default=0)
        for row_idx in range(max_rows):
            row = [col[row_idx] if row_idx < len(col) else "" for col in headers]
            writer.writerow(row)

    def _add_field(
        self,
        headers: list[list[str]],
        values: list[str | int | float],
        group: str,
        field_name: str,
        value: Any,
        units: str = "",
    ) -> None:
        """
        Add a single field to headers and values lists.

        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        :param group: Top-level category for the field
        :param field_name: Name of the field
        :param value: Value for the field
        :param units: Optional units for the field
        """
        headers.append([group, field_name, units])
        values.append(value)

    def _add_runtime_info(
        self,
        report: GenerativeBenchmarksReport,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add global metadata and environment information.

        :param report: Benchmark report to extract global info from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        self._add_field(
            headers,
            values,
            "Runtime Info",
            "Metadata",
            report.metadata.model_dump_json(),
        )
        self._add_field(
            headers,
            values,
            "Runtime Info",
            "Arguments",
            report.config.model_dump_json(),
        )

    def _add_run_info(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add overall run identification and configuration information.

        :param benchmark: Benchmark data to extract run info from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        self._add_field(headers, values, "Run Info", "Run ID", benchmark.config.run_id)
        self._add_field(
            headers, values, "Run Info", "Run Index", benchmark.config.run_index
        )
        self._add_field(
            headers,
            values,
            "Run Info",
            "Profile",
            json.dumps(benchmark.config.profile),
        )
        self._add_field(
            headers,
            values,
            "Run Info",
            "Requests",
            json.dumps(benchmark.config.requests),
        )
        self._add_field(
            headers, values, "Run Info", "Backend", json.dumps(benchmark.config.backend)
        )
        self._add_field(
            headers,
            values,
            "Run Info",
            "Environment",
            json.dumps(benchmark.config.environment),
        )

    def _add_benchmark_info(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add individual benchmark configuration details.

        :param benchmark: Benchmark data to extract configuration from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        self._add_field(headers, values, "Benchmark", "Type", benchmark.type_)
        self._add_field(headers, values, "Benchmark", "ID", benchmark.config.id_)
        self._add_field(
            headers, values, "Benchmark", "Strategy", benchmark.config.strategy.type_
        )
        self._add_field(
            headers,
            values,
            "Benchmark",
            "Constraints",
            json.dumps(benchmark.config.constraints),
        )

    def _add_timing_info(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add timing information including start, end, duration, warmup, and cooldown.

        :param benchmark: Benchmark data to extract timing from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        timing_fields: list[tuple[str, Any]] = [
            ("Start Time", benchmark.scheduler_metrics.start_time),
            ("Request Start Time", benchmark.scheduler_metrics.request_start_time),
            ("Measure Start Time", benchmark.scheduler_metrics.measure_start_time),
            ("Measure End Time", benchmark.scheduler_metrics.measure_end_time),
            ("Request End Time", benchmark.scheduler_metrics.request_end_time),
            ("End Time", benchmark.scheduler_metrics.end_time),
        ]
        for field_name, timestamp in timing_fields:
            self._add_field(
                headers,
                values,
                "Timings",
                field_name,
                safe_format_timestamp(timestamp, TIMESTAMP_FORMAT),
            )

        duration_fields: list[tuple[str, float | str]] = [
            ("Duration", benchmark.duration),
            ("Warmup", benchmark.warmup_duration),
            ("Cooldown", benchmark.cooldown_duration),
        ]
        for field_name, duration_value in duration_fields:
            self._add_field(
                headers, values, "Timings", field_name, duration_value, "Sec"
            )

    def _add_request_counts(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add request count totals by status.

        :param benchmark: Benchmark data to extract request counts from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        for status in ["successful", "incomplete", "errored", "total"]:
            self._add_field(
                headers,
                values,
                "Request Counts",
                status.capitalize(),
                getattr(benchmark.metrics.request_totals, status),
            )

    def _add_request_latency_metrics(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add request latency and streaming metrics.

        :param benchmark: Benchmark data to extract latency metrics from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        self._add_stats_for_metric(
            headers, values, benchmark.metrics.request_latency, "Request Latency", "Sec"
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.request_streaming_iterations_count,
            "Streaming Iterations",
            "Count",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.time_to_first_token_ms,
            "Time to First Token",
            "ms",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.time_to_first_output_token_ms,
            "Time to First Output Token",
            "ms",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.time_per_output_token_ms,
            "Time per Output Token",
            "ms",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.inter_token_latency_ms,
            "Inter Token Latency",
            "ms",
        )

    def _add_server_throughput_metrics(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add server throughput metrics including requests, tokens, and concurrency.

        :param benchmark: Benchmark data to extract throughput metrics from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.requests_per_second,
            "Server Throughput",
            "Requests/Sec",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.request_concurrency,
            "Server Throughput",
            "Concurrency",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.prompt_token_count,
            "Token Metrics",
            "Input Tokens",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.output_token_count,
            "Token Metrics",
            "Output Tokens",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.total_token_count,
            "Token Metrics",
            "Total Tokens",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.prompt_tokens_per_second,
            "Token Throughput",
            "Input Tokens/Sec",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.output_tokens_per_second,
            "Token Throughput",
            "Output Tokens/Sec",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.tokens_per_second,
            "Token Throughput",
            "Total Tokens/Sec",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.output_tokens_per_iteration,
            "Token Streaming",
            "Output Tokens/Iter",
        )
        self._add_stats_for_metric(
            headers,
            values,
            benchmark.metrics.iter_tokens_per_iteration,
            "Token Streaming",
            "Iter Tokens/Iter",
        )

    def _add_modality_metrics(
        self,
        benchmark: GenerativeBenchmark,
        modality: Literal["text", "image", "video", "audio"],
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add modality-specific metrics for text, image, video, or audio data.

        :param benchmark: Benchmark data to extract modality metrics from
        :param modality: Type of modality to extract metrics for
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        modality_summary = getattr(benchmark.metrics, modality)
        metric_definitions = MODALITY_METRICS[modality]

        for metric_name, display_name in metric_definitions:
            metric_obj = getattr(modality_summary, metric_name, None)
            if metric_obj is None:
                continue

            for io_type in ["input", "output", "total"]:
                dist_summary = getattr(metric_obj, io_type, None)
                if dist_summary is None:
                    continue

                if not self._has_distribution_data(dist_summary):
                    continue

                self._add_stats_for_metric(
                    headers,
                    values,
                    dist_summary,
                    f"{modality.capitalize()} {display_name}",
                    io_type.capitalize(),
                )

    def _has_distribution_data(self, dist_summary: StatusDistributionSummary) -> bool:
        """
        Check if distribution summary contains any data.

        Uses ``count > 0`` rather than ``total_sum > 0`` so that
        all-zero distributions (e.g. errored tool-call requests) are
        still recognised as having data.

        :param dist_summary: Distribution summary to check
        :return: True if summary contains data, False otherwise
        """
        return any(
            getattr(dist_summary, status, None) is not None
            and getattr(dist_summary, status).count > 0
            for status in ["successful", "incomplete", "errored"]
        )

    def _add_scheduler_info(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add scheduler state and performance information.

        :param benchmark: Benchmark data to extract scheduler info from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        self._add_scheduler_state(benchmark, headers, values)
        self._add_scheduler_metrics(benchmark, headers, values)

    def _add_scheduler_state(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add scheduler state information including request counts and timing.

        :param benchmark: Benchmark data to extract scheduler state from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        state = benchmark.scheduler_state

        state_fields: list[tuple[str, Any]] = [
            ("Node ID", state.node_id),
            ("Num Processes", state.num_processes),
            ("Created Requests", state.created_requests),
            ("Processed Requests", state.processed_requests),
            ("Successful Requests", state.successful_requests),
            ("Errored Requests", state.errored_requests),
            ("Cancelled Requests", state.cancelled_requests),
        ]

        for field_name, value in state_fields:
            self._add_field(headers, values, "Scheduler State", field_name, value)

        if state.end_queuing_time:
            self._add_field(
                headers,
                values,
                "Scheduler State",
                "End Queuing Time",
                safe_format_timestamp(state.end_queuing_time, TIMESTAMP_FORMAT),
            )
            end_queuing_constraints_dict = {
                key: constraint.model_dump()
                for key, constraint in state.end_queuing_constraints.items()
            }
            self._add_field(
                headers,
                values,
                "Scheduler State",
                "End Queuing Constraints",
                json.dumps(end_queuing_constraints_dict),
            )

        if state.end_processing_time:
            self._add_field(
                headers,
                values,
                "Scheduler State",
                "End Processing Time",
                safe_format_timestamp(state.end_processing_time, TIMESTAMP_FORMAT),
            )
            end_processing_constraints_dict = {
                key: constraint.model_dump()
                for key, constraint in state.end_processing_constraints.items()
            }
            self._add_field(
                headers,
                values,
                "Scheduler State",
                "End Processing Constraints",
                json.dumps(end_processing_constraints_dict),
            )

    def _add_scheduler_metrics(
        self,
        benchmark: GenerativeBenchmark,
        headers: list[list[str]],
        values: list[str | int | float],
    ) -> None:
        """
        Add scheduler performance metrics including delays and processing times.

        :param benchmark: Benchmark data to extract scheduler metrics from
        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        """
        metrics = benchmark.scheduler_metrics

        requests_made_fields: list[tuple[str, int]] = [
            ("Requests Made Successful", metrics.requests_made.successful),
            ("Requests Made Incomplete", metrics.requests_made.incomplete),
            ("Requests Made Errored", metrics.requests_made.errored),
            ("Requests Made Total", metrics.requests_made.total),
        ]
        for field_name, value in requests_made_fields:
            self._add_field(headers, values, "Scheduler Metrics", field_name, value)

        timing_metrics: list[tuple[str, float]] = [
            ("Queued Time Avg", metrics.queued_time_avg),
            ("Resolve Start Delay Avg", metrics.resolve_start_delay_avg),
            (
                "Resolve Targeted Start Delay Avg",
                metrics.resolve_targeted_start_delay_avg,
            ),
            ("Request Start Delay Avg", metrics.request_start_delay_avg),
            (
                "Request Targeted Start Delay Avg",
                metrics.request_targeted_start_delay_avg,
            ),
            ("Request Time Avg", metrics.request_time_avg),
            ("Resolve End Delay Avg", metrics.resolve_end_delay_avg),
            ("Resolve Time Avg", metrics.resolve_time_avg),
            ("Finalized Delay Avg", metrics.finalized_delay_avg),
            ("Processed Delay Avg", metrics.processed_delay_avg),
        ]
        for field_name, timing in timing_metrics:
            self._add_field(
                headers, values, "Scheduler Metrics", field_name, timing, "Sec"
            )

    def _add_stats_for_metric(
        self,
        headers: list[list[str]],
        values: list[str | int | float],
        metric: StatusDistributionSummary | DistributionSummary,
        group: str,
        units: str,
    ) -> None:
        """
        Add statistical summaries for a metric across all statuses.

        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        :param metric: Distribution summary to extract statistics from
        :param group: Top-level category for the metric
        :param units: Units for the metric values
        """
        if isinstance(metric, StatusDistributionSummary):
            for status in ["successful", "incomplete", "errored"]:
                dist = getattr(metric, status, None)
                if dist is None or dist.total_sum == 0.0:
                    continue
                self._add_distribution_stats(
                    headers, values, dist, group, units, status
                )
        else:
            self._add_distribution_stats(headers, values, metric, group, units, None)

    def _add_distribution_stats(
        self,
        headers: list[list[str]],
        values: list[str | int | float],
        dist: DistributionSummary,
        group: str,
        units: str,
        status: str | None,
    ) -> None:
        """
        Add distribution statistics including mean, median, and percentiles.

        :param headers: List of header hierarchies to append to
        :param values: List of values to append to
        :param dist: Distribution summary with statistical data
        :param group: Top-level category for the metric
        :param units: Units for the metric values
        :param status: Request status (successful, incomplete, errored) or None
        """
        status_prefix = f"{status.capitalize()} " if status else ""

        headers.append([group, f"{status_prefix}{units}", "Mean"])
        values.append(dist.mean)

        headers.append([group, f"{status_prefix}{units}", "Median"])
        values.append(dist.median)

        headers.append([group, f"{status_prefix}{units}", "Std Dev"])
        values.append(dist.std_dev)

        headers.append([group, f"{status_prefix}{units}", "Percentiles"])
        percentiles_str = (
            f"[{dist.min}, {dist.percentiles.p001}, {dist.percentiles.p01}, "
            f"{dist.percentiles.p05}, {dist.percentiles.p10}, {dist.percentiles.p25}, "
            f"{dist.percentiles.p75}, {dist.percentiles.p90}, {dist.percentiles.p95}, "
            f"{dist.percentiles.p99}, {dist.max}]"
        )
        values.append(percentiles_str)

finalize(report) async

Save the benchmark report as a CSV file.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The completed benchmark report

required

Returns:

Type Description
Path

Path to the saved CSV file

Source code in src/guidellm/benchmark/outputs/csv.py
async def finalize(self, report: GenerativeBenchmarksReport) -> Path:
    """
    Save the benchmark report as a CSV file.

    :param report: The completed benchmark report
    :return: Path to the saved CSV file
    """
    output_path = self.output_path
    if output_path.is_dir():
        output_path = output_path / GenerativeBenchmarkerCSV.DEFAULT_FILE
    output_path.parent.mkdir(parents=True, exist_ok=True)

    with output_path.open("w", newline="") as file:
        writer = csv.writer(file)

        all_headers: list[list[list[str]]] = []
        all_values: list[list[str | int | float]] = []

        for benchmark in report.benchmarks:
            benchmark_headers: list[list[str]] = []
            benchmark_values: list[str | int | float] = []

            self._add_run_info(benchmark, benchmark_headers, benchmark_values)
            self._add_benchmark_info(benchmark, benchmark_headers, benchmark_values)
            self._add_timing_info(benchmark, benchmark_headers, benchmark_values)
            self._add_request_counts(benchmark, benchmark_headers, benchmark_values)
            self._add_request_latency_metrics(
                benchmark, benchmark_headers, benchmark_values
            )
            self._add_server_throughput_metrics(
                benchmark, benchmark_headers, benchmark_values
            )
            for modality_name in ["text", "image", "video", "audio"]:
                self._add_modality_metrics(
                    benchmark,
                    modality_name,  # type: ignore[arg-type]
                    benchmark_headers,
                    benchmark_values,
                )
            self._add_scheduler_info(benchmark, benchmark_headers, benchmark_values)
            self._add_runtime_info(report, benchmark_headers, benchmark_values)

            all_headers.append(benchmark_headers)
            all_values.append(benchmark_values)

        headers, data_rows = self._align_columns(all_headers, all_values)

        self._write_multirow_header(writer, headers)
        for row in data_rows:
            writer.writerow(row)

    return output_path

from_args(args) classmethod

Create a CSV output formatter from output arguments.

Parameters:

Name Type Description Default
args BenchmarkOutputArgs

Output configuration with path

required

Returns:

Type Description
GenerativeBenchmarkerCSV

Configured CSV output formatter

Source code in src/guidellm/benchmark/outputs/csv.py
@classmethod
def from_args(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerCSV:
    """
    Create a CSV output formatter from output arguments.

    :param args: Output configuration with path
    :return: Configured CSV output formatter
    """
    if not isinstance(args, CSVBenchmarkOutputArgs):
        raise ValueError(f"Expected CSVBenchmarkOutputArgs, got {type(args)}")

    return cls(output_path=args.path)

GenerativeBenchmarkerConsole

Bases: GenerativeBenchmarkerOutput

Console output formatter for benchmark reports.

Renders benchmark results as formatted tables in the terminal, organizing metrics by category (run summary, request counts, latency, throughput, modality-specific) with proper alignment and type-specific formatting for readability.

Source code in src/guidellm/benchmark/outputs/console.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
@GenerativeBenchmarkerOutput.register("console")
class GenerativeBenchmarkerConsole(GenerativeBenchmarkerOutput):
    """
    Console output formatter for benchmark reports.

    Renders benchmark results as formatted tables in the terminal, organizing metrics
    by category (run summary, request counts, latency, throughput, modality-specific)
    with proper alignment and type-specific formatting for readability.
    """

    @classmethod
    def from_args(cls, _args: BenchmarkOutputArgs) -> GenerativeBenchmarkerConsole:
        """
        Create a console output formatter from output arguments.

        :param _args: Output configuration (unused for console output)
        :return: Configured console output formatter
        """
        return cls()

    console: Console = Field(
        default_factory=Console,
        description="Console utility for rendering formatted tables",
    )

    async def finalize(self, report: GenerativeBenchmarksReport) -> str:
        """
        Print the complete benchmark report to the console.

        Renders all metric tables including run summary, request counts, latency,
        throughput, and modality-specific statistics to the console.

        :param report: The completed benchmark report
        :return: Status message indicating output location
        """
        self.print_run_summary_table(report)
        self.print_text_table(report)
        self.print_image_table(report)
        self.print_video_table(report)
        self.print_audio_table(report)
        self.print_tool_call_table(report)
        self.print_request_counts_table(report)
        self.print_request_latency_table(report)
        self.print_server_throughput_table(report)

        return "printed to console"

    def print_run_summary_table(self, report: GenerativeBenchmarksReport):
        """
        Print the run summary table with timing and token information.

        :param report: The benchmark report containing run metadata
        """
        columns = ConsoleTableColumnsCollection()

        for benchmark in report.benchmarks:
            columns.add_value(
                benchmark.config.strategy.type_,
                group="Benchmark",
                name="Strategy",
                type_="text",
            )
            columns.add_value(
                benchmark.start_time, group="Timings", name="Start", type_="timestamp"
            )
            columns.add_value(
                benchmark.end_time, group="Timings", name="End", type_="timestamp"
            )
            columns.add_value(
                benchmark.duration, group="Timings", name="Dur", units="Sec"
            )
            columns.add_value(
                benchmark.warmup_duration, group="Timings", name="Warm", units="Sec"
            )
            columns.add_value(
                benchmark.cooldown_duration, group="Timings", name="Cool", units="Sec"
            )

            for token_metrics, group in [
                (benchmark.metrics.prompt_token_count, "Input Tokens"),
                (benchmark.metrics.output_token_count, "Output Tokens"),
            ]:
                columns.add_value(
                    token_metrics.successful.total_sum,
                    group=group,
                    name="Comp",
                    units="Tot",
                )
                columns.add_value(
                    token_metrics.incomplete.total_sum,
                    group=group,
                    name="Inc",
                    units="Tot",
                )
                columns.add_value(
                    token_metrics.errored.total_sum,
                    group=group,
                    name="Err",
                    units="Tot",
                )

        headers, values = columns.get_table_data()
        self.console.print("\n")
        self.console.print_table(headers, values, title="Run Summary Info")

    def print_text_table(self, report: GenerativeBenchmarksReport):
        """
        Print text-specific metrics table if any text data exists.

        :param report: The benchmark report containing text metrics
        """
        self._print_modality_table(
            report=report,
            modality="text",
            title="Text Metrics Statistics (Completed Requests)",
            metric_groups=[
                ("tokens", "Tokens"),
                ("words", "Words"),
                ("characters", "Characters"),
            ],
        )

    def print_image_table(self, report: GenerativeBenchmarksReport):
        """
        Print image-specific metrics table if any image data exists.

        :param report: The benchmark report containing image metrics
        """
        self._print_modality_table(
            report=report,
            modality="image",
            title="Image Metrics Statistics (Completed Requests)",
            metric_groups=[
                ("tokens", "Tokens"),
                ("images", "Images"),
                ("pixels", "Pixels"),
                ("bytes", "Bytes"),
            ],
        )

    def print_video_table(self, report: GenerativeBenchmarksReport):
        """
        Print video-specific metrics table if any video data exists.

        :param report: The benchmark report containing video metrics
        """
        self._print_modality_table(
            report=report,
            modality="video",
            title="Video Metrics Statistics (Completed Requests)",
            metric_groups=[
                ("tokens", "Tokens"),
                ("frames", "Frames"),
                ("seconds", "Seconds"),
                ("bytes", "Bytes"),
            ],
        )

    def print_audio_table(self, report: GenerativeBenchmarksReport):
        """
        Print audio-specific metrics table if any audio data exists.

        :param report: The benchmark report containing audio metrics
        """
        self._print_modality_table(
            report=report,
            modality="audio",
            title="Audio Metrics Statistics (Completed Requests)",
            metric_groups=[
                ("tokens", "Tokens"),
                ("samples", "Samples"),
                ("seconds", "Seconds"),
                ("bytes", "Bytes"),
            ],
        )

    def print_tool_call_table(self, report: GenerativeBenchmarksReport):
        """
        Print tool-call-specific metrics table if any tool call data exists.

        :param report: The benchmark report containing tool call metrics
        """
        self._print_modality_table(
            report=report,
            modality="tool_call",
            title="Tool Call Metrics Statistics (Completed Requests)",
            metric_groups=[
                ("tokens", "Tokens"),
                ("mixed_tokens", "Mixed Tokens"),
                ("count", "Count"),
            ],
        )

    def print_request_counts_table(self, report: GenerativeBenchmarksReport):
        """
        Print request token count statistics table.

        :param report: The benchmark report containing request count metrics
        """
        columns = ConsoleTableColumnsCollection()

        for benchmark in report.benchmarks:
            columns.add_value(
                benchmark.config.strategy.type_,
                group="Benchmark",
                name="Strategy",
                type_="text",
            )
            columns.add_stats(
                benchmark.metrics.prompt_token_count,
                group="Input Tok",
                name="Per Req",
            )
            columns.add_stats(
                benchmark.metrics.output_token_count,
                group="Output Tok",
                name="Per Req",
            )
            columns.add_stats(
                benchmark.metrics.total_token_count,
                group="Total Tok",
                name="Per Req",
            )
            columns.add_stats(
                benchmark.metrics.request_streaming_iterations_count,
                group="Stream Iter",
                name="Per Req",
            )
            columns.add_stats(
                benchmark.metrics.output_tokens_per_iteration,
                group="Output Tok",
                name="Per Stream Iter",
            )

        headers, values = columns.get_table_data()
        self.console.print("\n")
        self.console.print_table(
            headers,
            values,
            title="Request Token Statistics (Completed Requests)",
        )

    def print_request_latency_table(self, report: GenerativeBenchmarksReport):
        """
        Print request latency metrics table.

        :param report: The benchmark report containing latency metrics
        """
        columns = ConsoleTableColumnsCollection()

        for benchmark in report.benchmarks:
            columns.add_value(
                benchmark.config.strategy.type_,
                group="Benchmark",
                name="Strategy",
                type_="text",
            )
            columns.add_stats(
                benchmark.metrics.request_latency,
                group="Request Latency",
                name="Sec",
            )
            columns.add_stats(
                benchmark.metrics.time_to_first_token_ms,
                group="TTFT",
                name="ms",
            )
            columns.add_stats(
                benchmark.metrics.time_to_first_output_token_ms,
                group="TTFOT",
                name="ms",
            )
            columns.add_stats(
                benchmark.metrics.inter_token_latency_ms,
                group="ITL",
                name="ms",
            )
            columns.add_stats(
                benchmark.metrics.time_per_output_token_ms,
                group="TPOT",
                name="ms",
            )

        headers, values = columns.get_table_data()
        self.console.print("\n")
        self.console.print_table(
            headers,
            values,
            title="Request Latency Statistics (Completed Requests)",
        )

    def print_server_throughput_table(self, report: GenerativeBenchmarksReport):
        """
        Print server throughput metrics table.

        :param report: The benchmark report containing throughput metrics
        """
        columns = ConsoleTableColumnsCollection()

        for benchmark in report.benchmarks:
            columns.add_value(
                benchmark.config.strategy.type_,
                group="Benchmark",
                name="Strategy",
                type_="text",
            )
            columns.add_stats(
                benchmark.metrics.request_concurrency,
                status="total",
                group="Requests",
                name="Concurrency",
                types=("median", "mean"),
            )
            columns.add_stats(
                benchmark.metrics.requests_per_second,
                status="total",
                group="Requests",
                name="Per Sec",
                types=("mean",),
            )
            columns.add_stats(
                benchmark.metrics.prompt_tokens_per_second,
                status="total",
                group="Input Tokens",
                name="Per Sec",
                types=("mean",),
            )
            columns.add_stats(
                benchmark.metrics.output_tokens_per_second,
                status="total",
                group="Output Tokens",
                name="Per Sec",
                types=("mean",),
            )
            columns.add_stats(
                benchmark.metrics.tokens_per_second,
                status="total",
                group="Total Tokens",
                name="Per Sec",
                types=("mean",),
            )

        headers, values = columns.get_table_data()
        self.console.print("\n")
        self.console.print_table(
            headers, values, title="Server Throughput Statistics (All Requests)"
        )

    def _print_modality_table(
        self,
        report: GenerativeBenchmarksReport,
        modality: Literal["text", "image", "video", "audio", "tool_call"],
        title: str,
        metric_groups: list[tuple[str, str]],
    ):
        columns: dict[str, ConsoleTableColumnsCollection] = defaultdict(
            ConsoleTableColumnsCollection
        )

        for benchmark in report.benchmarks:
            columns["labels"].add_value(
                benchmark.config.strategy.type_,
                group="Benchmark",
                name="Strategy",
                type_="text",
            )

            modality_metrics = getattr(benchmark.metrics, modality)

            for metric_attr, display_name in metric_groups:
                metric_obj = getattr(modality_metrics, metric_attr, None)
                input_stats: StatusDistributionSummary | None = (
                    getattr(metric_obj, "input", None) if metric_obj else None
                )
                columns[f"{metric_attr}.input"].add_stats(
                    input_stats,
                    group=f"Input {display_name}",
                    name="Per Request",
                )
                input_per_second_stats: StatusDistributionSummary | None = (
                    getattr(metric_obj, "input_per_second", None)
                    if metric_obj
                    else None
                )
                columns[f"{metric_attr}.input"].add_stats(
                    input_per_second_stats,
                    group=f"Input {display_name}",
                    name="Per Second",
                    types=("median", "mean"),
                )
                output_stats: StatusDistributionSummary | None = (
                    getattr(metric_obj, "output", None) if metric_obj else None
                )
                columns[f"{metric_attr}.output"].add_stats(
                    output_stats,
                    group=f"Output {display_name}",
                    name="Per Request",
                )
                output_per_second_stats: StatusDistributionSummary | None = (
                    getattr(metric_obj, "output_per_second", None)
                    if metric_obj
                    else None
                )
                columns[f"{metric_attr}.output"].add_stats(
                    output_per_second_stats,
                    group=f"Output {display_name}",
                    name="Per Second",
                    types=("median", "mean"),
                )

        self._print_inp_out_tables(
            title=title,
            labels=columns["labels"],
            groups=[
                (columns[f"{metric_attr}.input"], columns[f"{metric_attr}.output"])
                for metric_attr, _ in metric_groups
            ],
        )

    def _print_inp_out_tables(
        self,
        title: str,
        labels: ConsoleTableColumnsCollection,
        groups: list[
            tuple[ConsoleTableColumnsCollection, ConsoleTableColumnsCollection]
        ],
    ):
        input_headers, input_values = [], []
        output_headers, output_values = [], []
        input_has_data = False
        output_has_data = False

        for input_columns, output_columns in groups:
            # Check if columns have any non-None values
            type_input_has_data = any(
                any(value is not None for value in column.values)
                for column in input_columns.values()
            )
            type_output_has_data = any(
                any(value is not None for value in column.values)
                for column in output_columns.values()
            )

            if not (type_input_has_data or type_output_has_data):
                continue

            input_has_data = input_has_data or type_input_has_data
            output_has_data = output_has_data or type_output_has_data

            input_type_headers, input_type_columns = input_columns.get_table_data()
            output_type_headers, output_type_columns = output_columns.get_table_data()

            input_headers.extend(input_type_headers)
            input_values.extend(input_type_columns)
            output_headers.extend(output_type_headers)
            output_values.extend(output_type_columns)

        if not (input_has_data or output_has_data):
            return

        labels_headers, labels_values = labels.get_table_data()
        header_cols_groups = []
        value_cols_groups = []

        if input_has_data:
            header_cols_groups.append(labels_headers + input_headers)
            value_cols_groups.append(labels_values + input_values)
        if output_has_data:
            header_cols_groups.append(labels_headers + output_headers)
            value_cols_groups.append(labels_values + output_values)

        if header_cols_groups and value_cols_groups:
            self.console.print("\n")
            self.console.print_tables(
                header_cols_groups=header_cols_groups,
                value_cols_groups=value_cols_groups,
                title=title,
            )

finalize(report) async

Print the complete benchmark report to the console.

Renders all metric tables including run summary, request counts, latency, throughput, and modality-specific statistics to the console.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The completed benchmark report

required

Returns:

Type Description
str

Status message indicating output location

Source code in src/guidellm/benchmark/outputs/console.py
async def finalize(self, report: GenerativeBenchmarksReport) -> str:
    """
    Print the complete benchmark report to the console.

    Renders all metric tables including run summary, request counts, latency,
    throughput, and modality-specific statistics to the console.

    :param report: The completed benchmark report
    :return: Status message indicating output location
    """
    self.print_run_summary_table(report)
    self.print_text_table(report)
    self.print_image_table(report)
    self.print_video_table(report)
    self.print_audio_table(report)
    self.print_tool_call_table(report)
    self.print_request_counts_table(report)
    self.print_request_latency_table(report)
    self.print_server_throughput_table(report)

    return "printed to console"

from_args(_args) classmethod

Create a console output formatter from output arguments.

Parameters:

Name Type Description Default
_args BenchmarkOutputArgs

Output configuration (unused for console output)

required

Returns:

Type Description
GenerativeBenchmarkerConsole

Configured console output formatter

Source code in src/guidellm/benchmark/outputs/console.py
@classmethod
def from_args(cls, _args: BenchmarkOutputArgs) -> GenerativeBenchmarkerConsole:
    """
    Create a console output formatter from output arguments.

    :param _args: Output configuration (unused for console output)
    :return: Configured console output formatter
    """
    return cls()

print_audio_table(report)

Print audio-specific metrics table if any audio data exists.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing audio metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_audio_table(self, report: GenerativeBenchmarksReport):
    """
    Print audio-specific metrics table if any audio data exists.

    :param report: The benchmark report containing audio metrics
    """
    self._print_modality_table(
        report=report,
        modality="audio",
        title="Audio Metrics Statistics (Completed Requests)",
        metric_groups=[
            ("tokens", "Tokens"),
            ("samples", "Samples"),
            ("seconds", "Seconds"),
            ("bytes", "Bytes"),
        ],
    )

print_image_table(report)

Print image-specific metrics table if any image data exists.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing image metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_image_table(self, report: GenerativeBenchmarksReport):
    """
    Print image-specific metrics table if any image data exists.

    :param report: The benchmark report containing image metrics
    """
    self._print_modality_table(
        report=report,
        modality="image",
        title="Image Metrics Statistics (Completed Requests)",
        metric_groups=[
            ("tokens", "Tokens"),
            ("images", "Images"),
            ("pixels", "Pixels"),
            ("bytes", "Bytes"),
        ],
    )

print_request_counts_table(report)

Print request token count statistics table.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing request count metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_request_counts_table(self, report: GenerativeBenchmarksReport):
    """
    Print request token count statistics table.

    :param report: The benchmark report containing request count metrics
    """
    columns = ConsoleTableColumnsCollection()

    for benchmark in report.benchmarks:
        columns.add_value(
            benchmark.config.strategy.type_,
            group="Benchmark",
            name="Strategy",
            type_="text",
        )
        columns.add_stats(
            benchmark.metrics.prompt_token_count,
            group="Input Tok",
            name="Per Req",
        )
        columns.add_stats(
            benchmark.metrics.output_token_count,
            group="Output Tok",
            name="Per Req",
        )
        columns.add_stats(
            benchmark.metrics.total_token_count,
            group="Total Tok",
            name="Per Req",
        )
        columns.add_stats(
            benchmark.metrics.request_streaming_iterations_count,
            group="Stream Iter",
            name="Per Req",
        )
        columns.add_stats(
            benchmark.metrics.output_tokens_per_iteration,
            group="Output Tok",
            name="Per Stream Iter",
        )

    headers, values = columns.get_table_data()
    self.console.print("\n")
    self.console.print_table(
        headers,
        values,
        title="Request Token Statistics (Completed Requests)",
    )

print_request_latency_table(report)

Print request latency metrics table.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing latency metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_request_latency_table(self, report: GenerativeBenchmarksReport):
    """
    Print request latency metrics table.

    :param report: The benchmark report containing latency metrics
    """
    columns = ConsoleTableColumnsCollection()

    for benchmark in report.benchmarks:
        columns.add_value(
            benchmark.config.strategy.type_,
            group="Benchmark",
            name="Strategy",
            type_="text",
        )
        columns.add_stats(
            benchmark.metrics.request_latency,
            group="Request Latency",
            name="Sec",
        )
        columns.add_stats(
            benchmark.metrics.time_to_first_token_ms,
            group="TTFT",
            name="ms",
        )
        columns.add_stats(
            benchmark.metrics.time_to_first_output_token_ms,
            group="TTFOT",
            name="ms",
        )
        columns.add_stats(
            benchmark.metrics.inter_token_latency_ms,
            group="ITL",
            name="ms",
        )
        columns.add_stats(
            benchmark.metrics.time_per_output_token_ms,
            group="TPOT",
            name="ms",
        )

    headers, values = columns.get_table_data()
    self.console.print("\n")
    self.console.print_table(
        headers,
        values,
        title="Request Latency Statistics (Completed Requests)",
    )

print_run_summary_table(report)

Print the run summary table with timing and token information.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing run metadata

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_run_summary_table(self, report: GenerativeBenchmarksReport):
    """
    Print the run summary table with timing and token information.

    :param report: The benchmark report containing run metadata
    """
    columns = ConsoleTableColumnsCollection()

    for benchmark in report.benchmarks:
        columns.add_value(
            benchmark.config.strategy.type_,
            group="Benchmark",
            name="Strategy",
            type_="text",
        )
        columns.add_value(
            benchmark.start_time, group="Timings", name="Start", type_="timestamp"
        )
        columns.add_value(
            benchmark.end_time, group="Timings", name="End", type_="timestamp"
        )
        columns.add_value(
            benchmark.duration, group="Timings", name="Dur", units="Sec"
        )
        columns.add_value(
            benchmark.warmup_duration, group="Timings", name="Warm", units="Sec"
        )
        columns.add_value(
            benchmark.cooldown_duration, group="Timings", name="Cool", units="Sec"
        )

        for token_metrics, group in [
            (benchmark.metrics.prompt_token_count, "Input Tokens"),
            (benchmark.metrics.output_token_count, "Output Tokens"),
        ]:
            columns.add_value(
                token_metrics.successful.total_sum,
                group=group,
                name="Comp",
                units="Tot",
            )
            columns.add_value(
                token_metrics.incomplete.total_sum,
                group=group,
                name="Inc",
                units="Tot",
            )
            columns.add_value(
                token_metrics.errored.total_sum,
                group=group,
                name="Err",
                units="Tot",
            )

    headers, values = columns.get_table_data()
    self.console.print("\n")
    self.console.print_table(headers, values, title="Run Summary Info")

print_server_throughput_table(report)

Print server throughput metrics table.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing throughput metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_server_throughput_table(self, report: GenerativeBenchmarksReport):
    """
    Print server throughput metrics table.

    :param report: The benchmark report containing throughput metrics
    """
    columns = ConsoleTableColumnsCollection()

    for benchmark in report.benchmarks:
        columns.add_value(
            benchmark.config.strategy.type_,
            group="Benchmark",
            name="Strategy",
            type_="text",
        )
        columns.add_stats(
            benchmark.metrics.request_concurrency,
            status="total",
            group="Requests",
            name="Concurrency",
            types=("median", "mean"),
        )
        columns.add_stats(
            benchmark.metrics.requests_per_second,
            status="total",
            group="Requests",
            name="Per Sec",
            types=("mean",),
        )
        columns.add_stats(
            benchmark.metrics.prompt_tokens_per_second,
            status="total",
            group="Input Tokens",
            name="Per Sec",
            types=("mean",),
        )
        columns.add_stats(
            benchmark.metrics.output_tokens_per_second,
            status="total",
            group="Output Tokens",
            name="Per Sec",
            types=("mean",),
        )
        columns.add_stats(
            benchmark.metrics.tokens_per_second,
            status="total",
            group="Total Tokens",
            name="Per Sec",
            types=("mean",),
        )

    headers, values = columns.get_table_data()
    self.console.print("\n")
    self.console.print_table(
        headers, values, title="Server Throughput Statistics (All Requests)"
    )

print_text_table(report)

Print text-specific metrics table if any text data exists.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing text metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_text_table(self, report: GenerativeBenchmarksReport):
    """
    Print text-specific metrics table if any text data exists.

    :param report: The benchmark report containing text metrics
    """
    self._print_modality_table(
        report=report,
        modality="text",
        title="Text Metrics Statistics (Completed Requests)",
        metric_groups=[
            ("tokens", "Tokens"),
            ("words", "Words"),
            ("characters", "Characters"),
        ],
    )

print_tool_call_table(report)

Print tool-call-specific metrics table if any tool call data exists.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing tool call metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_tool_call_table(self, report: GenerativeBenchmarksReport):
    """
    Print tool-call-specific metrics table if any tool call data exists.

    :param report: The benchmark report containing tool call metrics
    """
    self._print_modality_table(
        report=report,
        modality="tool_call",
        title="Tool Call Metrics Statistics (Completed Requests)",
        metric_groups=[
            ("tokens", "Tokens"),
            ("mixed_tokens", "Mixed Tokens"),
            ("count", "Count"),
        ],
    )

print_video_table(report)

Print video-specific metrics table if any video data exists.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

The benchmark report containing video metrics

required
Source code in src/guidellm/benchmark/outputs/console.py
def print_video_table(self, report: GenerativeBenchmarksReport):
    """
    Print video-specific metrics table if any video data exists.

    :param report: The benchmark report containing video metrics
    """
    self._print_modality_table(
        report=report,
        modality="video",
        title="Video Metrics Statistics (Completed Requests)",
        metric_groups=[
            ("tokens", "Tokens"),
            ("frames", "Frames"),
            ("seconds", "Seconds"),
            ("bytes", "Bytes"),
        ],
    )

GenerativeBenchmarkerHTML

Bases: GenerativeBenchmarkerOutput

HTML output formatter for benchmark results.

Generates interactive HTML reports from benchmark data by transforming results into camelCase JSON structures and injecting them into HTML templates. The formatter processes benchmark metrics, creates histogram distributions, and embeds all data into a pre-built HTML template for browser-based visualization. Reports are saved to the specified output path or current working directory.

Attributes:

Name Type Description
DEFAULT_FILE str

Default filename for HTML output when a directory is provided

Source code in src/guidellm/benchmark/outputs/html.py
@GenerativeBenchmarkerOutput.register("html")
class GenerativeBenchmarkerHTML(GenerativeBenchmarkerOutput):
    """
    HTML output formatter for benchmark results.

    Generates interactive HTML reports from benchmark data by transforming results
    into camelCase JSON structures and injecting them into HTML templates. The
    formatter processes benchmark metrics, creates histogram distributions, and
    embeds all data into a pre-built HTML template for browser-based visualization.
    Reports are saved to the specified output path or current working directory.

    :cvar DEFAULT_FILE: Default filename for HTML output when a directory is provided
    """

    DEFAULT_FILE: ClassVar[str] = "benchmarks.html"

    output_path: Path = Field(
        default_factory=Path.cwd,
        description=(
            "Directory or file path for saving the HTML report, "
            "defaults to current working directory"
        ),
    )

    @classmethod
    def from_args(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerHTML:
        """
        Create an HTML output formatter from output arguments.

        :param args: Output configuration with path
        :return: Configured HTML output formatter
        """
        if not isinstance(args, HTMLBenchmarkOutputArgs):
            raise TypeError(f"Expected HTMLBenchmarkOutputArgs, got {type(args)}")

        return cls(output_path=args.path)

    async def finalize(self, report: GenerativeBenchmarksReport) -> Path:
        """
        Generate and save the HTML benchmark report.

        Transforms benchmark data into camelCase JSON format, injects it into the
        HTML template, and writes the resulting report to the output path. Creates
        parent directories if they don't exist.

        :param report: Completed benchmark report containing all results
        :return: Path to the saved HTML report file
        """
        output_path = self.output_path
        if output_path.is_dir():
            output_path = output_path / self.DEFAULT_FILE
        output_path.parent.mkdir(parents=True, exist_ok=True)

        data = _build_ui_data(report.benchmarks, report.config)
        camel_data = recursive_key_update(deepcopy(data), camelize_str)

        ui_api_data = {
            f"window.{key} = {{}};": f"window.{key} = {json.dumps(value, indent=2)};\n"
            for key, value in camel_data.items()
        }

        _create_html_report(ui_api_data, output_path)

        return output_path

finalize(report) async

Generate and save the HTML benchmark report.

Transforms benchmark data into camelCase JSON format, injects it into the HTML template, and writes the resulting report to the output path. Creates parent directories if they don't exist.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

Completed benchmark report containing all results

required

Returns:

Type Description
Path

Path to the saved HTML report file

Source code in src/guidellm/benchmark/outputs/html.py
async def finalize(self, report: GenerativeBenchmarksReport) -> Path:
    """
    Generate and save the HTML benchmark report.

    Transforms benchmark data into camelCase JSON format, injects it into the
    HTML template, and writes the resulting report to the output path. Creates
    parent directories if they don't exist.

    :param report: Completed benchmark report containing all results
    :return: Path to the saved HTML report file
    """
    output_path = self.output_path
    if output_path.is_dir():
        output_path = output_path / self.DEFAULT_FILE
    output_path.parent.mkdir(parents=True, exist_ok=True)

    data = _build_ui_data(report.benchmarks, report.config)
    camel_data = recursive_key_update(deepcopy(data), camelize_str)

    ui_api_data = {
        f"window.{key} = {{}};": f"window.{key} = {json.dumps(value, indent=2)};\n"
        for key, value in camel_data.items()
    }

    _create_html_report(ui_api_data, output_path)

    return output_path

from_args(args) classmethod

Create an HTML output formatter from output arguments.

Parameters:

Name Type Description Default
args BenchmarkOutputArgs

Output configuration with path

required

Returns:

Type Description
GenerativeBenchmarkerHTML

Configured HTML output formatter

Source code in src/guidellm/benchmark/outputs/html.py
@classmethod
def from_args(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerHTML:
    """
    Create an HTML output formatter from output arguments.

    :param args: Output configuration with path
    :return: Configured HTML output formatter
    """
    if not isinstance(args, HTMLBenchmarkOutputArgs):
        raise TypeError(f"Expected HTMLBenchmarkOutputArgs, got {type(args)}")

    return cls(output_path=args.path)

GenerativeBenchmarkerOutput

Bases: BaseModel, RegistryMixin[type['GenerativeBenchmarkerOutput']], ABC

Abstract base for benchmark output formatters with registry support.

Defines the interface for transforming benchmark reports into various output formats. Subclasses implement specific formatters (JSON, CSV, HTML) that can be registered and resolved dynamically.

Example: ::

    output = GenerativeBenchmarkerOutput.resolve(
        JSONBenchmarkOutputArgs(path="./results.json")
    )
    await output.finalize(report)
Source code in src/guidellm/benchmark/outputs/output.py
class GenerativeBenchmarkerOutput(
    BaseModel, RegistryMixin[type["GenerativeBenchmarkerOutput"]], ABC
):
    """
    Abstract base for benchmark output formatters with registry support.

    Defines the interface for transforming benchmark reports into various output
    formats. Subclasses implement specific formatters (JSON, CSV, HTML) that can be
    registered and resolved dynamically.

    Example:
        ::

            output = GenerativeBenchmarkerOutput.resolve(
                JSONBenchmarkOutputArgs(path="./results.json")
            )
            await output.finalize(report)
    """

    model_config = ConfigDict(
        extra="ignore",
        arbitrary_types_allowed=True,
        validate_assignment=True,
        from_attributes=True,
        use_enum_values=True,
    )

    @classmethod
    @abstractmethod
    def from_args(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerOutput:
        """
        Create an output formatter instance from output arguments.

        :param args: Output configuration arguments
        :return: Configured output formatter instance
        """
        ...

    @classmethod
    def resolve(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerOutput:
        """
        Resolve output arguments into a formatter instance.

        Looks up the registered output class by ``args.kind`` and delegates
        construction to its :meth:`from_args` factory.

        :param args: Output configuration arguments with kind and format-specific fields
        :return: Configured output formatter instance
        :raises ValueError: If the output kind is not registered
        """
        output_class = cls.get_registered_object(args.kind)
        if output_class is None:
            available_formats = list(cls.registry.keys()) if cls.registry else []
            raise ValueError(
                f"Output format '{args.kind}' is not registered. "
                f"Available formats: {available_formats}"
            )
        return output_class.from_args(args)

    @abstractmethod
    async def finalize(self, report: GenerativeBenchmarksReport) -> Any:
        """
        Process and persist benchmark report in the formatter's output format.

        :param report: Benchmark report containing results to format and output
        :return: Format-specific output result (file path, response object, etc.)
        """
        ...

finalize(report) abstractmethod async

Process and persist benchmark report in the formatter's output format.

Parameters:

Name Type Description Default
report GenerativeBenchmarksReport

Benchmark report containing results to format and output

required

Returns:

Type Description
Any

Format-specific output result (file path, response object, etc.)

Source code in src/guidellm/benchmark/outputs/output.py
@abstractmethod
async def finalize(self, report: GenerativeBenchmarksReport) -> Any:
    """
    Process and persist benchmark report in the formatter's output format.

    :param report: Benchmark report containing results to format and output
    :return: Format-specific output result (file path, response object, etc.)
    """
    ...

from_args(args) abstractmethod classmethod

Create an output formatter instance from output arguments.

Parameters:

Name Type Description Default
args BenchmarkOutputArgs

Output configuration arguments

required

Returns:

Type Description
GenerativeBenchmarkerOutput

Configured output formatter instance

Source code in src/guidellm/benchmark/outputs/output.py
@classmethod
@abstractmethod
def from_args(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerOutput:
    """
    Create an output formatter instance from output arguments.

    :param args: Output configuration arguments
    :return: Configured output formatter instance
    """
    ...

resolve(args) classmethod

Resolve output arguments into a formatter instance.

Looks up the registered output class by args.kind and delegates construction to its :meth:from_args factory.

Parameters:

Name Type Description Default
args BenchmarkOutputArgs

Output configuration arguments with kind and format-specific fields

required

Returns:

Type Description
GenerativeBenchmarkerOutput

Configured output formatter instance

Raises:

Type Description
ValueError

If the output kind is not registered

Source code in src/guidellm/benchmark/outputs/output.py
@classmethod
def resolve(cls, args: BenchmarkOutputArgs) -> GenerativeBenchmarkerOutput:
    """
    Resolve output arguments into a formatter instance.

    Looks up the registered output class by ``args.kind`` and delegates
    construction to its :meth:`from_args` factory.

    :param args: Output configuration arguments with kind and format-specific fields
    :return: Configured output formatter instance
    :raises ValueError: If the output kind is not registered
    """
    output_class = cls.get_registered_object(args.kind)
    if output_class is None:
        available_formats = list(cls.registry.keys()) if cls.registry else []
        raise ValueError(
            f"Output format '{args.kind}' is not registered. "
            f"Available formats: {available_formats}"
        )
    return output_class.from_args(args)

GenerativeBenchmarksReport

Bases: StandardBaseModel

Container for multiple benchmark results with load/save functionality.

Aggregates multiple generative benchmark executions into a single report, providing persistence through JSON and YAML file formats. Enables result collection, storage, and retrieval across different execution sessions with automatic file type detection and path resolution.

Attributes:

Name Type Description
DEFAULT_FILE str

Default filename used when saving to or loading from a directory

Source code in src/guidellm/benchmark/schemas/report.py
class GenerativeBenchmarksReport(StandardBaseModel):
    """Container for multiple benchmark results with load/save functionality.

    Aggregates multiple generative benchmark executions into a single report,
    providing persistence through JSON and YAML file formats. Enables result
    collection, storage, and retrieval across different execution sessions with
    automatic file type detection and path resolution.

    :cvar DEFAULT_FILE: Default filename used when saving to or loading from a directory
    """

    DEFAULT_FILE: ClassVar[str] = "benchmarks.json"

    metadata: GenerativeBenchmarkMetadata = Field(
        description="Metadata about the benchmark report and execution environment",
        default_factory=GenerativeBenchmarkMetadata,
    )
    config: BenchmarkScenario = Field(
        description="Benchmark arguments used for all benchmarks in the report"
    )
    benchmarks: list[GenerativeBenchmark] = Field(
        description="List of completed benchmarks in the report",
        default_factory=list,
    )

    def save_file(
        self,
        path: str | Path | None = None,
        type_: Literal["json", "yaml"] | None = None,
    ) -> Path:
        """
        Save report to file in JSON or YAML format.

        :param path: File path or directory for saving, defaults to current directory
            with DEFAULT_FILE name
        :param type_: File format override ('json' or 'yaml'), auto-detected from
            extension if None
        :return: Resolved path to the saved file
        :raises ValueError: If file type is unsupported or cannot be determined
        """
        file_path = GenerativeBenchmarksReport._resolve_path(
            path if path is not None else Path.cwd()
        )
        file_path.parent.mkdir(parents=True, exist_ok=True)
        file_type = type_ or file_path.suffix.lower()[1:]
        model_dict = self.model_dump(mode="json")
        if file_type == "json":
            save_str = json.dumps(model_dict)
        elif file_type in ["yaml", "yml"]:
            save_str = yaml.dump(model_dict)
        else:
            raise ValueError(f"Unsupported file type: {file_type} for {file_path}.")

        with file_path.open("w") as file:
            file.write(save_str)

        return file_path

    @classmethod
    def load_file(
        cls, path: str | Path, type_: Literal["json", "yaml"] | None = None
    ) -> GenerativeBenchmarksReport:
        """
        Load report from JSON or YAML file.

        :param path: File path or directory containing DEFAULT_FILE to load from
        :param type_: File format override ('json' or 'yaml'), auto-detected from
            extension if None
        :return: Loaded report instance with benchmarks and configuration
        :raises ValueError: If file type is unsupported or cannot be determined
        :raises FileNotFoundError: If specified file does not exist
        """
        file_path = GenerativeBenchmarksReport._resolve_path(path)
        file_type = type_ or file_path.suffix.lower()[1:]

        with file_path.open("r") as file:
            if file_type == "json":
                model_dict = json.loads(file.read())
            elif file_type in ["yaml", "yml"]:
                model_dict = yaml.safe_load(file)
            else:
                raise ValueError(f"Unsupported file type: {file_type} for {file_path}.")

        return GenerativeBenchmarksReport.model_validate(model_dict)

    @classmethod
    def _resolve_path(cls, path: str | Path) -> Path:
        """
        Resolve input to file path, converting directories to DEFAULT_FILE location.

        :param path: String or Path to resolve, directories append DEFAULT_FILE
        :return: Resolved file path
        """
        resolved = Path(path) if not isinstance(path, Path) else path

        if resolved.is_dir():
            resolved = resolved / GenerativeBenchmarksReport.DEFAULT_FILE

        return resolved

load_file(path, type_=None) classmethod

Load report from JSON or YAML file.

Parameters:

Name Type Description Default
path str | Path

File path or directory containing DEFAULT_FILE to load from

required
type_ Literal['json', 'yaml'] | None

File format override ('json' or 'yaml'), auto-detected from extension if None

None

Returns:

Type Description
GenerativeBenchmarksReport

Loaded report instance with benchmarks and configuration

Raises:

Type Description
ValueError

If file type is unsupported or cannot be determined

FileNotFoundError

If specified file does not exist

Source code in src/guidellm/benchmark/schemas/report.py
@classmethod
def load_file(
    cls, path: str | Path, type_: Literal["json", "yaml"] | None = None
) -> GenerativeBenchmarksReport:
    """
    Load report from JSON or YAML file.

    :param path: File path or directory containing DEFAULT_FILE to load from
    :param type_: File format override ('json' or 'yaml'), auto-detected from
        extension if None
    :return: Loaded report instance with benchmarks and configuration
    :raises ValueError: If file type is unsupported or cannot be determined
    :raises FileNotFoundError: If specified file does not exist
    """
    file_path = GenerativeBenchmarksReport._resolve_path(path)
    file_type = type_ or file_path.suffix.lower()[1:]

    with file_path.open("r") as file:
        if file_type == "json":
            model_dict = json.loads(file.read())
        elif file_type in ["yaml", "yml"]:
            model_dict = yaml.safe_load(file)
        else:
            raise ValueError(f"Unsupported file type: {file_type} for {file_path}.")

    return GenerativeBenchmarksReport.model_validate(model_dict)

save_file(path=None, type_=None)

Save report to file in JSON or YAML format.

Parameters:

Name Type Description Default
path str | Path | None

File path or directory for saving, defaults to current directory with DEFAULT_FILE name

None
type_ Literal['json', 'yaml'] | None

File format override ('json' or 'yaml'), auto-detected from extension if None

None

Returns:

Type Description
Path

Resolved path to the saved file

Raises:

Type Description
ValueError

If file type is unsupported or cannot be determined

Source code in src/guidellm/benchmark/schemas/report.py
def save_file(
    self,
    path: str | Path | None = None,
    type_: Literal["json", "yaml"] | None = None,
) -> Path:
    """
    Save report to file in JSON or YAML format.

    :param path: File path or directory for saving, defaults to current directory
        with DEFAULT_FILE name
    :param type_: File format override ('json' or 'yaml'), auto-detected from
        extension if None
    :return: Resolved path to the saved file
    :raises ValueError: If file type is unsupported or cannot be determined
    """
    file_path = GenerativeBenchmarksReport._resolve_path(
        path if path is not None else Path.cwd()
    )
    file_path.parent.mkdir(parents=True, exist_ok=True)
    file_type = type_ or file_path.suffix.lower()[1:]
    model_dict = self.model_dump(mode="json")
    if file_type == "json":
        save_str = json.dumps(model_dict)
    elif file_type in ["yaml", "yml"]:
        save_str = yaml.dump(model_dict)
    else:
        raise ValueError(f"Unsupported file type: {file_type} for {file_path}.")

    with file_path.open("w") as file:
        file.write(save_str)

    return file_path

GenerativeConsoleBenchmarkerProgress

Bases: BenchmarkerProgress[GenerativeBenchmarkAccumulator, GenerativeBenchmark], Live

Console-based real-time progress display for generative benchmarks.

Renders live benchmark execution statistics using Rich library components with structured progress bars, timing information, request/token metrics, and optional scheduler statistics. Updates refresh automatically during benchmark execution.

Attributes:

Name Type Description
display_scheduler_stats bool

Whether to include scheduler statistics in display

Source code in src/guidellm/benchmark/progress.py
class GenerativeConsoleBenchmarkerProgress(
    BenchmarkerProgress[GenerativeBenchmarkAccumulator, GenerativeBenchmark], Live
):
    """
    Console-based real-time progress display for generative benchmarks.

    Renders live benchmark execution statistics using Rich library components with
    structured progress bars, timing information, request/token metrics, and optional
    scheduler statistics. Updates refresh automatically during benchmark execution.

    :cvar display_scheduler_stats: Whether to include scheduler statistics in display
    """

    def __init__(self, display_scheduler_stats: bool = False):
        """
        Initialize console progress display with rendering configuration.

        :param display_scheduler_stats: Whether to display scheduler timing statistics
        """
        super().__init__()
        Live.__init__(
            self,
            refresh_per_second=4,
            auto_refresh=True,
            redirect_stdout=True,
            redirect_stderr=True,
        )
        self.display_scheduler_stats: bool = display_scheduler_stats
        self.run_progress: Progress | None = None
        self.run_progress_task: TaskID | None = None
        self.tasks_progress: _GenerativeProgressTasks | None = None

    async def on_initialize(self, profile: Profile):
        """
        Initialize console display components and begin live rendering.

        :param profile: Benchmark profile configuration defining execution parameters
        """
        self.tasks_progress = _GenerativeProgressTasks(
            profile=profile, display_scheduler_stats=self.display_scheduler_stats
        )
        self.run_progress = Progress(
            TextColumn("Generating...", style=f"italic {Colors.progress}"),
            BarColumn(
                bar_width=None,
                complete_style=Colors.progress,
                finished_style=Colors.success,
            ),
            TextColumn(
                "({task.fields[completed_benchmarks]}/{task.fields[total_benchmarks]})",
                style=Colors.progress,
            ),
            TextColumn("["),
            TimeElapsedColumn(),
            TextColumn("<"),
            TimeRemainingColumn(),
            TextColumn("]"),
            auto_refresh=False,
        )
        self.run_progress_task = self.run_progress.add_task("")
        self._sync_run_progress()
        self.update(
            Group(
                Panel(
                    self.tasks_progress,
                    title="Benchmarks",
                    title_align="left",
                    expand=True,
                ),
                self.run_progress,
            )
        )
        self.start()

    async def on_benchmark_start(self, strategy: SchedulingStrategy):
        """
        Update display for benchmark strategy execution start.

        :param strategy: Scheduling strategy configuration being executed
        """
        if self.tasks_progress is not None:
            self.tasks_progress.start_benchmark(strategy)
            self._sync_run_progress()

    async def on_benchmark_update(
        self,
        accumulator: GenerativeBenchmarkAccumulator,
        scheduler_state: SchedulerState,
    ):
        """
        Update display with current benchmark progress and metrics.

        :param accumulator: Current accumulated benchmark metrics and statistics
        :param scheduler_state: Current scheduler execution state and counters
        """
        if self.tasks_progress is not None:
            self.tasks_progress.update_benchmark(accumulator, scheduler_state)
            self._sync_run_progress()

    async def on_benchmark_complete(self, benchmark: GenerativeBenchmark):
        """
        Update display for completed benchmark strategy.

        :param benchmark: Completed benchmark results with final metrics
        """
        if self.tasks_progress is not None:
            self.tasks_progress.complete_benchmark(benchmark)
            self._sync_run_progress()

    async def on_finalize(self):
        """Stop display rendering and release resources."""
        if self.tasks_progress is not None:
            self.tasks_progress.finalize()
            self._sync_run_progress()
        if self.run_progress is not None and self.run_progress_task is not None:
            self.run_progress.stop_task(self.run_progress_task)
        self.stop()
        self.run_progress = None
        self.run_progress_task = None
        self.tasks_progress = None

    def _sync_run_progress(self):
        """Synchronize overall progress display with task progress."""
        if (
            self.run_progress is not None
            and self.run_progress_task is not None
            and self.tasks_progress is not None
        ):
            self.run_progress.update(
                self.run_progress_task,
                total=self.tasks_progress.steps_total,
                completed=self.tasks_progress.steps_progress,
                completed_benchmarks=self.tasks_progress.tasks_progress,
                total_benchmarks=self.tasks_progress.tasks_total,
            )

__init__(display_scheduler_stats=False)

Initialize console progress display with rendering configuration.

Parameters:

Name Type Description Default
display_scheduler_stats bool

Whether to display scheduler timing statistics

False
Source code in src/guidellm/benchmark/progress.py
def __init__(self, display_scheduler_stats: bool = False):
    """
    Initialize console progress display with rendering configuration.

    :param display_scheduler_stats: Whether to display scheduler timing statistics
    """
    super().__init__()
    Live.__init__(
        self,
        refresh_per_second=4,
        auto_refresh=True,
        redirect_stdout=True,
        redirect_stderr=True,
    )
    self.display_scheduler_stats: bool = display_scheduler_stats
    self.run_progress: Progress | None = None
    self.run_progress_task: TaskID | None = None
    self.tasks_progress: _GenerativeProgressTasks | None = None

on_benchmark_complete(benchmark) async

Update display for completed benchmark strategy.

Parameters:

Name Type Description Default
benchmark GenerativeBenchmark

Completed benchmark results with final metrics

required
Source code in src/guidellm/benchmark/progress.py
async def on_benchmark_complete(self, benchmark: GenerativeBenchmark):
    """
    Update display for completed benchmark strategy.

    :param benchmark: Completed benchmark results with final metrics
    """
    if self.tasks_progress is not None:
        self.tasks_progress.complete_benchmark(benchmark)
        self._sync_run_progress()

on_benchmark_start(strategy) async

Update display for benchmark strategy execution start.

Parameters:

Name Type Description Default
strategy SchedulingStrategy

Scheduling strategy configuration being executed

required
Source code in src/guidellm/benchmark/progress.py
async def on_benchmark_start(self, strategy: SchedulingStrategy):
    """
    Update display for benchmark strategy execution start.

    :param strategy: Scheduling strategy configuration being executed
    """
    if self.tasks_progress is not None:
        self.tasks_progress.start_benchmark(strategy)
        self._sync_run_progress()

on_benchmark_update(accumulator, scheduler_state) async

Update display with current benchmark progress and metrics.

Parameters:

Name Type Description Default
accumulator GenerativeBenchmarkAccumulator

Current accumulated benchmark metrics and statistics

required
scheduler_state SchedulerState

Current scheduler execution state and counters

required
Source code in src/guidellm/benchmark/progress.py
async def on_benchmark_update(
    self,
    accumulator: GenerativeBenchmarkAccumulator,
    scheduler_state: SchedulerState,
):
    """
    Update display with current benchmark progress and metrics.

    :param accumulator: Current accumulated benchmark metrics and statistics
    :param scheduler_state: Current scheduler execution state and counters
    """
    if self.tasks_progress is not None:
        self.tasks_progress.update_benchmark(accumulator, scheduler_state)
        self._sync_run_progress()

on_finalize() async

Stop display rendering and release resources.

Source code in src/guidellm/benchmark/progress.py
async def on_finalize(self):
    """Stop display rendering and release resources."""
    if self.tasks_progress is not None:
        self.tasks_progress.finalize()
        self._sync_run_progress()
    if self.run_progress is not None and self.run_progress_task is not None:
        self.run_progress.stop_task(self.run_progress_task)
    self.stop()
    self.run_progress = None
    self.run_progress_task = None
    self.tasks_progress = None

on_initialize(profile) async

Initialize console display components and begin live rendering.

Parameters:

Name Type Description Default
profile Profile

Benchmark profile configuration defining execution parameters

required
Source code in src/guidellm/benchmark/progress.py
async def on_initialize(self, profile: Profile):
    """
    Initialize console display components and begin live rendering.

    :param profile: Benchmark profile configuration defining execution parameters
    """
    self.tasks_progress = _GenerativeProgressTasks(
        profile=profile, display_scheduler_stats=self.display_scheduler_stats
    )
    self.run_progress = Progress(
        TextColumn("Generating...", style=f"italic {Colors.progress}"),
        BarColumn(
            bar_width=None,
            complete_style=Colors.progress,
            finished_style=Colors.success,
        ),
        TextColumn(
            "({task.fields[completed_benchmarks]}/{task.fields[total_benchmarks]})",
            style=Colors.progress,
        ),
        TextColumn("["),
        TimeElapsedColumn(),
        TextColumn("<"),
        TimeRemainingColumn(),
        TextColumn("]"),
        auto_refresh=False,
    )
    self.run_progress_task = self.run_progress.add_task("")
    self._sync_run_progress()
    self.update(
        Group(
            Panel(
                self.tasks_progress,
                title="Benchmarks",
                title_align="left",
                expand=True,
            ),
            self.run_progress,
        )
    )
    self.start()

GenerativeImageMetricsSummary

Bases: StandardBaseDict

Image-specific metric summaries for generative benchmarks.

Tracks token, image count, pixel, and byte-level metrics across input, output, and total usage for image generation workloads.

Source code in src/guidellm/benchmark/schemas/metrics.py
class GenerativeImageMetricsSummary(StandardBaseDict):
    """
    Image-specific metric summaries for generative benchmarks.

    Tracks token, image count, pixel, and byte-level metrics across input, output,
    and total usage for image generation workloads.
    """

    tokens: GenerativeMetricsSummary | None = Field(
        description="Image token count metrics and distributions"
    )
    images: GenerativeMetricsSummary | None = Field(
        description="Image count metrics and distributions"
    )
    pixels: GenerativeMetricsSummary | None = Field(
        description="Pixel count metrics and distributions"
    )
    bytes: GenerativeMetricsSummary | None = Field(
        description="Byte size metrics and distributions"
    )

    @classmethod
    def compile(
        cls,
        successful: list[GenerativeRequestStats],
        incomplete: list[GenerativeRequestStats],
        errored: list[GenerativeRequestStats],
    ) -> GenerativeImageMetricsSummary:
        """
        Compile image metrics summary from request statistics.

        :param successful: Successfully completed request statistics
        :param incomplete: Incomplete/cancelled request statistics
        :param errored: Failed request statistics
        :return: Compiled image metrics summary
        """
        return GenerativeImageMetricsSummary(
            tokens=GenerativeMetricsSummary.compile(
                property_name="image_tokens",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            images=GenerativeMetricsSummary.compile(
                property_name="image_count",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            pixels=GenerativeMetricsSummary.compile(
                property_name="image_pixels",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            bytes=GenerativeMetricsSummary.compile(
                property_name="image_bytes",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
        )

compile(successful, incomplete, errored) classmethod

Compile image metrics summary from request statistics.

Parameters:

Name Type Description Default
successful list[GenerativeRequestStats]

Successfully completed request statistics

required
incomplete list[GenerativeRequestStats]

Incomplete/cancelled request statistics

required
errored list[GenerativeRequestStats]

Failed request statistics

required

Returns:

Type Description
GenerativeImageMetricsSummary

Compiled image metrics summary

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile(
    cls,
    successful: list[GenerativeRequestStats],
    incomplete: list[GenerativeRequestStats],
    errored: list[GenerativeRequestStats],
) -> GenerativeImageMetricsSummary:
    """
    Compile image metrics summary from request statistics.

    :param successful: Successfully completed request statistics
    :param incomplete: Incomplete/cancelled request statistics
    :param errored: Failed request statistics
    :return: Compiled image metrics summary
    """
    return GenerativeImageMetricsSummary(
        tokens=GenerativeMetricsSummary.compile(
            property_name="image_tokens",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        images=GenerativeMetricsSummary.compile(
            property_name="image_count",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        pixels=GenerativeMetricsSummary.compile(
            property_name="image_pixels",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        bytes=GenerativeMetricsSummary.compile(
            property_name="image_bytes",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
    )

GenerativeMetrics

Bases: StandardBaseDict

Comprehensive metrics for generative AI benchmarks.

Aggregates request statistics, token metrics, timing distributions, and domain-specific measurements across text, image, video, and audio modalities. Provides detailed statistical summaries including distribution analysis for throughput, latency, concurrency, and resource utilization metrics across successful, incomplete, and errored requests.

Source code in src/guidellm/benchmark/schemas/metrics.py
class GenerativeMetrics(StandardBaseDict):
    """
    Comprehensive metrics for generative AI benchmarks.

    Aggregates request statistics, token metrics, timing distributions, and
    domain-specific measurements across text, image, video, and audio modalities.
    Provides detailed statistical summaries including distribution analysis for
    throughput, latency, concurrency, and resource utilization metrics across
    successful, incomplete, and errored requests.
    """

    # Request stats
    request_totals: StatusBreakdown[int, int, int, int] = Field(
        description="Request counts by status: successful, incomplete, errored, total"
    )
    requests_per_second: StatusDistributionSummary = Field(
        description="Distribution of requests per second across benchmark execution"
    )
    request_concurrency: StatusDistributionSummary = Field(
        description="Distribution of concurrent request counts during execution"
    )
    request_latency: StatusDistributionSummary = Field(
        description="Distribution of request latencies for completed requests"
    )
    request_streaming_iterations_count: StatusDistributionSummary = Field(
        description="Distribution of stream iterations for completed requests"
    )

    # General token stats
    prompt_token_count: StatusDistributionSummary = Field(
        description="Distribution of prompt token counts by request status"
    )
    output_token_count: StatusDistributionSummary = Field(
        description="Distribution of output token counts by request status"
    )
    total_token_count: StatusDistributionSummary = Field(
        description="Distribution of total token counts by request status"
    )
    time_to_first_token_ms: StatusDistributionSummary = Field(
        description="Distribution of first token latencies in milliseconds"
    )
    time_to_first_output_token_ms: StatusDistributionSummary = Field(
        description=(
            "Distribution of first content (non-reasoning) token latencies "
            "in milliseconds"
        )
    )
    time_per_output_token_ms: StatusDistributionSummary = Field(
        description="Distribution of average time per output token in milliseconds"
    )
    inter_token_latency_ms: StatusDistributionSummary = Field(
        description="Distribution of inter-token latencies in milliseconds"
    )
    prompt_tokens_per_second: StatusDistributionSummary = Field(
        description="Distribution of prompt token processing rates"
    )
    output_tokens_per_second: StatusDistributionSummary = Field(
        description="Distribution of output token generation rates"
    )
    tokens_per_second: StatusDistributionSummary = Field(
        description="Distribution of total token throughput including prompt and output"
    )
    output_tokens_per_iteration: StatusDistributionSummary = Field(
        description="Distribution of output tokens generated per streaming iteration"
    )
    iter_tokens_per_iteration: StatusDistributionSummary = Field(
        description=(
            "Distribution of output tokens (without first) generated per "
            "streaming iteration"
        )
    )

    # Domain specific stats
    text: GenerativeTextMetricsSummary = Field(
        description="Text-specific metrics for tokens, words, and characters"
    )
    image: GenerativeImageMetricsSummary = Field(
        description="Image-specific metrics for tokens, images, pixels, and bytes"
    )
    video: GenerativeVideoMetricsSummary = Field(
        description="Video-specific metrics for tokens, frames, duration, and bytes"
    )
    audio: GenerativeAudioMetricsSummary = Field(
        description="Audio-specific metrics for tokens, samples, duration, and bytes"
    )
    tool_call: GenerativeToolCallMetricsSummary = Field(
        description="Tool call metrics for tokens and call counts"
    )

    @classmethod
    def compile(cls, accumulator: GenerativeBenchmarkAccumulator) -> GenerativeMetrics:
        """
        Compile comprehensive generative metrics from benchmark accumulator.

        :param accumulator: Benchmark accumulator with completed request statistics
        :return: Compiled generative metrics with all distributions and summaries
        :raises ValueError: If measure_start and measure_end/request_end are not set
        """
        start_time = accumulator.timings.finalized_measure_start
        end_time = accumulator.timings.finalized_measure_end

        if start_time == -1.0 or end_time == -1.0:
            raise ValueError(
                "Cannot compile GenerativeMetrics: "
                "No measurement start or end times available."
            )

        successful = accumulator.completed.get_within_range(start_time, end_time)
        incomplete = accumulator.incomplete.get_within_range(start_time, end_time)
        errored = accumulator.errored.get_within_range(start_time, end_time)

        return GenerativeMetrics(
            # Request stats
            request_totals=StatusBreakdown(
                successful=len(successful),
                incomplete=len(incomplete),
                errored=len(errored),
                total=(len(successful) + len(incomplete) + len(errored)),
            ),
            requests_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
                function=lambda req: req.request_end_time,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
                start_time=start_time,
                end_time=end_time,
            ),
            request_concurrency=StatusDistributionSummary.concurrency_distribution_from_timings_function(
                function=(
                    lambda req: (
                        (req.request_start_time, req.request_end_time)
                        if req.request_start_time is not None
                        and req.request_end_time is not None
                        else None
                    )
                ),
                successful=successful,
                incomplete=incomplete,
                errored=errored,
                start_time=start_time,
                end_time=end_time,
            ),
            request_latency=StatusDistributionSummary.from_values_function(
                function=lambda req: req.request_latency or 0.0,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            request_streaming_iterations_count=StatusDistributionSummary.from_values_function(
                function=lambda req: req.info.timings.request_iterations or 0.0,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            # General token stats
            prompt_token_count=StatusDistributionSummary.from_values_function(
                function=lambda req: req.prompt_tokens or 0.0,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            output_token_count=StatusDistributionSummary.from_values_function(
                function=lambda req: req.output_tokens or 0.0,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            total_token_count=StatusDistributionSummary.from_values_function(
                function=lambda req: req.total_tokens or 0.0,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            time_to_first_token_ms=StatusDistributionSummary.from_values_function(
                function=lambda req: req.time_to_first_token_ms or 0.0,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            time_to_first_output_token_ms=StatusDistributionSummary.from_values_function(
                function=lambda req: req.time_to_first_output_token_ms or 0.0,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            time_per_output_token_ms=StatusDistributionSummary.from_values_function(
                function=lambda req: (
                    req.time_per_output_token_ms or 0.0,
                    req.output_tokens or 0.0,
                ),
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            inter_token_latency_ms=StatusDistributionSummary.from_values_function(
                function=lambda req: (
                    req.inter_token_latency_ms or 0.0,
                    (req.output_tokens or 1.0) - 1.0,
                ),
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            prompt_tokens_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
                function=lambda req: req.prompt_tokens_timing,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            output_tokens_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
                function=lambda req: req.output_tokens_timings,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            tokens_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
                function=lambda req: req.total_tokens_timings,
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            output_tokens_per_iteration=StatusDistributionSummary.from_values_function(
                function=lambda req: [
                    tokens for (_timing, tokens) in req.output_tokens_timings
                ],
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            iter_tokens_per_iteration=StatusDistributionSummary.from_values_function(
                function=lambda req: [
                    tokens for (_timing, tokens) in req.iter_tokens_timings
                ],
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            # Domain-specific stats
            text=GenerativeTextMetricsSummary.compile(
                successful=successful, incomplete=incomplete, errored=errored
            ),
            image=GenerativeImageMetricsSummary.compile(
                successful=successful, incomplete=incomplete, errored=errored
            ),
            video=GenerativeVideoMetricsSummary.compile(
                successful=successful, incomplete=incomplete, errored=errored
            ),
            audio=GenerativeAudioMetricsSummary.compile(
                successful=successful, incomplete=incomplete, errored=errored
            ),
            tool_call=GenerativeToolCallMetricsSummary.compile(
                successful=successful, incomplete=incomplete, errored=errored
            ),
        )

compile(accumulator) classmethod

Compile comprehensive generative metrics from benchmark accumulator.

Parameters:

Name Type Description Default
accumulator GenerativeBenchmarkAccumulator

Benchmark accumulator with completed request statistics

required

Returns:

Type Description
GenerativeMetrics

Compiled generative metrics with all distributions and summaries

Raises:

Type Description
ValueError

If measure_start and measure_end/request_end are not set

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile(cls, accumulator: GenerativeBenchmarkAccumulator) -> GenerativeMetrics:
    """
    Compile comprehensive generative metrics from benchmark accumulator.

    :param accumulator: Benchmark accumulator with completed request statistics
    :return: Compiled generative metrics with all distributions and summaries
    :raises ValueError: If measure_start and measure_end/request_end are not set
    """
    start_time = accumulator.timings.finalized_measure_start
    end_time = accumulator.timings.finalized_measure_end

    if start_time == -1.0 or end_time == -1.0:
        raise ValueError(
            "Cannot compile GenerativeMetrics: "
            "No measurement start or end times available."
        )

    successful = accumulator.completed.get_within_range(start_time, end_time)
    incomplete = accumulator.incomplete.get_within_range(start_time, end_time)
    errored = accumulator.errored.get_within_range(start_time, end_time)

    return GenerativeMetrics(
        # Request stats
        request_totals=StatusBreakdown(
            successful=len(successful),
            incomplete=len(incomplete),
            errored=len(errored),
            total=(len(successful) + len(incomplete) + len(errored)),
        ),
        requests_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
            function=lambda req: req.request_end_time,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
            start_time=start_time,
            end_time=end_time,
        ),
        request_concurrency=StatusDistributionSummary.concurrency_distribution_from_timings_function(
            function=(
                lambda req: (
                    (req.request_start_time, req.request_end_time)
                    if req.request_start_time is not None
                    and req.request_end_time is not None
                    else None
                )
            ),
            successful=successful,
            incomplete=incomplete,
            errored=errored,
            start_time=start_time,
            end_time=end_time,
        ),
        request_latency=StatusDistributionSummary.from_values_function(
            function=lambda req: req.request_latency or 0.0,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        request_streaming_iterations_count=StatusDistributionSummary.from_values_function(
            function=lambda req: req.info.timings.request_iterations or 0.0,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        # General token stats
        prompt_token_count=StatusDistributionSummary.from_values_function(
            function=lambda req: req.prompt_tokens or 0.0,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        output_token_count=StatusDistributionSummary.from_values_function(
            function=lambda req: req.output_tokens or 0.0,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        total_token_count=StatusDistributionSummary.from_values_function(
            function=lambda req: req.total_tokens or 0.0,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        time_to_first_token_ms=StatusDistributionSummary.from_values_function(
            function=lambda req: req.time_to_first_token_ms or 0.0,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        time_to_first_output_token_ms=StatusDistributionSummary.from_values_function(
            function=lambda req: req.time_to_first_output_token_ms or 0.0,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        time_per_output_token_ms=StatusDistributionSummary.from_values_function(
            function=lambda req: (
                req.time_per_output_token_ms or 0.0,
                req.output_tokens or 0.0,
            ),
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        inter_token_latency_ms=StatusDistributionSummary.from_values_function(
            function=lambda req: (
                req.inter_token_latency_ms or 0.0,
                (req.output_tokens or 1.0) - 1.0,
            ),
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        prompt_tokens_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
            function=lambda req: req.prompt_tokens_timing,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        output_tokens_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
            function=lambda req: req.output_tokens_timings,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        tokens_per_second=StatusDistributionSummary.rate_distribution_from_timings_function(
            function=lambda req: req.total_tokens_timings,
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        output_tokens_per_iteration=StatusDistributionSummary.from_values_function(
            function=lambda req: [
                tokens for (_timing, tokens) in req.output_tokens_timings
            ],
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        iter_tokens_per_iteration=StatusDistributionSummary.from_values_function(
            function=lambda req: [
                tokens for (_timing, tokens) in req.iter_tokens_timings
            ],
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        # Domain-specific stats
        text=GenerativeTextMetricsSummary.compile(
            successful=successful, incomplete=incomplete, errored=errored
        ),
        image=GenerativeImageMetricsSummary.compile(
            successful=successful, incomplete=incomplete, errored=errored
        ),
        video=GenerativeVideoMetricsSummary.compile(
            successful=successful, incomplete=incomplete, errored=errored
        ),
        audio=GenerativeAudioMetricsSummary.compile(
            successful=successful, incomplete=incomplete, errored=errored
        ),
        tool_call=GenerativeToolCallMetricsSummary.compile(
            successful=successful, incomplete=incomplete, errored=errored
        ),
    )

GenerativeMetricsAccumulator

Bases: StandardBaseModel

Accumulates generative model performance metrics during execution.

Tracks token throughput, latency characteristics, and request timing for generative workloads. Maintains running statistics for input/output tokens, time-to-first-token, inter-token latency, and streaming patterns for comprehensive performance analysis.

Source code in src/guidellm/benchmark/schemas/accumulator.py
class GenerativeMetricsAccumulator(StandardBaseModel):
    """
    Accumulates generative model performance metrics during execution.

    Tracks token throughput, latency characteristics, and request timing for generative
    workloads. Maintains running statistics for input/output tokens,
    time-to-first-token, inter-token latency, and streaming patterns for comprehensive
    performance analysis.
    """

    requests: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated request count statistics",
    )
    request_latency: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated request latency statistics",
    )
    prompt_tokens: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated input token count statistics",
    )
    output_tokens: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated output token count statistics",
    )
    total_tokens: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated total token count statistics",
    )
    time_to_first_token_ms: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated time to first token statistics in milliseconds",
    )
    time_to_first_output_token_ms: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated time to first content token stats in ms",
    )
    time_per_output_token_ms: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated time per output token statistics in milliseconds",
    )
    inter_token_latency_ms: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated inter-token latency statistics in milliseconds",
    )
    streaming_iterations: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated streaming iteration count statistics",
    )
    output_tokens_by_iteration: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated output tokens per iteration statistics",
    )
    iter_tokens_by_iteration: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Accumulated iteration tokens per iteration statistics",
    )

    def update_estimate(self, stats: GenerativeRequestStats, duration: float):
        """
        Update generative metrics with completed request statistics.

        Incorporates token counts, latency measurements, and streaming characteristics
        from a completed request into running metric accumulators with time-weighted
        calculations.

        :param stats: Request statistics containing token and latency measurements
        :param duration: Current benchmark duration for time-weighted metrics
        """
        self.requests.update_estimate(1.0, duration=duration)
        self.prompt_tokens.update_estimate(stats.prompt_tokens, duration=duration)
        self.output_tokens.update_estimate(stats.output_tokens, duration=duration)
        self.total_tokens.update_estimate(stats.total_tokens, duration=duration)
        self.request_latency.update_estimate(stats.request_latency, duration=duration)
        self.time_to_first_token_ms.update_estimate(
            stats.time_to_first_token_ms, duration=duration
        )
        self.time_to_first_output_token_ms.update_estimate(
            stats.time_to_first_output_token_ms, duration=duration
        )
        self.time_per_output_token_ms.update_estimate(
            stats.time_per_output_token_ms,
            count=int(stats.output_tokens or 0),
            duration=duration,
        )
        self.inter_token_latency_ms.update_estimate(
            stats.inter_token_latency_ms,
            count=int((stats.output_tokens or 1) - 1),
            duration=duration,
        )
        self.streaming_iterations.update_estimate(
            stats.token_iterations, duration=duration
        )
        self.output_tokens_by_iteration.update_estimate(
            stats.output_tokens_per_iteration,
            count=int(stats.token_iterations or 0),
            duration=duration,
        )
        self.iter_tokens_by_iteration.update_estimate(
            stats.iter_tokens_per_iteration,
            count=int((stats.token_iterations or 1) - 1),
            duration=duration,
        )

update_estimate(stats, duration)

Update generative metrics with completed request statistics.

Incorporates token counts, latency measurements, and streaming characteristics from a completed request into running metric accumulators with time-weighted calculations.

Parameters:

Name Type Description Default
stats GenerativeRequestStats

Request statistics containing token and latency measurements

required
duration float

Current benchmark duration for time-weighted metrics

required
Source code in src/guidellm/benchmark/schemas/accumulator.py
def update_estimate(self, stats: GenerativeRequestStats, duration: float):
    """
    Update generative metrics with completed request statistics.

    Incorporates token counts, latency measurements, and streaming characteristics
    from a completed request into running metric accumulators with time-weighted
    calculations.

    :param stats: Request statistics containing token and latency measurements
    :param duration: Current benchmark duration for time-weighted metrics
    """
    self.requests.update_estimate(1.0, duration=duration)
    self.prompt_tokens.update_estimate(stats.prompt_tokens, duration=duration)
    self.output_tokens.update_estimate(stats.output_tokens, duration=duration)
    self.total_tokens.update_estimate(stats.total_tokens, duration=duration)
    self.request_latency.update_estimate(stats.request_latency, duration=duration)
    self.time_to_first_token_ms.update_estimate(
        stats.time_to_first_token_ms, duration=duration
    )
    self.time_to_first_output_token_ms.update_estimate(
        stats.time_to_first_output_token_ms, duration=duration
    )
    self.time_per_output_token_ms.update_estimate(
        stats.time_per_output_token_ms,
        count=int(stats.output_tokens or 0),
        duration=duration,
    )
    self.inter_token_latency_ms.update_estimate(
        stats.inter_token_latency_ms,
        count=int((stats.output_tokens or 1) - 1),
        duration=duration,
    )
    self.streaming_iterations.update_estimate(
        stats.token_iterations, duration=duration
    )
    self.output_tokens_by_iteration.update_estimate(
        stats.output_tokens_per_iteration,
        count=int(stats.token_iterations or 0),
        duration=duration,
    )
    self.iter_tokens_by_iteration.update_estimate(
        stats.iter_tokens_per_iteration,
        count=int((stats.token_iterations or 1) - 1),
        duration=duration,
    )

GenerativeMetricsSummary

Bases: StandardBaseDict

Statistical summaries for input, output, and total metrics.

Provides distribution summaries across successful, incomplete, and errored requests for absolute values, per-second rates, and concurrency levels.

Source code in src/guidellm/benchmark/schemas/metrics.py
class GenerativeMetricsSummary(StandardBaseDict):
    """
    Statistical summaries for input, output, and total metrics.

    Provides distribution summaries across successful, incomplete, and errored
    requests for absolute values, per-second rates, and concurrency levels.
    """

    input: StatusDistributionSummary | None = Field(
        description="Distribution of input metric values"
    )
    input_per_second: StatusDistributionSummary | None = Field(
        description="Distribution of input metric rates per second"
    )
    input_concurrency: StatusDistributionSummary | None = Field(
        description="Distribution of concurrent input metric values"
    )

    output: StatusDistributionSummary | None = Field(
        description="Distribution of output metric values"
    )
    output_per_second: StatusDistributionSummary | None = Field(
        description="Distribution of output metric rates per second"
    )
    output_concurrency: StatusDistributionSummary | None = Field(
        description="Distribution of concurrent output metric values"
    )

    total: StatusDistributionSummary | None = Field(
        description="Distribution of total metric values (input + output)"
    )
    total_per_second: StatusDistributionSummary | None = Field(
        description="Distribution of total metric rates per second"
    )
    total_concurrency: StatusDistributionSummary | None = Field(
        description="Distribution of concurrent total metric values"
    )

    @classmethod
    def compile(
        cls,
        property_name: str,
        successful: list[GenerativeRequestStats],
        incomplete: list[GenerativeRequestStats],
        errored: list[GenerativeRequestStats],
    ) -> GenerativeMetricsSummary | None:
        """
        Compile metrics summary from request statistics for a specific property.

        :param property_name: Name of the property to extract from request metrics
        :param successful: Successfully completed request statistics
        :param incomplete: Incomplete or cancelled request statistics
        :param errored: Failed request statistics
        :return: Compiled metrics summary or None if no data available
        """
        successful_metrics = cls.extract_property_metrics_for_summary(
            successful, property_name
        )
        incomplete_metrics = cls.extract_property_metrics_for_summary(
            incomplete, property_name
        )
        errored_metrics = cls.extract_property_metrics_for_summary(
            errored, property_name
        )

        return cls.compile_timed_metrics(
            successful=successful_metrics,
            incomplete=incomplete_metrics,
            errored=errored_metrics,
        )

    @classmethod
    def compile_timed_metrics(
        cls,
        successful: list[TimedMetricTypeAlias],
        incomplete: list[TimedMetricTypeAlias],
        errored: list[TimedMetricTypeAlias],
    ) -> GenerativeMetricsSummary | None:
        """
        Compile metrics summary from timed metric tuples.

        :param successful: Timed metrics from successful requests
        :param incomplete: Timed metrics from incomplete requests
        :param errored: Timed metrics from errored requests
        :return: Compiled metrics summary or None if no data available
        """

        def _compile_metric_distributions(
            metrics_by_status: dict[StatusTypes, list[TimedMetricTypeAlias]],
            value_index: int,
        ) -> tuple[
            StatusDistributionSummary | None,
            StatusDistributionSummary | None,
            StatusDistributionSummary | None,
            dict[StatusTypes, list[float]],
            dict[StatusTypes, list[tuple[float, float]]],
            dict[StatusTypes, list[tuple[float, float, float]]],
        ]:
            """Helper to compile value, rate, and concurrency distributions."""
            # Filter out None values instead of coercing to 0.0 so we can
            # distinguish "metric not applicable" (None) from "metric is
            # zero" (e.g. errored tool call requests with tool_call_count=0).
            value_lists: dict[StatusTypes, list[float]] = {
                status: [
                    float(val)
                    for metric in metrics
                    if metric is not None
                    for val in [metric[value_index]]
                    if val is not None
                ]
                for status, metrics in metrics_by_status.items()
            }

            # No data at all for this value index — skip distributions.
            if all(len(vl) == 0 for vl in value_lists.values()):
                return None, None, None, value_lists, {}, {}

            value_dist = StatusDistributionSummary.from_values(
                successful=value_lists["successful"],
                incomplete=value_lists["incomplete"],
                errored=value_lists["errored"],
            )

            rate_lists: dict[StatusTypes, list[tuple[float, float]]] = {
                status: [
                    (  # type: ignore[misc]
                        metric[_TIMED_METRIC_END_TIME_INDEX],
                        float(metric[value_index] or 0.0),
                    )
                    for metric in metrics
                    if metric is not None
                ]
                for status, metrics in metrics_by_status.items()
            }
            rate_dist = StatusDistributionSummary.rate_distribution_from_timings(
                successful=rate_lists["successful"],
                incomplete=rate_lists["incomplete"],
                errored=rate_lists["errored"],
            )

            concurrency_lists: dict[StatusTypes, list[tuple[float, float, float]]] = {
                status: [
                    (  # type: ignore[misc]
                        metric[_TIMED_METRIC_START_TIME_INDEX],
                        metric[_TIMED_METRIC_END_TIME_INDEX],
                        float(metric[value_index] or 0.0),
                    )
                    for metric in metrics
                    if metric is not None
                ]
                for status, metrics in metrics_by_status.items()
            }
            concurrency_dist = (
                StatusDistributionSummary.concurrency_distribution_from_timings(
                    successful=concurrency_lists["successful"],
                    incomplete=concurrency_lists["incomplete"],
                    errored=concurrency_lists["errored"],
                )
            )

            return (
                value_dist,
                rate_dist,
                concurrency_dist,
                value_lists,
                rate_lists,
                concurrency_lists,
            )

        metrics_by_status: dict[StatusTypes, list[TimedMetricTypeAlias]] = {
            "successful": successful,
            "incomplete": incomplete,
            "errored": errored,
        }

        # Calculate input distributions
        (
            input_value_dist,
            input_rate_dist,
            input_concurrency_dist,
            input_value_lists,
            input_rate_lists,
            input_concurrency_lists,
        ) = _compile_metric_distributions(
            metrics_by_status, _TIMED_METRIC_INPUT_VALUE_INDEX
        )

        # Calculate output distributions
        (
            output_value_dist,
            output_rate_dist,
            output_concurrency_dist,
            output_value_lists,
            output_rate_lists,
            output_concurrency_lists,
        ) = _compile_metric_distributions(
            metrics_by_status, _TIMED_METRIC_OUTPUT_VALUE_INDEX
        )

        # Calculate total distributions if both input and output have data
        if input_value_dist is not None and output_value_dist is not None:
            total_value_dist = StatusDistributionSummary.from_values(
                successful=(
                    input_value_lists["successful"] + output_value_lists["successful"]
                ),
                incomplete=(
                    input_value_lists["incomplete"] + output_value_lists["incomplete"]
                ),
                errored=input_value_lists["errored"] + output_value_lists["errored"],
            )
            total_rate_dist = StatusDistributionSummary.rate_distribution_from_timings(
                successful=(
                    input_rate_lists["successful"] + output_rate_lists["successful"]
                ),
                incomplete=(
                    input_rate_lists["incomplete"] + output_rate_lists["incomplete"]
                ),
                errored=input_rate_lists["errored"] + output_rate_lists["errored"],
            )
            total_concurrency_dist = (
                StatusDistributionSummary.concurrency_distribution_from_timings(
                    successful=(
                        input_concurrency_lists["successful"]
                        + output_concurrency_lists["successful"]
                    ),
                    incomplete=(
                        input_concurrency_lists["incomplete"]
                        + output_concurrency_lists["incomplete"]
                    ),
                    errored=(
                        input_concurrency_lists["errored"]
                        + output_concurrency_lists["errored"]
                    ),
                )
            )
        else:
            total_value_dist = None
            total_rate_dist = None
            total_concurrency_dist = None

        return GenerativeMetricsSummary(
            input=input_value_dist,
            input_per_second=input_rate_dist,
            input_concurrency=input_concurrency_dist,
            output=output_value_dist,
            output_per_second=output_rate_dist,
            output_concurrency=output_concurrency_dist,
            total=total_value_dist,
            total_per_second=total_rate_dist,
            total_concurrency=total_concurrency_dist,
        )

    @classmethod
    def extract_property_metrics_for_summary(
        cls, stats_list: list[GenerativeRequestStats], property_name: str
    ) -> list[TimedMetricTypeAlias]:
        """
        Extract timed metrics for a specific property from request statistics.

        :param stats_list: List of request statistics to extract from
        :param property_name: Name of the property to extract from metrics
        :return: List of tuples containing
            (start_time, end_time, input_value, output_value)
        """
        return [
            (
                stats.request_start_time,
                stats.request_end_time,
                getattr(stats.input_metrics, property_name),
                getattr(stats.output_metrics, property_name),
            )
            for stats in stats_list
            if (
                stats.request_start_time
                and stats.request_end_time
                and (
                    getattr(stats.input_metrics, property_name) is not None
                    or getattr(stats.output_metrics, property_name) is not None
                )
            )
        ]

compile(property_name, successful, incomplete, errored) classmethod

Compile metrics summary from request statistics for a specific property.

Parameters:

Name Type Description Default
property_name str

Name of the property to extract from request metrics

required
successful list[GenerativeRequestStats]

Successfully completed request statistics

required
incomplete list[GenerativeRequestStats]

Incomplete or cancelled request statistics

required
errored list[GenerativeRequestStats]

Failed request statistics

required

Returns:

Type Description
GenerativeMetricsSummary | None

Compiled metrics summary or None if no data available

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile(
    cls,
    property_name: str,
    successful: list[GenerativeRequestStats],
    incomplete: list[GenerativeRequestStats],
    errored: list[GenerativeRequestStats],
) -> GenerativeMetricsSummary | None:
    """
    Compile metrics summary from request statistics for a specific property.

    :param property_name: Name of the property to extract from request metrics
    :param successful: Successfully completed request statistics
    :param incomplete: Incomplete or cancelled request statistics
    :param errored: Failed request statistics
    :return: Compiled metrics summary or None if no data available
    """
    successful_metrics = cls.extract_property_metrics_for_summary(
        successful, property_name
    )
    incomplete_metrics = cls.extract_property_metrics_for_summary(
        incomplete, property_name
    )
    errored_metrics = cls.extract_property_metrics_for_summary(
        errored, property_name
    )

    return cls.compile_timed_metrics(
        successful=successful_metrics,
        incomplete=incomplete_metrics,
        errored=errored_metrics,
    )

compile_timed_metrics(successful, incomplete, errored) classmethod

Compile metrics summary from timed metric tuples.

Parameters:

Name Type Description Default
successful list[TimedMetricTypeAlias]

Timed metrics from successful requests

required
incomplete list[TimedMetricTypeAlias]

Timed metrics from incomplete requests

required
errored list[TimedMetricTypeAlias]

Timed metrics from errored requests

required

Returns:

Type Description
GenerativeMetricsSummary | None

Compiled metrics summary or None if no data available

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile_timed_metrics(
    cls,
    successful: list[TimedMetricTypeAlias],
    incomplete: list[TimedMetricTypeAlias],
    errored: list[TimedMetricTypeAlias],
) -> GenerativeMetricsSummary | None:
    """
    Compile metrics summary from timed metric tuples.

    :param successful: Timed metrics from successful requests
    :param incomplete: Timed metrics from incomplete requests
    :param errored: Timed metrics from errored requests
    :return: Compiled metrics summary or None if no data available
    """

    def _compile_metric_distributions(
        metrics_by_status: dict[StatusTypes, list[TimedMetricTypeAlias]],
        value_index: int,
    ) -> tuple[
        StatusDistributionSummary | None,
        StatusDistributionSummary | None,
        StatusDistributionSummary | None,
        dict[StatusTypes, list[float]],
        dict[StatusTypes, list[tuple[float, float]]],
        dict[StatusTypes, list[tuple[float, float, float]]],
    ]:
        """Helper to compile value, rate, and concurrency distributions."""
        # Filter out None values instead of coercing to 0.0 so we can
        # distinguish "metric not applicable" (None) from "metric is
        # zero" (e.g. errored tool call requests with tool_call_count=0).
        value_lists: dict[StatusTypes, list[float]] = {
            status: [
                float(val)
                for metric in metrics
                if metric is not None
                for val in [metric[value_index]]
                if val is not None
            ]
            for status, metrics in metrics_by_status.items()
        }

        # No data at all for this value index — skip distributions.
        if all(len(vl) == 0 for vl in value_lists.values()):
            return None, None, None, value_lists, {}, {}

        value_dist = StatusDistributionSummary.from_values(
            successful=value_lists["successful"],
            incomplete=value_lists["incomplete"],
            errored=value_lists["errored"],
        )

        rate_lists: dict[StatusTypes, list[tuple[float, float]]] = {
            status: [
                (  # type: ignore[misc]
                    metric[_TIMED_METRIC_END_TIME_INDEX],
                    float(metric[value_index] or 0.0),
                )
                for metric in metrics
                if metric is not None
            ]
            for status, metrics in metrics_by_status.items()
        }
        rate_dist = StatusDistributionSummary.rate_distribution_from_timings(
            successful=rate_lists["successful"],
            incomplete=rate_lists["incomplete"],
            errored=rate_lists["errored"],
        )

        concurrency_lists: dict[StatusTypes, list[tuple[float, float, float]]] = {
            status: [
                (  # type: ignore[misc]
                    metric[_TIMED_METRIC_START_TIME_INDEX],
                    metric[_TIMED_METRIC_END_TIME_INDEX],
                    float(metric[value_index] or 0.0),
                )
                for metric in metrics
                if metric is not None
            ]
            for status, metrics in metrics_by_status.items()
        }
        concurrency_dist = (
            StatusDistributionSummary.concurrency_distribution_from_timings(
                successful=concurrency_lists["successful"],
                incomplete=concurrency_lists["incomplete"],
                errored=concurrency_lists["errored"],
            )
        )

        return (
            value_dist,
            rate_dist,
            concurrency_dist,
            value_lists,
            rate_lists,
            concurrency_lists,
        )

    metrics_by_status: dict[StatusTypes, list[TimedMetricTypeAlias]] = {
        "successful": successful,
        "incomplete": incomplete,
        "errored": errored,
    }

    # Calculate input distributions
    (
        input_value_dist,
        input_rate_dist,
        input_concurrency_dist,
        input_value_lists,
        input_rate_lists,
        input_concurrency_lists,
    ) = _compile_metric_distributions(
        metrics_by_status, _TIMED_METRIC_INPUT_VALUE_INDEX
    )

    # Calculate output distributions
    (
        output_value_dist,
        output_rate_dist,
        output_concurrency_dist,
        output_value_lists,
        output_rate_lists,
        output_concurrency_lists,
    ) = _compile_metric_distributions(
        metrics_by_status, _TIMED_METRIC_OUTPUT_VALUE_INDEX
    )

    # Calculate total distributions if both input and output have data
    if input_value_dist is not None and output_value_dist is not None:
        total_value_dist = StatusDistributionSummary.from_values(
            successful=(
                input_value_lists["successful"] + output_value_lists["successful"]
            ),
            incomplete=(
                input_value_lists["incomplete"] + output_value_lists["incomplete"]
            ),
            errored=input_value_lists["errored"] + output_value_lists["errored"],
        )
        total_rate_dist = StatusDistributionSummary.rate_distribution_from_timings(
            successful=(
                input_rate_lists["successful"] + output_rate_lists["successful"]
            ),
            incomplete=(
                input_rate_lists["incomplete"] + output_rate_lists["incomplete"]
            ),
            errored=input_rate_lists["errored"] + output_rate_lists["errored"],
        )
        total_concurrency_dist = (
            StatusDistributionSummary.concurrency_distribution_from_timings(
                successful=(
                    input_concurrency_lists["successful"]
                    + output_concurrency_lists["successful"]
                ),
                incomplete=(
                    input_concurrency_lists["incomplete"]
                    + output_concurrency_lists["incomplete"]
                ),
                errored=(
                    input_concurrency_lists["errored"]
                    + output_concurrency_lists["errored"]
                ),
            )
        )
    else:
        total_value_dist = None
        total_rate_dist = None
        total_concurrency_dist = None

    return GenerativeMetricsSummary(
        input=input_value_dist,
        input_per_second=input_rate_dist,
        input_concurrency=input_concurrency_dist,
        output=output_value_dist,
        output_per_second=output_rate_dist,
        output_concurrency=output_concurrency_dist,
        total=total_value_dist,
        total_per_second=total_rate_dist,
        total_concurrency=total_concurrency_dist,
    )

extract_property_metrics_for_summary(stats_list, property_name) classmethod

Extract timed metrics for a specific property from request statistics.

Parameters:

Name Type Description Default
stats_list list[GenerativeRequestStats]

List of request statistics to extract from

required
property_name str

Name of the property to extract from metrics

required

Returns:

Type Description
list[TimedMetricTypeAlias]

List of tuples containing (start_time, end_time, input_value, output_value)

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def extract_property_metrics_for_summary(
    cls, stats_list: list[GenerativeRequestStats], property_name: str
) -> list[TimedMetricTypeAlias]:
    """
    Extract timed metrics for a specific property from request statistics.

    :param stats_list: List of request statistics to extract from
    :param property_name: Name of the property to extract from metrics
    :return: List of tuples containing
        (start_time, end_time, input_value, output_value)
    """
    return [
        (
            stats.request_start_time,
            stats.request_end_time,
            getattr(stats.input_metrics, property_name),
            getattr(stats.output_metrics, property_name),
        )
        for stats in stats_list
        if (
            stats.request_start_time
            and stats.request_end_time
            and (
                getattr(stats.input_metrics, property_name) is not None
                or getattr(stats.output_metrics, property_name) is not None
            )
        )
    ]

GenerativeRequestsAccumulator

Bases: StandardBaseModel

Manages request statistics collection with optional reservoir sampling.

Collects detailed request statistics while optionally sampling to limit memory usage in long-running benchmarks. Supports configurable sampling rates and selective data retention (clearing request arguments and/or outputs for non-sampled requests).

Source code in src/guidellm/benchmark/schemas/accumulator.py
class GenerativeRequestsAccumulator(StandardBaseModel):
    """
    Manages request statistics collection with optional reservoir sampling.

    Collects detailed request statistics while optionally sampling to limit memory usage
    in long-running benchmarks. Supports configurable sampling rates and selective data
    retention (clearing request arguments and/or outputs for non-sampled requests).
    """

    sample_size: int | None = Field(
        default=None,
        description=(
            "Maximum number of requests in each status group to retain full data "
            "(prompt, output, tool calls) for. Lightweight stats are always kept. "
            "None keeps all, 0 strips all, N > 0 uses reservoir sampling."
        ),
    )
    requests_stats: list[GenerativeRequestStats] = Field(
        description="List of generative request statistics", default_factory=list
    )
    samples: list[int] | None = Field(
        description="Indices of sampled generative requests", default=None
    )
    clear_nonsampled_request_args: bool = Field(
        default=True,
        description=(
            "Whether to clear request arguments and outputs for non-sampled requests"
        ),
    )
    clear_nonsampled_outputs: bool = Field(
        default=True,
        description=(
            "Whether to clear outputs for non-sampled requests while keeping args"
        ),
    )

    def get_sampled(self) -> list[GenerativeRequestStats]:
        """
        Retrieve the list of sampled request statistics.

        :return: List of sampled generative request statistics
        """
        if self.samples is None:
            return self.requests_stats

        return [self.requests_stats[ind] for ind in self.samples]

    def get_within_range(
        self, start_time: float, end_time: float
    ) -> list[GenerativeRequestStats]:
        """
        Retrieve request statistics within a specified time range.

        :param start_time: Start timestamp for filtering (requests must end after this)
        :param end_time: End timestamp for filtering (requests must start before this)
        :return: List of request statistics within the time range
        """
        return [
            stats
            for stats in self.requests_stats
            if (stats.request_end_time >= start_time)
            and (
                (
                    stats.request_start_time is not None
                    and stats.request_start_time <= end_time
                )
                or (
                    stats.request_start_time is None
                    and stats.request_end_time <= end_time
                )
            )
        ]

    def update_estimate(
        self,
        response: GenerationResponse | None,
        request: GenerationRequest,
        info: RequestInfo,
        prefer_response_metrics: bool,
    ) -> GenerativeRequestStats:
        """
        Record request statistics and apply reservoir sampling if configured.

        Compiles statistics from the completed request and adds to the collection.
        Uses reservoir sampling algorithm to maintain uniform sample distribution when
        enabled, clearing non-sampled request data to manage memory.

        :param response: Generation response containing output and metrics
        :param request: Original generation request with input data
        :param info: Request execution information and timing
        :param prefer_response_metrics: Whether to prefer metrics from response
        :return: Compiled request statistics
        """
        stats = self.compile_stats(response, request, info, prefer_response_metrics)

        current_index = len(self.requests_stats)
        self.requests_stats.append(stats)

        if self.sample_size is None:
            # Keeping all requests, don't need to sample
            self.samples = None
        elif self.sample_size <= 0:
            # Not keeping any requests, clear out unnecessary memory usage for current
            self.clear_stats_data(stats)
        elif self.sample_size >= len(self.requests_stats):
            # Add directly to samples, haven't filled yet
            if self.samples is None:
                self.samples = []
            self.samples.append(current_index)
        elif self.sample_size / len(self.requests_stats) >= random.random():
            # Sampling logic: choose to replace with decreasing probability s / n
            # where s is sample size, n is current number of requests.
            # If chosen, choose random existing sample to replace.
            # P(new item in samples)  = s / n
            # P(prev item in samples) = P(item was in samples) * P(not replaced)
            # P(prev item in samples) =
            #    P(before replacement) * P(new item selected) * P(chosen from samples)
            # P(prev item in samples) = (s / (n - 1)) * (s / n) * (1 / s) = s / n
            # P(prev item in samples) = P(new item in samples)
            if self.samples is None:
                self.samples = []
            replace_index = random.randrange(len(self.samples))
            self.clear_stats_data(self.samples[replace_index])
            self.samples[replace_index] = current_index

        return stats

    def clear_stats_data(self, stats: GenerativeRequestStats | int):
        if isinstance(stats, int):
            stats = self.requests_stats[stats]

        if self.clear_nonsampled_request_args:
            stats.request_args = None
        if self.clear_nonsampled_outputs:
            stats.output = None
            stats.reasoning_output = None
            stats.tool_calls = None

    @classmethod
    def compile_stats(
        cls,
        response: GenerationResponse | None,
        request: GenerationRequest,
        info: RequestInfo,
        prefer_response_metrics: bool,
    ) -> GenerativeRequestStats:
        """
        Compile statistics from request, response, and execution info.

        :param response: Generation response with output and metrics, or None
        :param request: Original generation request with input data
        :param info: Request execution information and timing
        :param prefer_response_metrics: Whether to prefer metrics from response
        :return: Compiled generative request statistics
        """
        # Extract the first request for arguments if multi-turn
        first_request: GenerationRequest
        if isinstance(request, GenerationRequest):
            first_request = request
        else:
            # Multi-turn request: extract first item
            first_item = request[0]
            first_request = (
                first_item[0] if isinstance(first_item, tuple) else first_item
            )

        if response is None:
            response = GenerationResponse(
                request_id=info.request_id,
                request_args=None,
            )

        return response.compile_stats(
            request=first_request,
            info=info,
            prefer_response=prefer_response_metrics,
        )

compile_stats(response, request, info, prefer_response_metrics) classmethod

Compile statistics from request, response, and execution info.

Parameters:

Name Type Description Default
response GenerationResponse | None

Generation response with output and metrics, or None

required
request GenerationRequest

Original generation request with input data

required
info RequestInfo

Request execution information and timing

required
prefer_response_metrics bool

Whether to prefer metrics from response

required

Returns:

Type Description
GenerativeRequestStats

Compiled generative request statistics

Source code in src/guidellm/benchmark/schemas/accumulator.py
@classmethod
def compile_stats(
    cls,
    response: GenerationResponse | None,
    request: GenerationRequest,
    info: RequestInfo,
    prefer_response_metrics: bool,
) -> GenerativeRequestStats:
    """
    Compile statistics from request, response, and execution info.

    :param response: Generation response with output and metrics, or None
    :param request: Original generation request with input data
    :param info: Request execution information and timing
    :param prefer_response_metrics: Whether to prefer metrics from response
    :return: Compiled generative request statistics
    """
    # Extract the first request for arguments if multi-turn
    first_request: GenerationRequest
    if isinstance(request, GenerationRequest):
        first_request = request
    else:
        # Multi-turn request: extract first item
        first_item = request[0]
        first_request = (
            first_item[0] if isinstance(first_item, tuple) else first_item
        )

    if response is None:
        response = GenerationResponse(
            request_id=info.request_id,
            request_args=None,
        )

    return response.compile_stats(
        request=first_request,
        info=info,
        prefer_response=prefer_response_metrics,
    )

get_sampled()

Retrieve the list of sampled request statistics.

Returns:

Type Description
list[GenerativeRequestStats]

List of sampled generative request statistics

Source code in src/guidellm/benchmark/schemas/accumulator.py
def get_sampled(self) -> list[GenerativeRequestStats]:
    """
    Retrieve the list of sampled request statistics.

    :return: List of sampled generative request statistics
    """
    if self.samples is None:
        return self.requests_stats

    return [self.requests_stats[ind] for ind in self.samples]

get_within_range(start_time, end_time)

Retrieve request statistics within a specified time range.

Parameters:

Name Type Description Default
start_time float

Start timestamp for filtering (requests must end after this)

required
end_time float

End timestamp for filtering (requests must start before this)

required

Returns:

Type Description
list[GenerativeRequestStats]

List of request statistics within the time range

Source code in src/guidellm/benchmark/schemas/accumulator.py
def get_within_range(
    self, start_time: float, end_time: float
) -> list[GenerativeRequestStats]:
    """
    Retrieve request statistics within a specified time range.

    :param start_time: Start timestamp for filtering (requests must end after this)
    :param end_time: End timestamp for filtering (requests must start before this)
    :return: List of request statistics within the time range
    """
    return [
        stats
        for stats in self.requests_stats
        if (stats.request_end_time >= start_time)
        and (
            (
                stats.request_start_time is not None
                and stats.request_start_time <= end_time
            )
            or (
                stats.request_start_time is None
                and stats.request_end_time <= end_time
            )
        )
    ]

update_estimate(response, request, info, prefer_response_metrics)

Record request statistics and apply reservoir sampling if configured.

Compiles statistics from the completed request and adds to the collection. Uses reservoir sampling algorithm to maintain uniform sample distribution when enabled, clearing non-sampled request data to manage memory.

Parameters:

Name Type Description Default
response GenerationResponse | None

Generation response containing output and metrics

required
request GenerationRequest

Original generation request with input data

required
info RequestInfo

Request execution information and timing

required
prefer_response_metrics bool

Whether to prefer metrics from response

required

Returns:

Type Description
GenerativeRequestStats

Compiled request statistics

Source code in src/guidellm/benchmark/schemas/accumulator.py
def update_estimate(
    self,
    response: GenerationResponse | None,
    request: GenerationRequest,
    info: RequestInfo,
    prefer_response_metrics: bool,
) -> GenerativeRequestStats:
    """
    Record request statistics and apply reservoir sampling if configured.

    Compiles statistics from the completed request and adds to the collection.
    Uses reservoir sampling algorithm to maintain uniform sample distribution when
    enabled, clearing non-sampled request data to manage memory.

    :param response: Generation response containing output and metrics
    :param request: Original generation request with input data
    :param info: Request execution information and timing
    :param prefer_response_metrics: Whether to prefer metrics from response
    :return: Compiled request statistics
    """
    stats = self.compile_stats(response, request, info, prefer_response_metrics)

    current_index = len(self.requests_stats)
    self.requests_stats.append(stats)

    if self.sample_size is None:
        # Keeping all requests, don't need to sample
        self.samples = None
    elif self.sample_size <= 0:
        # Not keeping any requests, clear out unnecessary memory usage for current
        self.clear_stats_data(stats)
    elif self.sample_size >= len(self.requests_stats):
        # Add directly to samples, haven't filled yet
        if self.samples is None:
            self.samples = []
        self.samples.append(current_index)
    elif self.sample_size / len(self.requests_stats) >= random.random():
        # Sampling logic: choose to replace with decreasing probability s / n
        # where s is sample size, n is current number of requests.
        # If chosen, choose random existing sample to replace.
        # P(new item in samples)  = s / n
        # P(prev item in samples) = P(item was in samples) * P(not replaced)
        # P(prev item in samples) =
        #    P(before replacement) * P(new item selected) * P(chosen from samples)
        # P(prev item in samples) = (s / (n - 1)) * (s / n) * (1 / s) = s / n
        # P(prev item in samples) = P(new item in samples)
        if self.samples is None:
            self.samples = []
        replace_index = random.randrange(len(self.samples))
        self.clear_stats_data(self.samples[replace_index])
        self.samples[replace_index] = current_index

    return stats

GenerativeTextMetricsSummary

Bases: StandardBaseDict

Text-specific metric summaries for generative benchmarks.

Tracks token, word, and character-level metrics across input, output, and total usage for text generation workloads.

Source code in src/guidellm/benchmark/schemas/metrics.py
class GenerativeTextMetricsSummary(StandardBaseDict):
    """
    Text-specific metric summaries for generative benchmarks.

    Tracks token, word, and character-level metrics across input, output, and
    total usage for text generation workloads.
    """

    tokens: GenerativeMetricsSummary | None = Field(
        description="Token count metrics and distributions"
    )
    words: GenerativeMetricsSummary | None = Field(
        description="Word count metrics and distributions"
    )
    characters: GenerativeMetricsSummary | None = Field(
        description="Character count metrics and distributions"
    )

    @classmethod
    def compile(
        cls,
        successful: list[GenerativeRequestStats],
        incomplete: list[GenerativeRequestStats],
        errored: list[GenerativeRequestStats],
    ) -> GenerativeTextMetricsSummary:
        """
        Compile text metrics summary from request statistics.

        :param successful: Successfully completed request statistics
        :param incomplete: Incomplete/cancelled request statistics
        :param errored: Failed request statistics
        :return: Compiled text metrics summary
        """
        return GenerativeTextMetricsSummary(
            tokens=GenerativeMetricsSummary.compile(
                property_name="text_tokens",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            words=GenerativeMetricsSummary.compile(
                property_name="text_words",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            characters=GenerativeMetricsSummary.compile(
                property_name="text_characters",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
        )

compile(successful, incomplete, errored) classmethod

Compile text metrics summary from request statistics.

Parameters:

Name Type Description Default
successful list[GenerativeRequestStats]

Successfully completed request statistics

required
incomplete list[GenerativeRequestStats]

Incomplete/cancelled request statistics

required
errored list[GenerativeRequestStats]

Failed request statistics

required

Returns:

Type Description
GenerativeTextMetricsSummary

Compiled text metrics summary

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile(
    cls,
    successful: list[GenerativeRequestStats],
    incomplete: list[GenerativeRequestStats],
    errored: list[GenerativeRequestStats],
) -> GenerativeTextMetricsSummary:
    """
    Compile text metrics summary from request statistics.

    :param successful: Successfully completed request statistics
    :param incomplete: Incomplete/cancelled request statistics
    :param errored: Failed request statistics
    :return: Compiled text metrics summary
    """
    return GenerativeTextMetricsSummary(
        tokens=GenerativeMetricsSummary.compile(
            property_name="text_tokens",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        words=GenerativeMetricsSummary.compile(
            property_name="text_words",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        characters=GenerativeMetricsSummary.compile(
            property_name="text_characters",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
    )

GenerativeVideoMetricsSummary

Bases: StandardBaseDict

Video-specific metric summaries for generative benchmarks.

Tracks token, frame count, duration, and byte-level metrics across input, output, and total usage for video generation workloads.

Source code in src/guidellm/benchmark/schemas/metrics.py
class GenerativeVideoMetricsSummary(StandardBaseDict):
    """
    Video-specific metric summaries for generative benchmarks.

    Tracks token, frame count, duration, and byte-level metrics across input,
    output, and total usage for video generation workloads.
    """

    tokens: GenerativeMetricsSummary | None = Field(
        description="Video token count metrics and distributions"
    )
    frames: GenerativeMetricsSummary | None = Field(
        description="Frame count metrics and distributions"
    )
    seconds: GenerativeMetricsSummary | None = Field(
        description="Duration metrics in seconds and distributions"
    )
    bytes: GenerativeMetricsSummary | None = Field(
        description="Byte size metrics and distributions"
    )

    @classmethod
    def compile(
        cls,
        successful: list[GenerativeRequestStats],
        incomplete: list[GenerativeRequestStats],
        errored: list[GenerativeRequestStats],
    ) -> GenerativeVideoMetricsSummary:
        """
        Compile video metrics summary from request statistics.

        :param successful: Successfully completed request statistics
        :param incomplete: Incomplete/cancelled request statistics
        :param errored: Failed request statistics
        :return: Compiled video metrics summary
        """
        return GenerativeVideoMetricsSummary(
            tokens=GenerativeMetricsSummary.compile(
                property_name="video_tokens",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            frames=GenerativeMetricsSummary.compile(
                property_name="video_frames",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            seconds=GenerativeMetricsSummary.compile(
                property_name="video_seconds",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
            bytes=GenerativeMetricsSummary.compile(
                property_name="video_bytes",
                successful=successful,
                incomplete=incomplete,
                errored=errored,
            ),
        )

compile(successful, incomplete, errored) classmethod

Compile video metrics summary from request statistics.

Parameters:

Name Type Description Default
successful list[GenerativeRequestStats]

Successfully completed request statistics

required
incomplete list[GenerativeRequestStats]

Incomplete/cancelled request statistics

required
errored list[GenerativeRequestStats]

Failed request statistics

required

Returns:

Type Description
GenerativeVideoMetricsSummary

Compiled video metrics summary

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile(
    cls,
    successful: list[GenerativeRequestStats],
    incomplete: list[GenerativeRequestStats],
    errored: list[GenerativeRequestStats],
) -> GenerativeVideoMetricsSummary:
    """
    Compile video metrics summary from request statistics.

    :param successful: Successfully completed request statistics
    :param incomplete: Incomplete/cancelled request statistics
    :param errored: Failed request statistics
    :return: Compiled video metrics summary
    """
    return GenerativeVideoMetricsSummary(
        tokens=GenerativeMetricsSummary.compile(
            property_name="video_tokens",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        frames=GenerativeMetricsSummary.compile(
            property_name="video_frames",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        seconds=GenerativeMetricsSummary.compile(
            property_name="video_seconds",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
        bytes=GenerativeMetricsSummary.compile(
            property_name="video_bytes",
            successful=successful,
            incomplete=incomplete,
            errored=errored,
        ),
    )

Profile

Bases: ABC

Coordinate multi-strategy benchmark execution with automatic strategy generation.

Manages sequential execution of scheduling strategies with automatic strategy generation, constraint management, and completion tracking. Subclasses define specific execution patterns like synchronous, concurrent, throughput-focused, rate-based async, or adaptive sweep profiles.

Example: :: @Profile.register("synchronous") class SynchronousProfile(Profile): def init(self, args: SynchronousProfileArgs): super().init(args)

args = SynchronousProfileArgs(kind="synchronous")
profile = Profile.create(args)
Source code in src/guidellm/benchmark/profiles/profile.py
class Profile(ABC):
    """
    Coordinate multi-strategy benchmark execution with automatic strategy generation.

    Manages sequential execution of scheduling strategies with automatic strategy
    generation, constraint management, and completion tracking. Subclasses define
    specific execution patterns like synchronous, concurrent, throughput-focused,
    rate-based async, or adaptive sweep profiles.

    Example:
    ::
        @Profile.register("synchronous")
        class SynchronousProfile(Profile):
            def __init__(self, args: SynchronousProfileArgs):
                super().__init__(args)

        args = SynchronousProfileArgs(kind="synchronous")
        profile = Profile.create(args)
    """

    def __init__(
        self,
        args: ProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
        **kwargs: Any,
    ):
        """
        Initialize a profile instance.

        :param args: Validated profile argument model for this profile type
        :param random_seed: Seed for reproducible random operations in profile
            strategies.
        :param constraints: Constraints for the profile strategies.
        :param kwargs: Additional profile-specific configuration parameters
        """
        _ = kwargs  # unused
        self.kind = args.kind
        self.args = args
        self.random_seed = random_seed
        self.constraints = dict(constraints or {})
        self.completed_strategies: list[SchedulingStrategy] = []

    @property
    def info(self) -> dict[str, Any]:
        """
        Help json serialization by deferring to ProfileArgs.
        """
        return self.args.model_dump()

    @property
    def strategy_types(self) -> list[str]:
        """
        :return: Strategy types executed or to be executed in this profile
        """
        return [strat.type_ for strat in self.completed_strategies]

    @staticmethod
    def _should_stop_escalating(prev_benchmark: Benchmark) -> bool:
        """
        Check if a benchmark was terminated by a constraint with stopping_scope="all".

        Inspects the scheduler state's end_queuing_constraints for any constraint
        whose stopping_scope is "all", indicating the system could not handle the
        load and escalation to subsequent rates/streams should halt.

        :param prev_benchmark: Benchmark instance
        :return: True if escalation should stop, False otherwise
        """
        scheduler_state = getattr(prev_benchmark, "scheduler_state", None)
        if scheduler_state is None:
            return False

        for name, action in scheduler_state.end_queuing_constraints.items():
            if action.stopping_scope == "all":
                logger.debug(
                    "Stopping rate escalation: constraint '{}' "
                    "triggered (stopping_scope=all)",
                    name,
                )
                return True
        return False

    def strategies_generator(
        self,
    ) -> Generator[
        tuple[SchedulingStrategy, dict[str, Constraint] | None],
        Benchmark | None,
        None,
    ]:
        """
        Generate strategies and constraints for sequential execution.

        :return: Generator yielding (strategy, constraints) tuples and receiving
            benchmark results after each execution
        """
        prev_strategy: SchedulingStrategy | None = None
        prev_benchmark: Benchmark | None = None

        while (
            strategy := self.next_strategy(prev_strategy, prev_benchmark)
        ) is not None:
            constraints = self.next_strategy_constraints(
                strategy, prev_strategy, prev_benchmark
            )
            prev_benchmark = yield (
                strategy,
                constraints,
            )
            prev_strategy = strategy
            self.completed_strategies.append(prev_strategy)

    @abstractmethod
    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> SchedulingStrategy | None:
        """
        Generate next strategy in the profile execution sequence.

        :param prev_strategy: Previously completed strategy instance
        :param prev_benchmark: Benchmark results from previous strategy execution
        :return: Next strategy to execute, or None if profile complete
        """
        ...

    def next_strategy_constraints(
        self,
        next_strategy: SchedulingStrategy | None,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> dict[str, Constraint] | None:
        """
        Generate constraints for next strategy execution.

        :param next_strategy: Strategy to be executed next
        :param prev_strategy: Previously completed strategy instance
        :param prev_benchmark: Benchmark results from previous strategy execution
        :return: Constraints dictionary for next strategy, or None
        """
        _ = (prev_strategy, prev_benchmark)  # unused
        return (
            ConstraintsInitializerFactory.resolve(self.constraints)
            if next_strategy and self.constraints
            else None
        )

info property

Help json serialization by deferring to ProfileArgs.

strategy_types property

Returns:

Type Description
list[str]

Strategy types executed or to be executed in this profile

__init__(args, random_seed, constraints, **kwargs)

Initialize a profile instance.

Parameters:

Name Type Description Default
args ProfileArgs

Validated profile argument model for this profile type

required
random_seed int

Seed for reproducible random operations in profile strategies.

required
constraints MutableMapping[str, ConstraintInitializer | Any] | None

Constraints for the profile strategies.

required
kwargs Any

Additional profile-specific configuration parameters

{}
Source code in src/guidellm/benchmark/profiles/profile.py
def __init__(
    self,
    args: ProfileArgs,
    random_seed: int,
    constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
    **kwargs: Any,
):
    """
    Initialize a profile instance.

    :param args: Validated profile argument model for this profile type
    :param random_seed: Seed for reproducible random operations in profile
        strategies.
    :param constraints: Constraints for the profile strategies.
    :param kwargs: Additional profile-specific configuration parameters
    """
    _ = kwargs  # unused
    self.kind = args.kind
    self.args = args
    self.random_seed = random_seed
    self.constraints = dict(constraints or {})
    self.completed_strategies: list[SchedulingStrategy] = []

next_strategy(prev_strategy, prev_benchmark) abstractmethod

Generate next strategy in the profile execution sequence.

Parameters:

Name Type Description Default
prev_strategy SchedulingStrategy | None

Previously completed strategy instance

required
prev_benchmark Benchmark | None

Benchmark results from previous strategy execution

required

Returns:

Type Description
SchedulingStrategy | None

Next strategy to execute, or None if profile complete

Source code in src/guidellm/benchmark/profiles/profile.py
@abstractmethod
def next_strategy(
    self,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> SchedulingStrategy | None:
    """
    Generate next strategy in the profile execution sequence.

    :param prev_strategy: Previously completed strategy instance
    :param prev_benchmark: Benchmark results from previous strategy execution
    :return: Next strategy to execute, or None if profile complete
    """
    ...

next_strategy_constraints(next_strategy, prev_strategy, prev_benchmark)

Generate constraints for next strategy execution.

Parameters:

Name Type Description Default
next_strategy SchedulingStrategy | None

Strategy to be executed next

required
prev_strategy SchedulingStrategy | None

Previously completed strategy instance

required
prev_benchmark Benchmark | None

Benchmark results from previous strategy execution

required

Returns:

Type Description
dict[str, Constraint] | None

Constraints dictionary for next strategy, or None

Source code in src/guidellm/benchmark/profiles/profile.py
def next_strategy_constraints(
    self,
    next_strategy: SchedulingStrategy | None,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> dict[str, Constraint] | None:
    """
    Generate constraints for next strategy execution.

    :param next_strategy: Strategy to be executed next
    :param prev_strategy: Previously completed strategy instance
    :param prev_benchmark: Benchmark results from previous strategy execution
    :return: Constraints dictionary for next strategy, or None
    """
    _ = (prev_strategy, prev_benchmark)  # unused
    return (
        ConstraintsInitializerFactory.resolve(self.constraints)
        if next_strategy and self.constraints
        else None
    )

strategies_generator()

Generate strategies and constraints for sequential execution.

Returns:

Type Description
Generator[tuple[SchedulingStrategy, dict[str, Constraint] | None], Benchmark | None, None]

Generator yielding (strategy, constraints) tuples and receiving benchmark results after each execution

Source code in src/guidellm/benchmark/profiles/profile.py
def strategies_generator(
    self,
) -> Generator[
    tuple[SchedulingStrategy, dict[str, Constraint] | None],
    Benchmark | None,
    None,
]:
    """
    Generate strategies and constraints for sequential execution.

    :return: Generator yielding (strategy, constraints) tuples and receiving
        benchmark results after each execution
    """
    prev_strategy: SchedulingStrategy | None = None
    prev_benchmark: Benchmark | None = None

    while (
        strategy := self.next_strategy(prev_strategy, prev_benchmark)
    ) is not None:
        constraints = self.next_strategy_constraints(
            strategy, prev_strategy, prev_benchmark
        )
        prev_benchmark = yield (
            strategy,
            constraints,
        )
        prev_strategy = strategy
        self.completed_strategies.append(prev_strategy)

RunningMetricStats

Bases: StandardBaseModel

Maintains running statistics for a metric stream without storing all samples.

Accumulates count, sum, time-weighted sum, and duration to compute mean, rate, and time-weighted statistics incrementally. Efficient for real-time metric tracking during long-running benchmarks where storing individual samples is impractical.

Source code in src/guidellm/benchmark/schemas/accumulator.py
class RunningMetricStats(StandardBaseModel):
    """
    Maintains running statistics for a metric stream without storing all samples.

    Accumulates count, sum, time-weighted sum, and duration to compute mean, rate,
    and time-weighted statistics incrementally. Efficient for real-time metric tracking
    during long-running benchmarks where storing individual samples is impractical.
    """

    count: int = Field(description="Number of samples accumulated", default=0)
    value_sum: float = Field(description="Total sum of accumulated values", default=0.0)
    time_weighted_sum: float = Field(
        description="Time-weighted sum of accumulated values", default=0.0
    )
    duration: float = Field(
        description="Total duration over which values were accumulated", default=0.0
    )
    last_value: float | None = Field(
        description="Most recent value added to the accumulator", default=None
    )

    @property
    def mean(self) -> float | None:
        """
        :return: Arithmetic mean of accumulated values, or None if no samples
        """
        if self.count <= 0:
            return None

        return self.value_sum / self.count

    @property
    def time_weighted_mean(self) -> float | None:
        """
        :return: Time-weighted mean considering duration between samples, or None
        """
        if self.duration <= 0.0:
            return None

        return self.time_weighted_sum / self.duration

    @property
    def rate_per_item(self) -> float | None:
        """
        :return: Average value per accumulated item, or None if no samples
        """
        if self.count <= 0:
            return None

        return self.value_sum / self.count

    @property
    def rate_per_second(self) -> float | None:
        """
        :return: Average value per second of duration, or None if no duration
        """
        if self.duration <= 0.0:
            return None

        return self.value_sum / self.duration

    def update_estimate(
        self,
        value: float | None,
        count: int = 1,
        duration: float | None = None,
        elapsed: float | None = None,
    ):
        """
        Incorporate a new metric value into running statistics.

        Updates count, sum, and time-weighted statistics using the new value and timing
        information. Time-weighted calculations use the previous value over the elapsed
        interval to capture sustained metric behavior.

        :param value: New metric value to accumulate
        :param count: Number of occurrences this value represents
        :param duration: Total duration to set, overriding incremental elapsed updates
        :param elapsed: Time elapsed since last update for time-weighted calculations
        """
        if value is not None:
            self.count += count
            self.value_sum += value * count

        if elapsed is not None:
            self.time_weighted_sum += (self.last_value or 0.0) * elapsed

        self.duration = (
            duration if duration is not None else (self.duration + (elapsed or 0.0))
        )
        self.last_value = value

mean property

Returns:

Type Description
float | None

Arithmetic mean of accumulated values, or None if no samples

rate_per_item property

Returns:

Type Description
float | None

Average value per accumulated item, or None if no samples

rate_per_second property

Returns:

Type Description
float | None

Average value per second of duration, or None if no duration

time_weighted_mean property

Returns:

Type Description
float | None

Time-weighted mean considering duration between samples, or None

update_estimate(value, count=1, duration=None, elapsed=None)

Incorporate a new metric value into running statistics.

Updates count, sum, and time-weighted statistics using the new value and timing information. Time-weighted calculations use the previous value over the elapsed interval to capture sustained metric behavior.

Parameters:

Name Type Description Default
value float | None

New metric value to accumulate

required
count int

Number of occurrences this value represents

1
duration float | None

Total duration to set, overriding incremental elapsed updates

None
elapsed float | None

Time elapsed since last update for time-weighted calculations

None
Source code in src/guidellm/benchmark/schemas/accumulator.py
def update_estimate(
    self,
    value: float | None,
    count: int = 1,
    duration: float | None = None,
    elapsed: float | None = None,
):
    """
    Incorporate a new metric value into running statistics.

    Updates count, sum, and time-weighted statistics using the new value and timing
    information. Time-weighted calculations use the previous value over the elapsed
    interval to capture sustained metric behavior.

    :param value: New metric value to accumulate
    :param count: Number of occurrences this value represents
    :param duration: Total duration to set, overriding incremental elapsed updates
    :param elapsed: Time elapsed since last update for time-weighted calculations
    """
    if value is not None:
        self.count += count
        self.value_sum += value * count

    if elapsed is not None:
        self.time_weighted_sum += (self.last_value or 0.0) * elapsed

    self.duration = (
        duration if duration is not None else (self.duration + (elapsed or 0.0))
    )
    self.last_value = value

SchedulerMetrics

Bases: StandardBaseDict

Scheduler timing and performance statistics.

Tracks overall benchmark timing, request counts by status, and detailed internal scheduler performance metrics including queue times, processing delays, and request execution statistics. Used to analyze scheduler efficiency and identify bottlenecks in request processing pipelines.

Source code in src/guidellm/benchmark/schemas/metrics.py
class SchedulerMetrics(StandardBaseDict):
    """Scheduler timing and performance statistics.

    Tracks overall benchmark timing, request counts by status, and detailed internal
    scheduler performance metrics including queue times, processing delays, and
    request execution statistics. Used to analyze scheduler efficiency and identify
    bottlenecks in request processing pipelines.
    """

    # Overall timings for the scheduler
    start_time: float = Field(
        description="Unix timestamp when the benchmark run started"
    )
    request_start_time: float = Field(
        description="Unix timestamp when first request was made"
    )
    measure_start_time: float = Field(
        description="Unix timestamp when measurement period started"
    )
    measure_end_time: float = Field(
        description="Unix timestamp when measurement period ended"
    )
    request_end_time: float = Field(
        description="Unix timestamp when last request completed"
    )
    end_time: float = Field(description="Unix timestamp when the benchmark run ended")

    # Request details tracked by the scheduler
    requests_made: StatusBreakdown[int, int, int, int] = Field(
        description="Request counts by status: successful, incomplete, errored, total"
    )

    # Scheduler internal performance timings
    queued_time_avg: float = Field(
        description="Avg time requests spent in the queue (seconds)"
    )
    resolve_start_delay_avg: float = Field(
        description="Avg delay before worker begins resolving req after dequeue (sec)"
    )
    resolve_targeted_start_delay_avg: float = Field(
        description="Avg delay to targeted resolve start time (seconds)"
    )
    request_start_delay_avg: float = Field(
        description="Avg delay before request starts after resolve (seconds)"
    )
    request_targeted_start_delay_avg: float = Field(
        description="Avg delay to targeted request start time (seconds)"
    )
    request_time_avg: float = Field(description="Avg request execution time (seconds)")
    resolve_end_delay_avg: float = Field(
        description="Avg delay after request completes before resolve ends (seconds)"
    )
    resolve_time_avg: float = Field(
        description="Avg total resolve time including request (seconds)"
    )
    finalized_delay_avg: float = Field(
        description="Avg delay from resolve end to request finalization (seconds)"
    )
    processed_delay_avg: float = Field(
        description="Avg delay from finalization to processing completion (seconds)"
    )

    @classmethod
    def compile(
        cls,
        accumulator: GenerativeBenchmarkAccumulator,
        scheduler_state: SchedulerState,
    ) -> SchedulerMetrics:
        """
        Compile scheduler metrics from accumulator and scheduler state.

        :param accumulator: Benchmark accumulator containing timing and metric data
        :param scheduler_state: Scheduler state with execution timing information
        :return: Compiled scheduler metrics with performance statistics
        """
        return SchedulerMetrics(
            # Overall timings for the scheduler
            start_time=scheduler_state.start_time,
            request_start_time=accumulator.timings.finalized_request_start,
            measure_start_time=accumulator.timings.finalized_measure_start,
            measure_end_time=accumulator.timings.finalized_measure_end,
            request_end_time=accumulator.timings.finalized_request_end,
            end_time=scheduler_state.end_time or -1.0,
            # Request details tracked by the scheduler
            requests_made=accumulator.scheduler_metrics.requests_made,
            # Scheduler internal performance timings
            queued_time_avg=accumulator.scheduler_metrics.queued_time.mean or -1.0,
            resolve_start_delay_avg=(
                accumulator.scheduler_metrics.resolve_start_delay.mean or -1.0
            ),
            resolve_targeted_start_delay_avg=(
                accumulator.scheduler_metrics.resolve_targeted_start_delay.mean or -1.0
            ),
            request_start_delay_avg=(
                accumulator.scheduler_metrics.request_start_delay.mean or -1.0
            ),
            request_targeted_start_delay_avg=(
                accumulator.scheduler_metrics.request_targeted_start_delay.mean or -1.0
            ),
            request_time_avg=accumulator.scheduler_metrics.request_time.mean or -1.0,
            resolve_end_delay_avg=(
                accumulator.scheduler_metrics.resolve_end_delay.mean or -1.0
            ),
            resolve_time_avg=accumulator.scheduler_metrics.resolve_time.mean or -1.0,
            finalized_delay_avg=(
                accumulator.scheduler_metrics.finalized_delay.mean or -1.0
            ),
            processed_delay_avg=(
                accumulator.scheduler_metrics.processed_delay.mean or -1.0
            ),
        )

compile(accumulator, scheduler_state) classmethod

Compile scheduler metrics from accumulator and scheduler state.

Parameters:

Name Type Description Default
accumulator GenerativeBenchmarkAccumulator

Benchmark accumulator containing timing and metric data

required
scheduler_state SchedulerState

Scheduler state with execution timing information

required

Returns:

Type Description
SchedulerMetrics

Compiled scheduler metrics with performance statistics

Source code in src/guidellm/benchmark/schemas/metrics.py
@classmethod
def compile(
    cls,
    accumulator: GenerativeBenchmarkAccumulator,
    scheduler_state: SchedulerState,
) -> SchedulerMetrics:
    """
    Compile scheduler metrics from accumulator and scheduler state.

    :param accumulator: Benchmark accumulator containing timing and metric data
    :param scheduler_state: Scheduler state with execution timing information
    :return: Compiled scheduler metrics with performance statistics
    """
    return SchedulerMetrics(
        # Overall timings for the scheduler
        start_time=scheduler_state.start_time,
        request_start_time=accumulator.timings.finalized_request_start,
        measure_start_time=accumulator.timings.finalized_measure_start,
        measure_end_time=accumulator.timings.finalized_measure_end,
        request_end_time=accumulator.timings.finalized_request_end,
        end_time=scheduler_state.end_time or -1.0,
        # Request details tracked by the scheduler
        requests_made=accumulator.scheduler_metrics.requests_made,
        # Scheduler internal performance timings
        queued_time_avg=accumulator.scheduler_metrics.queued_time.mean or -1.0,
        resolve_start_delay_avg=(
            accumulator.scheduler_metrics.resolve_start_delay.mean or -1.0
        ),
        resolve_targeted_start_delay_avg=(
            accumulator.scheduler_metrics.resolve_targeted_start_delay.mean or -1.0
        ),
        request_start_delay_avg=(
            accumulator.scheduler_metrics.request_start_delay.mean or -1.0
        ),
        request_targeted_start_delay_avg=(
            accumulator.scheduler_metrics.request_targeted_start_delay.mean or -1.0
        ),
        request_time_avg=accumulator.scheduler_metrics.request_time.mean or -1.0,
        resolve_end_delay_avg=(
            accumulator.scheduler_metrics.resolve_end_delay.mean or -1.0
        ),
        resolve_time_avg=accumulator.scheduler_metrics.resolve_time.mean or -1.0,
        finalized_delay_avg=(
            accumulator.scheduler_metrics.finalized_delay.mean or -1.0
        ),
        processed_delay_avg=(
            accumulator.scheduler_metrics.processed_delay.mean or -1.0
        ),
    )

SchedulerMetricsAccumulator

Bases: StandardBaseModel

Tracks scheduler-level timing and overhead metrics during execution.

Monitors request lifecycle timing from queuing through completion, capturing delays at each stage: queue time, worker start delays, request processing time, and finalization overhead. Provides insight into scheduler efficiency and bottleneck identification in request orchestration.

Source code in src/guidellm/benchmark/schemas/accumulator.py
class SchedulerMetricsAccumulator(StandardBaseModel):
    """
    Tracks scheduler-level timing and overhead metrics during execution.

    Monitors request lifecycle timing from queuing through completion, capturing delays
    at each stage: queue time, worker start delays, request processing time, and
    finalization overhead. Provides insight into scheduler efficiency and bottleneck
    identification in request orchestration.
    """

    requests_made: StatusBreakdown[int, int, int, int] = Field(
        description="Request counts by status: successful, incomplete, errored, total",
        default_factory=lambda: StatusBreakdown[int, int, int, int](
            successful=0, errored=0, incomplete=0, total=0
        ),
    )
    # Timings flow:
    # Request scheduling: queued->dequeued->scheduled_at->resolve_start->
    # Request processing: request_start->*_iteration->request_end->
    # Request finalizing: resolve_end->finalized->accumulation update processed
    queued_time: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Running stats for time requests spent in the queue",
    )
    resolve_start_delay: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description=(
            "Running stats for delay before worker begins resolving req after dequeue"
        ),
    )
    resolve_targeted_start_delay: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description=(
            "Running stats for delay from targeted start to actual worker start"
        ),
    )
    request_start_delay: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Running stats for delay after resolve til request start",
    )
    request_targeted_start_delay: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description=(
            "Running stats for delay from targeted start to actual request start"
        ),
    )
    request_time: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Running stats for request processing time",
    )
    resolve_end_delay: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Running stats for delay after request end till worker resolves",
    )
    resolve_time: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Running stats for time for worker to resolve requests",
    )
    finalized_delay: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description="Running stats for delay after resolve til finalized in scheduler",
    )
    processed_delay: RunningMetricStats = Field(
        default_factory=RunningMetricStats,
        description=(
            "Running stats for delay from finalized til request being "
            "processed by accumulation"
        ),
    )

    def update_estimate(
        self, scheduler_state: SchedulerState, stats: GenerativeRequestStats
    ):
        """
        Update scheduler metrics with completed request timing data.

        Extracts timing information from request statistics to update running metrics
        for each scheduler lifecycle stage. Validates that required timing markers are
        present before processing.

        :param scheduler_state: Current scheduler state with request counts
        :param stats: Completed request statistics with detailed timing information
        :raises ValueError: If required timing markers are missing
        """
        # Update request counts
        self.requests_made.successful = scheduler_state.successful_requests
        self.requests_made.errored = scheduler_state.errored_requests
        self.requests_made.incomplete = scheduler_state.cancelled_requests
        self.requests_made.total = (
            scheduler_state.successful_requests
            + scheduler_state.errored_requests
            + scheduler_state.cancelled_requests
        )

        # All requests must have queued, dequeued, resolve_end, and finalized timings
        timings: RequestTimings = stats.info.timings
        if any(
            timing is None
            for timing in [
                timings.queued,
                timings.dequeued,
                timings.resolve_end,
                timings.finalized,
            ]
        ):
            raise ValueError(
                "Required timings 'queued', 'dequeued', 'resolve_end', and "
                "'finalized' must not be None"
            )

        # Store validated non-None timings for type safety
        queued: float = timings.queued  # type: ignore[assignment]
        dequeued: float = timings.dequeued  # type: ignore[assignment]
        resolve_end: float = timings.resolve_end  # type: ignore[assignment]
        finalized: float = timings.finalized  # type: ignore[assignment]

        # Update timing metrics in occurrence order
        self.queued_time.update_estimate(value=dequeued - queued)

        if timings.scheduled_at is not None and timings.resolve_start is not None:
            self.resolve_start_delay.update_estimate(
                value=timings.resolve_start - timings.scheduled_at
            )

        if timings.targeted_start is not None and timings.resolve_start is not None:
            self.resolve_targeted_start_delay.update_estimate(
                value=timings.resolve_start - timings.targeted_start
            )

        if timings.resolve_start is not None and timings.request_start is not None:
            self.request_start_delay.update_estimate(
                value=timings.request_start - timings.resolve_start
            )

        if timings.targeted_start is not None and timings.request_start is not None:
            self.request_targeted_start_delay.update_estimate(
                value=timings.request_start - timings.targeted_start
            )

        if timings.request_start is not None and timings.request_end is not None:
            self.request_time.update_estimate(
                value=timings.request_end - timings.request_start
            )

        if timings.request_end is not None:
            self.resolve_end_delay.update_estimate(
                value=resolve_end - timings.request_end
            )

        if timings.resolve_start is not None:
            self.resolve_time.update_estimate(value=resolve_end - timings.resolve_start)

        self.finalized_delay.update_estimate(value=finalized - resolve_end)
        self.processed_delay.update_estimate(value=time.time() - finalized)

update_estimate(scheduler_state, stats)

Update scheduler metrics with completed request timing data.

Extracts timing information from request statistics to update running metrics for each scheduler lifecycle stage. Validates that required timing markers are present before processing.

Parameters:

Name Type Description Default
scheduler_state SchedulerState

Current scheduler state with request counts

required
stats GenerativeRequestStats

Completed request statistics with detailed timing information

required

Raises:

Type Description
ValueError

If required timing markers are missing

Source code in src/guidellm/benchmark/schemas/accumulator.py
def update_estimate(
    self, scheduler_state: SchedulerState, stats: GenerativeRequestStats
):
    """
    Update scheduler metrics with completed request timing data.

    Extracts timing information from request statistics to update running metrics
    for each scheduler lifecycle stage. Validates that required timing markers are
    present before processing.

    :param scheduler_state: Current scheduler state with request counts
    :param stats: Completed request statistics with detailed timing information
    :raises ValueError: If required timing markers are missing
    """
    # Update request counts
    self.requests_made.successful = scheduler_state.successful_requests
    self.requests_made.errored = scheduler_state.errored_requests
    self.requests_made.incomplete = scheduler_state.cancelled_requests
    self.requests_made.total = (
        scheduler_state.successful_requests
        + scheduler_state.errored_requests
        + scheduler_state.cancelled_requests
    )

    # All requests must have queued, dequeued, resolve_end, and finalized timings
    timings: RequestTimings = stats.info.timings
    if any(
        timing is None
        for timing in [
            timings.queued,
            timings.dequeued,
            timings.resolve_end,
            timings.finalized,
        ]
    ):
        raise ValueError(
            "Required timings 'queued', 'dequeued', 'resolve_end', and "
            "'finalized' must not be None"
        )

    # Store validated non-None timings for type safety
    queued: float = timings.queued  # type: ignore[assignment]
    dequeued: float = timings.dequeued  # type: ignore[assignment]
    resolve_end: float = timings.resolve_end  # type: ignore[assignment]
    finalized: float = timings.finalized  # type: ignore[assignment]

    # Update timing metrics in occurrence order
    self.queued_time.update_estimate(value=dequeued - queued)

    if timings.scheduled_at is not None and timings.resolve_start is not None:
        self.resolve_start_delay.update_estimate(
            value=timings.resolve_start - timings.scheduled_at
        )

    if timings.targeted_start is not None and timings.resolve_start is not None:
        self.resolve_targeted_start_delay.update_estimate(
            value=timings.resolve_start - timings.targeted_start
        )

    if timings.resolve_start is not None and timings.request_start is not None:
        self.request_start_delay.update_estimate(
            value=timings.request_start - timings.resolve_start
        )

    if timings.targeted_start is not None and timings.request_start is not None:
        self.request_targeted_start_delay.update_estimate(
            value=timings.request_start - timings.targeted_start
        )

    if timings.request_start is not None and timings.request_end is not None:
        self.request_time.update_estimate(
            value=timings.request_end - timings.request_start
        )

    if timings.request_end is not None:
        self.resolve_end_delay.update_estimate(
            value=resolve_end - timings.request_end
        )

    if timings.resolve_start is not None:
        self.resolve_time.update_estimate(value=resolve_end - timings.resolve_start)

    self.finalized_delay.update_estimate(value=finalized - resolve_end)
    self.processed_delay.update_estimate(value=time.time() - finalized)

SweepProfile

Bases: Profile

Discover optimal rate range through adaptive multi-strategy execution.

Automatically discovers optimal rate range by executing synchronous and throughput strategies first, then interpolating rates for async strategies to comprehensively sweep the performance space.

Source code in src/guidellm/benchmark/profiles/sweep.py
@ProfileFactory.register("sweep")
class SweepProfile(Profile):
    """
    Discover optimal rate range through adaptive multi-strategy execution.

    Automatically discovers optimal rate range by executing synchronous and
    throughput strategies first, then interpolating rates for async strategies
    to comprehensively sweep the performance space.
    """

    args: SweepProfileArgs

    def __init__(
        self,
        args: SweepProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
        **kwargs: Any,
    ):
        super().__init__(args, random_seed, constraints, **kwargs)
        self.args = args
        self.synchronous_rate = -1.0
        self.throughput_rate = -1.0
        self.async_rates: list[float] = []
        self.measured_rates: list[float] = []

    @property
    def strategy_types(self) -> list[str]:
        """
        :return: Strategy types for the complete sweep sequence
        """
        types = ["synchronous", "throughput"]
        types += [self.args.strategy_type] * (self.args.sweep_size - len(types))
        return types

    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> (
        AsyncConstantStrategy
        | AsyncPoissonStrategy
        | SynchronousStrategy
        | ThroughputStrategy
        | None
    ):
        """
        Generate next strategy in adaptive sweep sequence.

        Executes synchronous and throughput strategies first to measure baseline
        rates, then generates interpolated rates for async strategies. If a
        failure constraint is triggered during the async phase, all remaining
        higher rates are skipped.

        :param prev_strategy: Previously completed strategy instance
        :param prev_benchmark: Benchmark results from previous strategy execution
        :return: Next strategy in sweep sequence, or None if complete
        :raises ValueError: If strategy_type is neither 'constant' nor 'poisson'
        """
        if prev_strategy is None:
            return SynchronousStrategy()

        if prev_strategy.type_ == "synchronous":
            self.synchronous_rate = prev_benchmark.request_throughput.successful.mean

            return ThroughputStrategy(
                max_concurrency=self.args.max_concurrency,
                rampup_duration=self.args.rampup_duration,
            )

        if prev_strategy.type_ == "throughput":
            self.throughput_rate = prev_benchmark.request_throughput.successful.mean
            if self.synchronous_rate <= 0 and self.throughput_rate <= 0:
                raise RuntimeError(
                    "Invalid rates in sweep; aborting. "
                    "Were there any successful requests?"
                )
            self.measured_rates = list(
                np.linspace(
                    self.synchronous_rate,
                    self.throughput_rate,
                    self.args.sweep_size - 1,
                )
            )[1:]  # don't rerun synchronous

        # Stop escalation if a constraint with stopping_scope='all' triggered
        # during the async phase. Throughput is excluded because it intentionally
        # pushes beyond sustainable load. Synchronous never reaches here.
        if (
            prev_strategy.type_ != "throughput"
            and self._should_stop_escalating(prev_benchmark)  # type: ignore[arg-type]
        ):
            return None

        next_index = (
            len(self.completed_strategies) - 1 - 1
        )  # subtract synchronous and throughput
        next_rate = (
            self.measured_rates[next_index]
            if next_index < len(self.measured_rates)
            else None
        )

        if next_rate is None or next_rate <= 0:
            # Stop if we don't have another valid rate to run
            return None

        if self.args.strategy_type == "constant":
            return AsyncConstantStrategy(
                rate=next_rate, max_concurrency=self.args.max_concurrency
            )
        if self.args.strategy_type == "poisson":
            return AsyncPoissonStrategy(
                rate=next_rate,
                max_concurrency=self.args.max_concurrency,
                random_seed=self.random_seed,
            )
        raise ValueError(f"Invalid strategy type: {self.args.strategy_type}")

strategy_types property

Returns:

Type Description
list[str]

Strategy types for the complete sweep sequence

next_strategy(prev_strategy, prev_benchmark)

Generate next strategy in adaptive sweep sequence.

Executes synchronous and throughput strategies first to measure baseline rates, then generates interpolated rates for async strategies. If a failure constraint is triggered during the async phase, all remaining higher rates are skipped.

Parameters:

Name Type Description Default
prev_strategy SchedulingStrategy | None

Previously completed strategy instance

required
prev_benchmark Benchmark | None

Benchmark results from previous strategy execution

required

Returns:

Type Description
AsyncConstantStrategy | AsyncPoissonStrategy | SynchronousStrategy | ThroughputStrategy | None

Next strategy in sweep sequence, or None if complete

Raises:

Type Description
ValueError

If strategy_type is neither 'constant' nor 'poisson'

Source code in src/guidellm/benchmark/profiles/sweep.py
def next_strategy(
    self,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> (
    AsyncConstantStrategy
    | AsyncPoissonStrategy
    | SynchronousStrategy
    | ThroughputStrategy
    | None
):
    """
    Generate next strategy in adaptive sweep sequence.

    Executes synchronous and throughput strategies first to measure baseline
    rates, then generates interpolated rates for async strategies. If a
    failure constraint is triggered during the async phase, all remaining
    higher rates are skipped.

    :param prev_strategy: Previously completed strategy instance
    :param prev_benchmark: Benchmark results from previous strategy execution
    :return: Next strategy in sweep sequence, or None if complete
    :raises ValueError: If strategy_type is neither 'constant' nor 'poisson'
    """
    if prev_strategy is None:
        return SynchronousStrategy()

    if prev_strategy.type_ == "synchronous":
        self.synchronous_rate = prev_benchmark.request_throughput.successful.mean

        return ThroughputStrategy(
            max_concurrency=self.args.max_concurrency,
            rampup_duration=self.args.rampup_duration,
        )

    if prev_strategy.type_ == "throughput":
        self.throughput_rate = prev_benchmark.request_throughput.successful.mean
        if self.synchronous_rate <= 0 and self.throughput_rate <= 0:
            raise RuntimeError(
                "Invalid rates in sweep; aborting. "
                "Were there any successful requests?"
            )
        self.measured_rates = list(
            np.linspace(
                self.synchronous_rate,
                self.throughput_rate,
                self.args.sweep_size - 1,
            )
        )[1:]  # don't rerun synchronous

    # Stop escalation if a constraint with stopping_scope='all' triggered
    # during the async phase. Throughput is excluded because it intentionally
    # pushes beyond sustainable load. Synchronous never reaches here.
    if (
        prev_strategy.type_ != "throughput"
        and self._should_stop_escalating(prev_benchmark)  # type: ignore[arg-type]
    ):
        return None

    next_index = (
        len(self.completed_strategies) - 1 - 1
    )  # subtract synchronous and throughput
    next_rate = (
        self.measured_rates[next_index]
        if next_index < len(self.measured_rates)
        else None
    )

    if next_rate is None or next_rate <= 0:
        # Stop if we don't have another valid rate to run
        return None

    if self.args.strategy_type == "constant":
        return AsyncConstantStrategy(
            rate=next_rate, max_concurrency=self.args.max_concurrency
        )
    if self.args.strategy_type == "poisson":
        return AsyncPoissonStrategy(
            rate=next_rate,
            max_concurrency=self.args.max_concurrency,
            random_seed=self.random_seed,
        )
    raise ValueError(f"Invalid strategy type: {self.args.strategy_type}")

SynchronousProfile

Bases: Profile

Execute single synchronous strategy for baseline performance metrics.

Executes requests sequentially with one request at a time, establishing baseline performance metrics without concurrent execution overhead.

Source code in src/guidellm/benchmark/profiles/synchronous.py
@ProfileFactory.register("synchronous")
class SynchronousProfile(Profile):
    """
    Execute single synchronous strategy for baseline performance metrics.

    Executes requests sequentially with one request at a time, establishing
    baseline performance metrics without concurrent execution overhead.
    """

    args: SynchronousProfileArgs

    def __init__(
        self,
        args: SynchronousProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
        **kwargs: Any,
    ):
        super().__init__(args, random_seed, constraints, **kwargs)
        self.args = args

    @property
    def strategy_types(self) -> list[str]:
        """
        :return: Single synchronous strategy type
        """
        return [self.kind]

    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> SynchronousStrategy | None:
        """
        Generate synchronous strategy for first execution only.

        :param prev_strategy: Previously completed strategy (unused)
        :param prev_benchmark: Benchmark results from previous execution (unused)
        :return: SynchronousStrategy for first execution, None afterward
        """
        _ = (prev_strategy, prev_benchmark)  # unused
        if len(self.completed_strategies) >= 1:
            return None

        return SynchronousStrategy()

strategy_types property

Returns:

Type Description
list[str]

Single synchronous strategy type

next_strategy(prev_strategy, prev_benchmark)

Generate synchronous strategy for first execution only.

Parameters:

Name Type Description Default
prev_strategy SchedulingStrategy | None

Previously completed strategy (unused)

required
prev_benchmark Benchmark | None

Benchmark results from previous execution (unused)

required

Returns:

Type Description
SynchronousStrategy | None

SynchronousStrategy for first execution, None afterward

Source code in src/guidellm/benchmark/profiles/synchronous.py
def next_strategy(
    self,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> SynchronousStrategy | None:
    """
    Generate synchronous strategy for first execution only.

    :param prev_strategy: Previously completed strategy (unused)
    :param prev_benchmark: Benchmark results from previous execution (unused)
    :return: SynchronousStrategy for first execution, None afterward
    """
    _ = (prev_strategy, prev_benchmark)  # unused
    if len(self.completed_strategies) >= 1:
        return None

    return SynchronousStrategy()

ThroughputProfile

Bases: Profile

Maximize system throughput with optional concurrency constraints.

Maximizes system throughput by maintaining maximum concurrent requests, optionally constrained by a concurrency limit.

Source code in src/guidellm/benchmark/profiles/throughput.py
@ProfileFactory.register("throughput")
class ThroughputProfile(Profile):
    """
    Maximize system throughput with optional concurrency constraints.

    Maximizes system throughput by maintaining maximum concurrent requests,
    optionally constrained by a concurrency limit.
    """

    args: ThroughputProfileArgs

    def __init__(
        self,
        args: ThroughputProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
        **kwargs: Any,
    ):
        super().__init__(args, random_seed, constraints, **kwargs)
        self.args = args

    @property
    def strategy_types(self) -> list[str]:
        """
        :return: Single throughput strategy type
        """
        return [self.kind]

    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> ThroughputStrategy | None:
        """
        Generate throughput strategy for first execution only.

        :param prev_strategy: Previously completed strategy (unused)
        :param prev_benchmark: Benchmark results from previous execution (unused)
        :return: ThroughputStrategy for first execution, None afterward
        """
        _ = (prev_strategy, prev_benchmark)  # unused
        if len(self.completed_strategies) >= 1:
            return None

        return ThroughputStrategy(
            max_concurrency=self.args.max_concurrency,
            rampup_duration=self.args.rampup_duration,
        )

strategy_types property

Returns:

Type Description
list[str]

Single throughput strategy type

next_strategy(prev_strategy, prev_benchmark)

Generate throughput strategy for first execution only.

Parameters:

Name Type Description Default
prev_strategy SchedulingStrategy | None

Previously completed strategy (unused)

required
prev_benchmark Benchmark | None

Benchmark results from previous execution (unused)

required

Returns:

Type Description
ThroughputStrategy | None

ThroughputStrategy for first execution, None afterward

Source code in src/guidellm/benchmark/profiles/throughput.py
def next_strategy(
    self,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> ThroughputStrategy | None:
    """
    Generate throughput strategy for first execution only.

    :param prev_strategy: Previously completed strategy (unused)
    :param prev_benchmark: Benchmark results from previous execution (unused)
    :return: ThroughputStrategy for first execution, None afterward
    """
    _ = (prev_strategy, prev_benchmark)  # unused
    if len(self.completed_strategies) >= 1:
        return None

    return ThroughputStrategy(
        max_concurrency=self.args.max_concurrency,
        rampup_duration=self.args.rampup_duration,
    )

benchmark_generative_text(args, progress=None, console=None, **constraints) async

Execute a comprehensive generative text benchmarking workflow.

Orchestrates the full benchmarking pipeline by resolving all components from provided arguments, executing benchmark runs across configured profiles, and finalizing results in specified output formats. Components include backend initialization, data loading, profile configuration, and output generation.

Parameters:

Name Type Description Default
args BenchmarkScenario

Scenario configuration for the benchmark execution

required
progress GenerativeConsoleBenchmarkerProgress | None

Progress tracker for benchmark execution, or None for no tracking

None
console Console | None

Console instance for status reporting, or None for silent operation

None
constraints str | ConstraintInitializer | Any

Additional constraint initializers for benchmark limits

{}

Returns:

Type Description
tuple[GenerativeBenchmarksReport, list[tuple[str, Any]]]

Tuple of GenerativeBenchmarksReport and dictionary of output format results

Source code in src/guidellm/benchmark/entrypoints.py
async def benchmark_generative_text(
    args: BenchmarkScenario,
    progress: GenerativeConsoleBenchmarkerProgress | None = None,
    console: Console | None = None,
    **constraints: str | ConstraintInitializer | Any,
) -> tuple[GenerativeBenchmarksReport, list[tuple[str, Any]]]:
    """
    Execute a comprehensive generative text benchmarking workflow.

    Orchestrates the full benchmarking pipeline by resolving all components from
    provided arguments, executing benchmark runs across configured profiles, and
    finalizing results in specified output formats. Components include backend
    initialization, data loading, profile configuration, and output generation.

    :param args: Scenario configuration for the benchmark execution
    :param progress: Progress tracker for benchmark execution, or None for no tracking
    :param console: Console instance for status reporting, or None for silent operation
    :param constraints: Additional constraint initializers for benchmark limits
    :return: Tuple of GenerativeBenchmarksReport and dictionary of output format
        results
    """
    benchmark_args = resolve_to_single_benchmark(args.get_benchmarks())

    metrics_args = benchmark_args.metrics
    if not isinstance(metrics_args, GenerativeMetricsArgs):
        raise TypeError(
            f"Expected GenerativeMetricsArgs for generative text benchmark, "
            f"got {type(metrics_args).__name__}"
        )

    backend, model = await resolve_backend(
        backend_args=benchmark_args.backend,
        console=console,
    )
    await resolve_tokenizer(args=benchmark_args, model=model, console=console)
    request_loader: DataLoader[GenerationRequest] = await create_data_loader(
        loader_config=benchmark_args.data_loader,
        data_config=benchmark_args.data,
        tokenizer_config=benchmark_args.tokenizer,
        column_mapper_config=benchmark_args.data_column_mapper,
        preprocessors_config=benchmark_args.data_preprocessors,
        finalizer_config=benchmark_args.data_finalizer,
        random_seed=benchmark_args.seed.value,  # type: ignore[attr-defined]
        console=console,
    )

    warmup = benchmark_args.profile.warmup
    cooldown = benchmark_args.profile.cooldown

    constraints = resolve_constraints(benchmark_args, **constraints)
    profile = await resolve_profile(
        profile=benchmark_args.profile,
        constraints=constraints,
        console=console,
        random_seed=benchmark_args.seed.value,  # type: ignore[attr-defined]
    )
    output_formats = await resolve_output_formats(
        outputs=benchmark_args.outputs, console=console
    )

    report = GenerativeBenchmarksReport(config=args)
    if console:
        console.print_update(
            title="Setup complete, starting benchmarks...", status="success"
        )
        console.print("\n\n")

    benchmarker: Benchmarker[
        GenerativeBenchmark, GenerationRequest, GenerationResponse
    ] = Benchmarker()
    async for benchmark in benchmarker.run(
        accumulator_class=GenerativeBenchmarkAccumulator,
        benchmark_class=GenerativeBenchmark,
        requests=request_loader,  # type: ignore[arg-type]
        backend=backend,
        profile=profile,
        environment=NonDistributedEnvironment(),
        progress=progress,
        sample_size=metrics_args.sample_size,
        warmup=warmup,
        cooldown=cooldown,
        prefer_response_metrics=metrics_args.prefer_response_metrics,
    ):
        if benchmark:
            report.benchmarks.append(benchmark)

    output_format_results: list[tuple[str, Any]] = []
    for output_arg, output in zip(benchmark_args.outputs, output_formats, strict=True):
        output_format_results.append((output_arg.kind, await output.finalize(report)))

    if console:
        await GenerativeBenchmarkerConsole(console=console).finalize(report)
        console.print("\n\n")
        console.print_update(
            title=(
                "Benchmarking complete, generated "
                f"{len(report.benchmarks)} benchmark(s)"
            ),
            status="success",
        )
        for kind, value in output_format_results:
            console.print_update(title=f"  {kind:<8}: {value}", status="debug")

    return report, output_format_results

get_builtin_scenarios() cached

Retrieve all builtin scenario definitions from the scenarios directory.

Scans the scenarios directory for JSON files and returns a mapping of scenario names to their file paths. Each scenario is indexed by both its stem name (filename without extension) and full filename for convenient lookup.

Returns:

Type Description
dict[str, Path]

Dictionary mapping scenario names and filenames to their Path objects

Source code in src/guidellm/benchmark/scenarios/__init__.py
@cache
def get_builtin_scenarios() -> dict[str, Path]:
    """
    Retrieve all builtin scenario definitions from the scenarios directory.

    Scans the scenarios directory for JSON files and returns a mapping of scenario
    names to their file paths. Each scenario is indexed by both its stem name
    (filename without extension) and full filename for convenient lookup.

    :return: Dictionary mapping scenario names and filenames to their Path objects
    """
    builtin = {}
    for path in SCENARIO_DIR.glob("*.json"):
        builtin[path.stem] = path
        builtin[path.name] = path

    return builtin

reimport_benchmarks_report(file, outputs) async

Load and re-export an existing benchmarks report in specified output formats.

Parameters:

Name Type Description Default
file Path

Path to the existing benchmark report file to load

required
outputs tuple[BenchmarkOutputArgs, ...] | list[dict[str, Any]]

Output format kind strings to resolve and finalize

required

Returns:

Type Description
tuple[GenerativeBenchmarksReport, list[tuple[str, Any]]]

Tuple of loaded GenerativeBenchmarksReport and dictionary of output results

Source code in src/guidellm/benchmark/entrypoints.py
async def reimport_benchmarks_report(
    file: Path,
    outputs: tuple[BenchmarkOutputArgs, ...] | list[dict[str, Any]],
) -> tuple[GenerativeBenchmarksReport, list[tuple[str, Any]]]:
    """
    Load and re-export an existing benchmarks report in specified output formats.

    :param file: Path to the existing benchmark report file to load
    :param outputs: Output format kind strings to resolve and finalize
    :return: Tuple of loaded GenerativeBenchmarksReport and dictionary of output
        results
    """
    console = Console()

    with console.print_update_step(
        title=f"Loading benchmarks from {file}..."
    ) as console_step:
        report = GenerativeBenchmarksReport.load_file(file)
        console_step.finish(
            "Import of old benchmarks complete;"
            f" loaded {len(report.benchmarks)} benchmark(s)"
        )

    output_args: list[BenchmarkOutputArgs] = []
    for fmt in outputs:
        output_args.append(BenchmarkOutputArgs.model_validate(fmt))

    output_results: list[tuple[str, Any]] = []
    for args in output_args:
        output = GenerativeBenchmarkerOutput.resolve(args)
        output_results.append((args.kind, await output.finalize(report)))

    for kind, value in output_results:
        console.print_update(title=f"  {kind:<8}: {value}", status="debug")

    return report, output_results