Skip to content

guidellm.benchmark.profiles.knee

Concurrent benchmark profile that estimates and refines a throughput knee.

KneeProfile

Bases: Profile

Analyze an initial concurrency sweep and optionally refine its knee once.

Source code in src/guidellm/benchmark/profiles/knee.py
@ProfileFactory.register("knee")
class KneeProfile(Profile):
    """Analyze an initial concurrency sweep and optionally refine its knee once."""

    args: KneeProfileArgs

    def __init__(
        self,
        args: KneeProfileArgs,
        random_seed: int,
        constraints: MutableMapping[str, ConstraintInitializer | Any] | None,
        **kwargs: Any,
    ):
        super().__init__(args, random_seed, constraints, **kwargs)
        self.args = args
        self._initial_streams = args.resolved_initial_streams()
        self._streams = list(self._initial_streams)
        self._benchmarks: list[GenerativeBenchmark] = []
        self._initial: KneeAnalysis | None = None
        self._adaptive_plan: AdaptiveConcurrencyPlan | None = None
        self._conclusion: KneeDetectionConclusion | None = None

    @property
    def strategy_types(self) -> list[str]:
        """
        Reserve progress slots for the initial sweep and possible adaptive points.

        :return: Concurrent strategy types, one per possible benchmark
        """
        extra = 2 * self.args.points_each_side + 1 if self.args.adaptive else 0
        return ["concurrent"] * (len(self._initial_streams) + extra)

    @property
    def conclusion(self) -> dict[str, Any] | None:
        """
        :return: Initial analysis, adaptive plan and final analysis after completion
        """
        return self._conclusion.model_dump(mode="json") if self._conclusion else None

    def next_strategy(
        self,
        prev_strategy: SchedulingStrategy | None,
        prev_benchmark: Benchmark | None,
    ) -> ConcurrentStrategy | None:
        """
        Execute the initial points followed by at most one adaptive grid.

        :param prev_strategy: Previously completed strategy
        :param prev_benchmark: Benchmark results from the previous concurrency
        :return: Next concurrent strategy, or None when complete or stopped
        :raises RuntimeError: If the previous result is not a generative benchmark
        """
        _ = prev_strategy
        if self._conclusion is not None:
            return None

        stopped = False
        if prev_benchmark is not None:
            if not isinstance(prev_benchmark, GenerativeBenchmark):
                raise RuntimeError(
                    "The knee profile requires generative benchmark results, "
                    f"got {type(prev_benchmark).__name__}."
                )
            self._benchmarks.append(prev_benchmark)
            stopped = self._should_stop_escalating(prev_benchmark) or any(
                action.stopping_scope == "all"
                for action in (
                    prev_benchmark.scheduler_state.end_processing_constraints.values()
                )
            )

        if self._initial is None and (
            stopped or len(self._benchmarks) == len(self._initial_streams)
        ):
            self._plan_refinement(stopped)

        index = len(self.completed_strategies)
        if stopped or index >= len(self._streams):
            self._finish()
            return None

        return ConcurrentStrategy(
            streams=self._streams[index],
            rampup_duration=self.args.rampup_duration,
        )

    def _plan_refinement(self, stopped: bool) -> None:
        """Analyze the initial sweep and append eligible adaptive points."""
        self._initial = analyze_knee(self._benchmarks)
        if stopped:
            self._adaptive_plan = AdaptiveConcurrencyPlan(
                status="skipped",
                reason=(
                    "An initial benchmark triggered a stopping_scope='all' constraint"
                ),
            )
        elif not self.args.adaptive:
            self._adaptive_plan = AdaptiveConcurrencyPlan(
                status="skipped", reason="Adaptive refinement is disabled"
            )
        else:
            self._adaptive_plan = generate_adaptive_concurrency_plan(
                self._initial,
                [benchmark_concurrency(benchmark) for benchmark in self._benchmarks],
                points_each_side=self.args.points_each_side,
                max_step=self.args.max_step,
            )
        self._streams.extend(self._adaptive_plan.concurrencies)
        logger.debug(
            "Knee profile adaptive plan: {} ({})",
            self._adaptive_plan.concurrencies,
            self._adaptive_plan.reason,
        )

    def _finish(self) -> None:
        """Include the last measurement in the final profile conclusion."""
        if self._initial is None or self._adaptive_plan is None:
            raise RuntimeError("The knee profile finished before analyzing its sweep")
        self._conclusion = KneeDetectionConclusion(
            initial=self._initial,
            adaptive_plan=self._adaptive_plan,
            final=analyze_knee(self._benchmarks),
        )
        result = self._conclusion.final.throughput
        logger.debug(
            "Knee profile complete after {} benchmarks: knee={} ({})",
            len(self._benchmarks),
            result.knee,
            result.reason,
        )

conclusion property

Returns:

Type Description
dict[str, Any] | None

Initial analysis, adaptive plan and final analysis after completion

strategy_types property

Reserve progress slots for the initial sweep and possible adaptive points.

Returns:

Type Description
list[str]

Concurrent strategy types, one per possible benchmark

next_strategy(prev_strategy, prev_benchmark)

Execute the initial points followed by at most one adaptive grid.

Parameters:

Name Type Description Default
prev_strategy SchedulingStrategy | None

Previously completed strategy

required
prev_benchmark Benchmark | None

Benchmark results from the previous concurrency

required

Returns:

Type Description
ConcurrentStrategy | None

Next concurrent strategy, or None when complete or stopped

Raises:

Type Description
RuntimeError

If the previous result is not a generative benchmark

Source code in src/guidellm/benchmark/profiles/knee.py
def next_strategy(
    self,
    prev_strategy: SchedulingStrategy | None,
    prev_benchmark: Benchmark | None,
) -> ConcurrentStrategy | None:
    """
    Execute the initial points followed by at most one adaptive grid.

    :param prev_strategy: Previously completed strategy
    :param prev_benchmark: Benchmark results from the previous concurrency
    :return: Next concurrent strategy, or None when complete or stopped
    :raises RuntimeError: If the previous result is not a generative benchmark
    """
    _ = prev_strategy
    if self._conclusion is not None:
        return None

    stopped = False
    if prev_benchmark is not None:
        if not isinstance(prev_benchmark, GenerativeBenchmark):
            raise RuntimeError(
                "The knee profile requires generative benchmark results, "
                f"got {type(prev_benchmark).__name__}."
            )
        self._benchmarks.append(prev_benchmark)
        stopped = self._should_stop_escalating(prev_benchmark) or any(
            action.stopping_scope == "all"
            for action in (
                prev_benchmark.scheduler_state.end_processing_constraints.values()
            )
        )

    if self._initial is None and (
        stopped or len(self._benchmarks) == len(self._initial_streams)
    ):
        self._plan_refinement(stopped)

    index = len(self.completed_strategies)
    if stopped or index >= len(self._streams):
        self._finish()
        return None

    return ConcurrentStrategy(
        streams=self._streams[index],
        rampup_duration=self.args.rampup_duration,
    )