Skip to content

guidellm.benchmark.profiles

Orchestrate multi-strategy benchmark execution through configurable profiles.

Provides abstractions for coordinating sequential execution of scheduling strategies during benchmarking workflows. Profiles automatically generate strategies based on configuration parameters, manage runtime constraints, and track completion state across execution sequences. Each profile type implements a specific execution pattern (synchronous, concurrent, throughput-focused, rate-based async, or adaptive sweep) that determines how benchmark requests are scheduled and executed.

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}")

AsyncProfileArgs

Bases: ProfileArgs

Pydantic model for asynchronous profile creation arguments.

Source code in src/guidellm/benchmark/profiles/asynchronous.py
@ProfileArgs.register(["async", "constant", "poisson"])
class AsyncProfileArgs(ProfileArgs):
    """Pydantic model for asynchronous profile creation arguments."""

    kind: Literal["async", "constant", "poisson"] = Field(
        default="async",
        description="Profile type discriminator for asynchronous scheduling",
    )
    rate: list[PositiveFloat] = Field(
        description="Request scheduling rates in requests per second",
        examples=[1.0, [1.0, 2.0, 3.0]],
    )
    max_concurrency: PositiveInt | None = Field(
        default=None,
        description="Maximum concurrent requests to schedule",
        examples=[10],
    )

    @field_validator("rate", mode="before")
    @classmethod
    def _coerce_rate_to_list(
        cls, value: list[PositiveFloat] | PositiveFloat
    ) -> list[PositiveFloat]:
        """Normalize rate to a list of integers.

        Allow single integer or list of integers.
        """
        if isinstance(value, str):
            with contextlib.suppress(json.JSONDecodeError, ValueError):
                value = json.loads(value)
        if not value:
            raise ValueError("rate requires at least one value")
        if isinstance(value, list | tuple):
            return value
        if isinstance(value, int | float):
            return [value]
        raise ValueError(
            "rate must be a number or a list of numeric values, "
            f"got {type(value).__name__}"
        )

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,
    )

ConcurrentProfileArgs

Bases: ProfileArgs

Pydantic model for concurrent profile creation arguments.

Source code in src/guidellm/benchmark/profiles/concurrent.py
@ProfileArgs.register("concurrent")
class ConcurrentProfileArgs(ProfileArgs):
    """Pydantic model for concurrent profile creation arguments."""

    kind: Literal["concurrent"] = Field(
        default="concurrent",
        description="Profile type discriminator for concurrent scheduling",
    )
    streams: list[PositiveInt] = Field(
        description="Concurrent stream counts to execute",
        examples=[[1, 2, 3], 10],
    )

    @field_validator("streams", mode="before")
    @classmethod
    def _coerce_streams_to_list(cls, value: Any) -> Any:
        """Normalize streams to a list of integers.

        Allow single integer or list of integers.
        """
        if isinstance(value, str):
            with contextlib.suppress(json.JSONDecodeError, ValueError):
                value = json.loads(value)
        if not value:
            raise ValueError("streams requires at least one value")
        if isinstance(value, list | tuple):
            return [int(stream) for stream in value]
        if isinstance(value, int | float):
            return [int(value)]
        raise ValueError(
            "streams must be a number or a list of numeric values, "
            f"got {type(value).__name__}"
        )

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)

ProfileFactory

Bases: RegistryMixin['type[Profile]']

Source code in src/guidellm/benchmark/profiles/profile.py
class ProfileFactory(RegistryMixin["type[Profile]"]):
    @classmethod
    def create(
        cls,
        args: ProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None = None,
        **kwargs: Any,
    ) -> Profile:
        """
        Create profile instances from validated profile arguments.

        :param args: Validated profile argument model for the target 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
        :return: Configured profile instance for the specified type
        :raises ValueError: If the profile kind is not registered
        """
        kind = args.kind

        profile_class = cls.get_registered_object(kind)

        if profile_class is None:
            raise ValueError(
                f"Profile type '{kind}' is not registered. "
                f"Available types: {list(cls.registry.keys()) if cls.registry else []}"
            )

        return profile_class(args, random_seed, constraints, **kwargs)

    @classmethod
    def registered_names(cls) -> tuple[str, ...]:
        """
        Get all registered names from the registry.
        """
        return tuple(cls.registry.keys() if cls.registry else [])

create(args, random_seed, constraints=None, **kwargs) classmethod

Create profile instances from validated profile arguments.

Parameters:

Name Type Description Default
args ProfileArgs

Validated profile argument model for the target 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.

None
kwargs Any

Additional profile-specific configuration parameters

{}

Returns:

Type Description
Profile

Configured profile instance for the specified type

Raises:

Type Description
ValueError

If the profile kind is not registered

