Skip to content

Commit b54ab14

Browse files
Lint fixes
1 parent 2fe64c7 commit b54ab14

File tree

7 files changed

+93
-53
lines changed

7 files changed

+93
-53
lines changed

src/guidellm/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ def cli():
168168
type=float,
169169
help=(
170170
"The maximum error rate after which a benchmark will stop. "
171-
"Applicable only for finite deterministic scenarios i.e rate_type is 'constant' and 'max_seconds' exists OR "
171+
"Applicable only for finite deterministic scenarios i.e "
172+
"rate_type is 'constant' and 'max_seconds' exists OR "
172173
"'max_requests' exists OR the dataset is finite. "
173174
"If None or not applicable, benchmarks will continue regardless of error rate."
174175
),

src/guidellm/benchmark/aggregator.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,8 +599,8 @@ def compile(self) -> GenerativeBenchmark:
599599
and return the compiled object.
600600
"""
601601
successful, incomplete, errored = self._compile_results()
602-
error_rate = self.requests_stats.totals.errored.total / \
603-
(self.requests_stats.totals.successful.total + self.requests_stats.totals.errored.total)
602+
603+
error_rate = self._calculate_error_rate()
604604

605605
return GenerativeBenchmark.from_stats(
606606
run_id=self.run_id,
@@ -634,6 +634,12 @@ def compile(self) -> GenerativeBenchmark:
634634
extras=self.extras,
635635
)
636636

637+
def _calculate_error_rate(self) -> float:
638+
total_successful = self.requests_stats.totals.successful.total
639+
total_errored = self.requests_stats.totals.errored.total
640+
total_sent = total_errored + total_successful
641+
return total_errored / total_sent
642+
637643
def _compile_results(
638644
self,
639645
) -> tuple[

src/guidellm/benchmark/benchmark.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,10 @@ class BenchmarkRunStats(StandardBaseModel):
218218
)
219219
error_rate: float = Field(
220220
description=(
221-
"The number of errored requests divided by the number of errored requests. This can be higher "
222-
"than max_error_rate (if applicable) cause it does not take into account incomplete requests."
221+
"The number of errored requests divided by the number "
222+
"of errored requests. This can be higher than max_error_rate "
223+
"(if applicable) cause it does not take into "
224+
"account incomplete requests."
223225
)
224226
)
225227

src/guidellm/request/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from .loader import (
22
GenerativeRequestLoader,
33
GenerativeRequestLoaderDescription,
4+
GetInfiniteDatasetLengthError,
45
RequestLoader,
56
RequestLoaderDescription,
67
)
@@ -10,6 +11,7 @@
1011
"GenerationRequest",
1112
"GenerativeRequestLoader",
1213
"GenerativeRequestLoaderDescription",
14+
"GetInfiniteDatasetLengthError",
1315
"RequestLoader",
1416
"RequestLoaderDescription",
1517
]

src/guidellm/request/loader.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
__all__ = [
2020
"GenerativeRequestLoader",
2121
"GenerativeRequestLoaderDescription",
22+
"GetInfiniteDatasetLengthError",
2223
"RequestLoader",
2324
"RequestLoaderDescription",
24-
"InfiniteDatasetError"
2525
]
2626

2727

28-
class InfiniteDatasetError(Exception):
28+
class GetInfiniteDatasetLengthError(Exception):
2929
pass
3030

3131

@@ -125,8 +125,11 @@ def __len__(self) -> int:
125125
if self.iter_type == "finite":
126126
return self.num_unique_items()
127127

128-
assert self.iter_type == "infinite"
129-
raise InfiniteDatasetError(f"Dataset {self.data} is infinite and thus unable to determine length")
128+
if self.iter_type != "infinite":
129+
raise ValueError(f"Invalid iter_type {self.iter_type}")
130+
raise GetInfiniteDatasetLengthError(f"Dataset {self.data} is "
131+
f"infinite and thus "
132+
f"unable to determine length")
130133

131134
@property
132135
def description(self) -> GenerativeRequestLoaderDescription:

src/guidellm/scheduler/scheduler.py

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from loguru import logger
1616

1717
from guidellm.config import settings
18-
from guidellm.request.loader import InfiniteDatasetError
18+
from guidellm.request.loader import GetInfiniteDatasetLengthError
1919
from guidellm.scheduler.result import (
2020
SchedulerRequestResult,
2121
SchedulerResult,
@@ -101,24 +101,15 @@ async def run(
101101
:param max_duration: The maximum duration for the scheduling run.
102102
If None, then no limit is set and either the iterator must be exhaustible
103103
or the max_number must be set.
104-
:param max_error_rate: The maximum error rate after which the scheduler shuts down.
104+
:param max_error_rate: The maximum error rate after which the
105+
scheduler shuts down.
105106
Only applicable in benchmarks with finite deterministic number of requests.
106107
If None or not applicable then scheduler will continue regardless of errors.
107108
:return: An asynchronous generator that yields SchedulerResult objects.
108109
Each SchedulerResult object contains information about the request,
109110
the response, and the run information.
110111
"""
111-
if scheduling_strategy is None or not isinstance(
112-
scheduling_strategy, SchedulingStrategy
113-
):
114-
raise ValueError(f"Invalid scheduling strategy: {scheduling_strategy}")
115-
116-
if max_number is not None and max_number < 1:
117-
raise ValueError(f"Invalid max_number: {max_number}")
118-
if max_duration is not None and max_duration < 0:
119-
raise ValueError(f"Invalid max_duration: {max_duration}")
120-
if max_error_rate is not None and (max_error_rate < 0 or max_error_rate > 1):
121-
raise ValueError(f"Invalid max_error_rate: {max_error_rate}")
112+
self._validate_scheduler_params(scheduling_strategy, max_duration, max_error_rate, max_number)
122113

