Skip to content

guidellm.benchmark.profiles.concurrent

Concurrent benchmark profile.

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