Source code in src/guidellm/benchmark/profiles/profile.py
@classmethod
def create(
    cls,
    args: ProfileArgs,
    random_seed: int,
    constraints: MutableMapping[str, ConstraintInitializer | Any] | None = None,
    **kwargs: Any,
) -> Profile:
    """
    Create profile instances from validated profile arguments.

    :param args: Validated profile argument model for the target 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
    :return: Configured profile instance for the specified type
    :raises ValueError: If the profile kind is not registered
    """
    kind = args.kind

    profile_class = cls.get_registered_object(kind)

    if profile_class is None:
        raise ValueError(
            f"Profile type '{kind}' is not registered. "
            f"Available types: {list(cls.registry.keys()) if cls.registry else []}"
        )

    return profile_class(args, random_seed, constraints, **kwargs)

registered_names() classmethod

Get all registered names from the registry.

Source code in src/guidellm/benchmark/profiles/profile.py
@classmethod
def registered_names(cls) -> tuple[str, ...]:
    """
    Get all registered names from the registry.
    """
    return tuple(cls.registry.keys() if cls.registry else [])

ReplayProfile

Bases: Profile

Replay a trace file using per-row relative_timestamp from the dataset.

Each request is scheduled at start_time + time_scale * relative_timestamp via RequestSettings on the dataset finalizer output. For this profile, rate is interpreted as time_scale (not requests per second).

When data_samples is set, the default max_requests constraint matches the truncated dataset size.

Source code in src/guidellm/benchmark/profiles/replay.py
@ProfileFactory.register("replay")
class ReplayProfile(Profile):
    """
    Replay a trace file using per-row ``relative_timestamp`` from the dataset.

    Each request is scheduled at
    ``start_time + time_scale * relative_timestamp`` via ``RequestSettings`` on
    the dataset finalizer output. For this profile, ``rate`` is interpreted as
    ``time_scale`` (not requests per second).

    When ``data_samples`` is set, the default ``max_requests`` constraint matches
    the truncated dataset size.
    """

    args: ReplayProfileArgs

    def __init__(
        self,
        args: ReplayProfileArgs,
        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 ["trace"]

    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> TraceReplayStrategy | None:
        _ = prev_benchmark
        # Replay has a single strategy; return it once, then None
        if prev_strategy is not None:
            return None
        return TraceReplayStrategy(time_scale=self.args.time_scale)

ReplayProfileArgs

Bases: ProfileArgs

Pydantic model for trace replay profile creation arguments.

Source code in src/guidellm/benchmark/profiles/replay.py
@ProfileArgs.register("replay")
class ReplayProfileArgs(ProfileArgs):
    """Pydantic model for trace replay profile creation arguments."""

    kind: Literal["replay"] = Field(
        default="replay",
        description="Profile type discriminator for trace replay scheduling",
    )
    time_scale: float = Field(
        default=1.0,
        gt=0,
        description="Scale factor applied to relative timestamps",
    )

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}")

SweepProfileArgs

Bases: ProfileArgs

Pydantic model for sweep profile creation arguments.

Source code in src/guidellm/benchmark/profiles/sweep.py
@ProfileArgs.register("sweep")
class SweepProfileArgs(ProfileArgs):
    """Pydantic model for sweep profile creation arguments."""

    kind: Literal["sweep"] = Field(
        default="sweep",
        description="Profile type discriminator for sweep scheduling",
    )
    sweep_size: int = Field(
        default=10,
        description="Number of strategies to generate for the sweep",
        ge=2,
    )
    strategy_type: Literal["constant", "poisson"] = Field(
        default="constant",
        description="Type of strategy to use for the asynchronous sweep",
    )
    max_concurrency: PositiveInt | None = Field(
        default=512,
        description="Maximum concurrent requests to schedule",
    )

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()

SynchronousProfileArgs

Bases: ProfileArgs

Pydantic model for synchronous profile creation arguments.

Source code in src/guidellm/benchmark/profiles/synchronous.py
@ProfileArgs.register("synchronous")
class SynchronousProfileArgs(ProfileArgs):
    """Pydantic model for synchronous profile creation arguments."""

    kind: Literal["synchronous"] = Field(
        default="synchronous",
        description="Profile type discriminator for synchronous scheduling",
    )

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,
    )

ThroughputProfileArgs

Bases: ProfileArgs

Pydantic model for throughput profile creation arguments.

Source code in src/guidellm/benchmark/profiles/throughput.py
@ProfileArgs.register("throughput")
class ThroughputProfileArgs(ProfileArgs):
    """Pydantic model for throughput profile creation arguments."""

    kind: Literal["throughput"] = Field(
        default="throughput",
        description="Profile type discriminator for throughput scheduling",
    )
    max_concurrency: PositiveInt | None = Field(
        description="Maximum concurrent requests to schedule",
        examples=[10],
    )