123114
with (
124115
multiprocessing.Manager() as manager,
@@ -127,11 +118,13 @@ async def run(
127118
) as executor,
128119
):
129120
requests_iter: Optional[Iterator[Any]] = None
130-
futures, requests_queue, responses_queue, shutdown_event = await self._start_processes(
131-
manager, executor, scheduling_strategy, max_error_rate is not None
132-
)
133-
if shutdown_event:
134-
assert not shutdown_event.is_set(), "shutdown_event is set before starting scheduling"
121+
futures, requests_queue, responses_queue, shutdown_event = \
122+
await self._start_processes(
123+
manager, executor, scheduling_strategy, max_error_rate is not None)
124+
if shutdown_event and shutdown_event.is_set():
125+
raise RuntimeError(
126+
"shutdown_event is set before starting scheduling"
127+
)
135128
run_info, requests_iter, times_iter = self._run_setup(
136129
futures, scheduling_strategy, max_number, max_duration, max_error_rate
137130
)
@@ -169,17 +162,14 @@ async def run(
169162
run_info,
170163
)
171164
if iter_result is not None:
172-
if iter_result.request_info.errored and not iter_result.request_info.canceled:
173-
current_error_rate = run_info.errored_requests / run_info.end_number
174-
is_over_max_error_rate = run_info.max_error_rate < current_error_rate
175-
176-
if is_over_max_error_rate:
177-
shutdown_event.set()
178-
max_error_rate_reached = True
179-
logger.info(f"Max error rate of ({iter_result.run_info.max_error_rate}) "
180-
f"reached, sending shutdown signal")
181-
else:
182-
logger.debug(f"Current error rate: {current_error_rate}")
165+
if iter_result.request_info.errored \
166+
and not iter_result.request_info.canceled \
167+
and self._is_max_error_rate_reached(iter_result.run_info):
168+
shutdown_event.set()
169+
max_error_rate_reached = True
170+
logger.info(f"Max error rate of "
171+
f"({iter_result.run_info.max_error_rate}) "
172+
f"reached, sending shutdown signal")
183173
yield iter_result
184174

