mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-30 06:43:27 +00:00
* test(perf): add small_bodies_30rps and mixed_size_requests_4rps load cases Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): run the load cases at 50 rps small and 5 rps mixed, the pod's knee Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): ramp the load cases until the pod stops keeping up and report sustained_rps Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): hand the ramp to the observation and widen the mixed ramp to 14 rps Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): floor the small ramp at 20 rps and emit the per-step readings Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): emit the ramp's hold bound and each step's unexpected statuses Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): read each ramp step's cpu, redis latency and connections from the samplers' windows Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): floor mixed_size_requests_ramp at 8 rps from the lane's 10 rps sustained step Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * test(perf): compare step readings with math.isclose so the e2e basedpyright gate stays clean Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: kerry <kerry@berri.ai> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
48 lines
1.5 KiB
Python
48 lines
1.5 KiB
Python
"""Readings a background sampler takes while the traffic runs, each stamped with the wall clock
|
|
(`time.time()`, the clock the Locust records carry in `started_at`), so a ramped run can cut them into its
|
|
steps' windows after the fact."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
from dataclasses import dataclass
|
|
from typing import Final, Generic, TypeVar
|
|
|
|
T = TypeVar("T")
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Sample(Generic[T]):
|
|
at: float
|
|
value: T
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class Series(Generic[T]):
|
|
samples: tuple[Sample[T], ...]
|
|
|
|
def between(self, start: float, end: float) -> tuple[T, ...]:
|
|
"""The values stamped inside `[start, end)`, in time order."""
|
|
return tuple(sample.value for sample in self.samples if start <= sample.at < end)
|
|
|
|
def last_before(self, at: float) -> T | None:
|
|
"""The newest value stamped before `at`, None when the series starts later."""
|
|
earlier: Final = tuple(sample.value for sample in self.samples if sample.at < at)
|
|
return earlier[-1] if earlier else None
|
|
|
|
|
|
class Recorder(Generic[T]):
|
|
"""What a sampler thread appends to; `series` is a frozen copy for the observation."""
|
|
|
|
def __init__(self) -> None:
|
|
self._samples: list[Sample[T]] = []
|
|
|
|
def record(self, value: T) -> None:
|
|
self._samples.append(Sample(at=time.time(), value=value))
|
|
|
|
@property
|
|
def series(self) -> Series[T]:
|
|
return Series(samples=tuple(self._samples))
|
|
|
|
def __len__(self) -> int:
|
|
return len(self._samples)
|