-
Notifications
You must be signed in to change notification settings - Fork 88
Multi Process Scheduler Implementation, Benchmarker, and Report Generation Refactor #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 14 commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
1e21612
Adds aiohttp backend
anmarques ce0c3c5
quality fixes
anmarques 8cb9876
Quality fixes
anmarques 039900a
Rework for OpenAI backend to use native http requests with httpx and …
markurtz 2b82bd5
Finalize implementation, fix bugs, and ensure unit tests are passing …
markurtz a01db7d
Initial state for Scheduling system rework. Still needs testing and f…
markurtz 85dee09
Enable temp testing script to work, refactor strategy to be more gene…
markurtz fb3fdd7
Polishing for scheduler
markurtz 12835e0
styling fixes
markurtz 65869d7
initial groundwork for new benchmark package and classes along with r…
markurtz 53e0943
finalize benchmark model objects
markurtz faacb63
Latest state with datasets and benchmarker created
markurtz 34f851c
latest working state with data loaders and benchmarking API
markurtz cfdc2ed
Working clis and entrypoints
markurtz d4f8c1a
Fixes for bugs surfaced from testing and enhancements to features bas…
markurtz 0a6230b
Update src/guidellm/scheduler/scheduler.py
markurtz 62cd7e9
Fix synthetic data generation edge case where text is much larger tha…
markurtz 94efbd4
Update src/guidellm/dataset/synthetic.py
markurtz a3e86d8
Update src/guidellm/benchmark/benchmark.py
markurtz c7476ab
Update src/guidellm/benchmark/benchmark.py
markurtz 3d8cd62
Update src/guidellm/benchmark/benchmark.py
markurtz dbc4789
Update src/guidellm/benchmark/benchmark.py
markurtz 649a86d
Updates for pydantic export with polymorphism and general cleanup
markurtz 4183512
Fixes for json / yaml output
markurtz f8161ed
Ensure style and types pass, remove tests that are no longer relevant…
markurtz 3b821c8
Move metrics to subobject in output
sjmonson 5e63061
Move requests to subobject in output
sjmonson 82a381f
Replace Request breakdown with generic class
sjmonson 31adea4
Define sampling sizes and counts as StatusBreakdowns
sjmonson f8c5e7a
Set a default type for SuccessfulT
sjmonson 93f0fd1
Fix case chnage on requests_per_second
sjmonson 00a210d
Plumb output changes though progress and summary
sjmonson cf160b6
Pluralization is hard
sjmonson 2bedc6d
Fix changes after rebase
sjmonson 331978b
Fix/ignore linting errors due to line length changes
sjmonson c449bde
Fix double quotes inside a double qoute f-string
sjmonson 4cd904d
importlib.resources.files requires valid module
sjmonson 48098fc
Fix for restructuring of output and general simplification based on f…
markurtz 0263361
Fix quality, unit, integration, and e2e tests
markurtz b164b4b
Just kidding, let's try that again and hopefully fix quality and tests
markurtz b411db3
Trying one more time for quality
markurtz d0d31d3
Bump min python to 3.9
sjmonson 70aa669
Revert "Bump min python to 3.9"
sjmonson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
import asyncio | ||
import json | ||
from pathlib import Path | ||
from typing import get_args | ||
|
||
import click | ||
|
||
from guidellm.backend import BackendType | ||
from guidellm.benchmark import ProfileType, benchmark_generative_text | ||
from guidellm.scheduler import StrategyType | ||
|
||
STRATEGY_PROFILE_CHOICES = set( | ||
list(get_args(ProfileType)) + list(get_args(StrategyType)) | ||
) | ||
|
||
|
||
def parse_json(ctx, param, value): | ||
if value is None: | ||
return None | ||
try: | ||
return json.loads(value) | ||
except json.JSONDecodeError as err: | ||
raise click.BadParameter(f"{param.name} must be a valid JSON string.") from err | ||
|
||
|
||
def parse_number_str(ctx, param, value): | ||
if value is None: | ||
return None | ||
|
||
values = value.split(",") if "," in value else [value] | ||
|
||
try: | ||
return [int(val) if val.isdigit() else float(val) for val in values] | ||
except ValueError as err: | ||
raise click.BadParameter( | ||
f"{param.name} must be a number or comma-separated list of numbers." | ||
) from err | ||
|
||
|
||
@click.group() | ||
def cli(): | ||
pass | ||
|
||
|
||
@cli.command() | ||
@click.option( | ||
"--target", | ||
required=True, | ||
type=str, | ||
help="The target path for the backend to run benchmarks against. For example, http://localhost:8000", | ||
) | ||
@click.option( | ||
"--backend-type", | ||
type=click.Choice(list(get_args(BackendType))), | ||
help=( | ||
"The type of backend to use to run requests against. Defaults to 'openai_http'." | ||
f" Supported types: {', '.join(get_args(BackendType))}" | ||
), | ||
default="openai_http", | ||
) | ||
@click.option( | ||
"--backend-args", | ||
callback=parse_json, | ||
default=None, | ||
help=( | ||
"A JSON string containing any arguments to pass to the backend as a " | ||
"dict with **kwargs." | ||
), | ||
) | ||
@click.option( | ||
"--model", | ||
default=None, | ||
type=str, | ||
help=( | ||
"The ID of the model to benchmark within the backend. " | ||
"If None provided (default), then it will use the first model available." | ||
), | ||
) | ||
@click.option( | ||
"--processor", | ||
default=None, | ||
type=str, | ||
help=( | ||
"The processor or tokenizer to use to calculate token counts for statistics " | ||
"and synthetic data generation. If None provided (default), will load " | ||
"using the model arg, if needed." | ||
), | ||
) | ||
@click.option( | ||
"--processor-args", | ||
default=None, | ||
callback=parse_json, | ||
help=( | ||
"A JSON string containing any arguments to pass to the processor constructor " | ||
"as a dict with **kwargs." | ||
), | ||
) | ||
@click.option( | ||
"--data", | ||
required=True, | ||
type=str, | ||
help=( | ||
"The HuggingFace dataset ID, a path to a HuggingFace dataset, " | ||
"a path to a data file csv, json, jsonl, or txt, " | ||
"or a synthetic data config as a json or key=value string." | ||
), | ||
) | ||
@click.option( | ||
"--data-args", | ||
callback=parse_json, | ||
help=( | ||
"A JSON string containing any arguments to pass to the dataset creation " | ||
"as a dict with **kwargs." | ||
), | ||
) | ||
@click.option( | ||
"--data-sampler", | ||
default=None, | ||
type=click.Choice(["random"]), | ||
help=( | ||
"The data sampler type to use. 'random' will add a random shuffle on the data. " | ||
"Defaults to None" | ||
), | ||
) | ||
@click.option( | ||
"--rate-type", | ||
required=True, | ||
type=click.Choice(STRATEGY_PROFILE_CHOICES), | ||
help=( | ||
"The type of benchmark to run. " | ||
f"Supported types {', '.join(STRATEGY_PROFILE_CHOICES)}. " | ||
), | ||
) | ||
@click.option( | ||
"--rate", | ||
default=None, | ||
callback=parse_number_str, | ||
help=( | ||
"The rates to run the benchmark at. " | ||
"Can be a single number or a comma-separated list of numbers. " | ||
"For rate-type=sweep, this is the number of benchmarks it runs in the sweep. " | ||
"For rate-type=concurrent, this is the number of concurrent requests. " | ||
"For rate-type=async,constant,poisson, this is the rate requests per second. " | ||
"For rate-type=synchronous,throughput, this must not be set." | ||
), | ||
) | ||
@click.option( | ||
"--max-seconds", | ||
type=float, | ||
help=( | ||
"The maximum number of seconds each benchmark can run for. " | ||
"If None, will run until max_requests or the data is exhausted." | ||
), | ||
) | ||
@click.option( | ||
"--max-requests", | ||
type=int, | ||
help=( | ||
"The maximum number of requests each benchmark can run for. " | ||
"If None, will run until max_seconds or the data is exhausted." | ||
), | ||
) | ||
@click.option( | ||
"--warmup-percent", | ||
type=float, | ||
default=None, | ||
help=( | ||
"The percent of the benchmark (based on max-seconds, max-requets, " | ||
"or lenth of dataset) to run as a warmup and not include in the final results. " | ||
"Defaults to None." | ||
), | ||
) | ||
@click.option( | ||
"--cooldown-percent", | ||
type=float, | ||
help=( | ||
"The percent of the benchmark (based on max-seconds, max-requets, or lenth " | ||
"of dataset) to run as a cooldown and not include in the final results. " | ||
"Defaults to None." | ||
), | ||
) | ||
@click.option( | ||
"--disable-progress", | ||
is_flag=True, | ||
help="Set this flag to disable progress updates to the console", | ||
) | ||
@click.option( | ||
"--display-scheduler-stats", | ||
is_flag=True, | ||
help="Set this flag to display stats for the processes running the benchmarks", | ||
) | ||
@click.option( | ||
"--disable-console-outputs", | ||
is_flag=True, | ||
help="Set this flag to disable console output", | ||
) | ||
@click.option( | ||
"--output-path", | ||
type=click.Path(), | ||
default=Path.cwd() / "benchmarks.json", | ||
help=( | ||
"The path to save the output to. If it is a directory, " | ||
"it will save benchmarks.json under it. " | ||
"Otherwise, json, yaml, or csv files are supported for output types " | ||
"which will be read from the extension for the file path." | ||
), | ||
) | ||
@click.option( | ||
"--output-extras", | ||
callback=parse_json, | ||
help="A JSON string of extra data to save with the output benchmarks", | ||
) | ||
@click.option( | ||
"--random-seed", | ||
default=42, | ||
type=int, | ||
help="The random seed to use for benchmarking to ensure reproducibility.", | ||
) | ||
def benchmark( | ||
target, | ||
backend_type, | ||
backend_args, | ||
model, | ||
processor, | ||
processor_args, | ||
data, | ||
data_args, | ||
data_sampler, | ||
rate_type, | ||
rate, | ||
max_seconds, | ||
max_requests, | ||
warmup_percent, | ||
cooldown_percent, | ||
disable_progress, | ||
display_scheduler_stats, | ||
disable_console_outputs, | ||
output_path, | ||
output_extras, | ||
random_seed, | ||
): | ||
asyncio.run( | ||
benchmark_generative_text( | ||
target=target, | ||
backend_type=backend_type, | ||
backend_args=backend_args, | ||
model=model, | ||
processor=processor, | ||
processor_args=processor_args, | ||
data=data, | ||
data_args=data_args, | ||
data_sampler=data_sampler, | ||
rate_type=rate_type, | ||
rate=rate, | ||
max_seconds=max_seconds, | ||
max_requests=max_requests, | ||
warmup_percent=warmup_percent, | ||
cooldown_percent=cooldown_percent, | ||
show_progress=not disable_progress, | ||
show_progress_scheduler_stats=display_scheduler_stats, | ||
output_console=not disable_console_outputs, | ||
output_path=output_path, | ||
output_extras=output_extras, | ||
random_seed=random_seed, | ||
) | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
cli() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.