185175
# yield control to the event loop
@@ -194,6 +184,28 @@ async def run(
194184

195185
await self._stop_processes(futures, requests_queue)
196186

187+
def _validate_scheduler_params(
188+
self,
189+
scheduling_strategy: SchedulingStrategy,
190+
max_duration: Optional[float],
191+
max_error_rate: Optional[float],
192+
max_number: Optional[int]
193+
) -> None:
194+
if scheduling_strategy is None or not isinstance(
195+
scheduling_strategy, SchedulingStrategy
196+
):
197+
raise ValueError(f"Invalid scheduling strategy: {scheduling_strategy}")
198+
if max_number is not None and max_number < 1:
199+
raise ValueError(f"Invalid max_number: {max_number}")
200+
if max_duration is not None and max_duration < 0:
201+
raise ValueError(f"Invalid max_duration: {max_duration}")
202+
if max_error_rate is not None and (max_error_rate < 0 or max_error_rate > 1):
203+
raise ValueError(f"Invalid max_error_rate: {max_error_rate}")
204+
205+
def _is_max_error_rate_reached(self, run_info) -> bool:
206+
current_error_rate = run_info.errored_requests / run_info.end_number
207+
return run_info.max_error_rate < current_error_rate
208+
197209
async def _start_processes(
198210
self,
199211
manager,
@@ -282,10 +294,13 @@ def _run_setup(
282294
start_time = time.time()
283295
times_iter = iter(scheduling_strategy.request_times())
284296
end_time = time.time() + (max_duration or math.inf)
285-
end_number = self._determine_total_requests_count(scheduling_strategy, max_duration, max_number)
297+
end_number = self._determine_total_requests_count(
298+
scheduling_strategy, max_duration, max_number
299+
)
286300

287301
if end_number == math.inf and max_error_rate is not None:
288-
logger.warning("max_error_rate will be ignored because end_number can not be determined.")
302+
logger.warning("max_error_rate will be ignored "
303+
"because end_number can not be determined.")
289304

290305
if end_number == math.inf and end_time is None:
291306
logger.warning(
@@ -312,17 +327,19 @@ def _determine_total_requests_count(
312327
) -> int:
313328
end_number = max_number or math.inf
314329
try:
315-
# update end number if the request loader is finite and less than max
330+
# update end_number if the request_loader is finite and less than max_number
316331
iter_length = len(self.request_loader) # type: ignore[arg-type]
317332
if 0 < iter_length < end_number:
318333
end_number = iter_length
319-
except InfiniteDatasetError:
320-
# Only when RPS is constant and duration is capped we can determine the total
321-
# amount of requests that are supposed to be sent
334+
except GetInfiniteDatasetLengthError:
335+
# Only when RPS is constant and duration is
336+
# capped we can determine the total amount of requests
337+
# that are supposed to be sent
322338
if scheduling_strategy.type_ == "constant" and max_duration is not None:
323-
total_requests_in_max_duration = int(scheduling_strategy.rate * max_duration)
324-
if total_requests_in_max_duration < end_number:
325-
assert total_requests_in_max_duration > 0
339+
total_requests_in_max_duration = int(
340+
scheduling_strategy.rate * max_duration
341+
)
342+
if 0 < total_requests_in_max_duration < end_number:
326343
end_number = total_requests_in_max_duration
327344
except Exception: # noqa: BLE001, S110
328345
pass

src/guidellm/scheduler/worker.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,18 +128,26 @@ async def get_request(
128128
process_id: Optional[int] = None,
129129
) -> Optional[WorkerProcessRequest[RequestT]]:
130130
if shutdown_event is not None and process_id is None:
131-
logger.warning("shutdown_event is not None and process_id is None which makes it hard to debug")
131+
logger.warning("shutdown_event is not None and process_id "
132+
"is None which makes it hard to debug")
132133

133134
def _get_queue_intermittently():
134-
assert shutdown_event is not None
135+
if shutdown_event is None:
136+
raise ValueError("Shouldn't use _get_queue_intermittently "
137+
"if there's no shutdown_even")
135138
while True:
136139
try:
137-
return requests_queue.get(timeout=timedelta(seconds=1).total_seconds())
140+
get_timeout = timedelta(seconds=1).total_seconds()
141+
return requests_queue.get(timeout=get_timeout)
138142
except queue.Empty:
139143
if shutdown_event.is_set():
140144
logger.info(f"Shutdown signal received in future {process_id}")
141-
return
142-
return await asyncio.to_thread(_get_queue_intermittently if shutdown_event is not None else requests_queue.get) # type: ignore[attr-defined]
145+
return None
146+
147+
get_method = _get_queue_intermittently \
148+
if shutdown_event is not None \
149+
else requests_queue.get
150+
return await asyncio.to_thread(get_method) # type: ignore[attr-defined]
143151

144152
async def send_result(
145153
self,
@@ -165,7 +173,8 @@ async def resolve_scheduler_request(
165173
scheduled_time=time.time(),
166174
process_id=process_id,
167175
)
168-
request_scheduled_result: WorkerProcessResult[RequestT, ResponseT] = WorkerProcessResult(
176+
request_scheduled_result: WorkerProcessResult[RequestT, ResponseT] = \
177+
WorkerProcessResult(
169178
type_="request_scheduled",
170179
request=request,
171180
response=None,

0 commit comments

Comments
 (0)