Skip to content
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

Offline LLM Engine Benchmark Throughput #1968

Merged
merged 35 commits into from
Nov 15, 2024
Merged
Changes from 11 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
807a3f0
add offline engine bench
zolinthecow Nov 9, 2024
e3ec623
llm_engine -> engine
zolinthecow Nov 9, 2024
8b1232b
add to unit test bench
zolinthecow Nov 9, 2024
e6293a8
first draft bench offline throughput
zolinthecow Nov 11, 2024
5564a96
script works
zolinthecow Nov 11, 2024
0078bc3
reset bench serving stuff
zolinthecow Nov 11, 2024
9f6c31a
merge
zolinthecow Nov 11, 2024
3158414
most recent commit?
zolinthecow Nov 11, 2024
550ec14
restore test utils
zolinthecow Nov 11, 2024
a6b183e
Merge branch 'main' into benchmark-script
zolinthecow Nov 11, 2024
c1c6226
lint
zolinthecow Nov 11, 2024
1895c79
use sharegpt from bench_serving
zolinthecow Nov 12, 2024
3c8faf9
add unit test
zolinthecow Nov 12, 2024
170c83f
lint
zolinthecow Nov 12, 2024
696dd95
add support for runtime backend + dataclass generic args
zolinthecow Nov 12, 2024
21b6ed5
push not being processed?
zolinthecow Nov 12, 2024
0589a6b
lint
zolinthecow Nov 12, 2024
383b6d1
fix benches
zolinthecow Nov 13, 2024
8db0340
lint
zolinthecow Nov 13, 2024
568ce97
Merge branch 'main' into benchmark-script
zolinthecow Nov 13, 2024
c6a6827
add review
ByronHsu Nov 13, 2024
ed1a133
address todos
zolinthecow Nov 13, 2024
c485dbe
not sure how the tuple stuff got there
zolinthecow Nov 13, 2024
3565766
Merge branch 'main' into benchmark-script
zolinthecow Nov 13, 2024
fd2d04d
fix
zolinthecow Nov 13, 2024
ea3b60a
fix
zolinthecow Nov 13, 2024
732e3ba
lint
zolinthecow Nov 13, 2024
41aad44
format benchmark + add diff metrics
zolinthecow Nov 14, 2024
fa76ac9
lint
zolinthecow Nov 14, 2024
cc2a5c5
fix script
zolinthecow Nov 14, 2024
e1045e4
fix test
zolinthecow Nov 14, 2024
4a322a3
fix
zolinthecow Nov 14, 2024
ef4f278
remove useless try except
zolinthecow Nov 14, 2024
df9da2e
fix test and move logging
ByronHsu Nov 15, 2024
d5fa88c
Merge branch 'main' into benchmark-script
ByronHsu Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions python/sglang/bench_offline_throughput.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
"""
Benchmark the throughput of using the offline LLM engine.
This script does not launch a server.
It accepts the same arguments as bench_latency.py
zolinthecow marked this conversation as resolved.
Show resolved Hide resolved

# Usage
python -m sglang.bench_offline_throughput --model-path meta-llama/Meta-Llama-3-8B-Instruct --batch 1 12 14 --input-len 256 512 --output-len 32 256 --result-filename out.jsonl

"""

import argparse
import dataclasses
import itertools
import logging
import time
from typing import Dict, List, Tuple

import jsonlines

from sglang.api import Engine as getEngine
merrymercy marked this conversation as resolved.
Show resolved Hide resolved
from sglang.srt.server import Engine
from sglang.srt.server_args import ServerArgs


@dataclasses.dataclass
class BenchArgs:
run_name: str = "before"
batch_size: Tuple[int] = (1,)
input_len: Tuple[int] = (1024,)
output_len: Tuple[int] = (16,)
result_filename: str = ""
# Plotting args
graph_sql: str = (
"select run_name, batch_size, prefill_throughput from results where run_name='before'"
)
graph_filename: str = "out.png"
merrymercy marked this conversation as resolved.
Show resolved Hide resolved

@staticmethod
def add_cli_args(parser: argparse.ArgumentParser):
parser.add_argument("--run-name", type=str, default=BenchArgs.run_name)
parser.add_argument(
"--batch-size", type=int, nargs="+", default=BenchArgs.batch_size
)
parser.add_argument(
"--input-len", type=int, nargs="+", default=BenchArgs.input_len
)
parser.add_argument(
"--output-len", type=int, nargs="+", default=BenchArgs.output_len
)
parser.add_argument(
"--result-filename", type=str, default=BenchArgs.result_filename
)
# graphing
parser.add_argument("--graph-sql", type=str, default=BenchArgs.graph_sql)
parser.add_argument(
"--graph-filename", type=str, default=BenchArgs.graph_filename
)

@classmethod
def from_cli_args(cls, args: argparse.Namespace):
# use the default value's type to case the args into correct types.
attrs = [(attr.name, type(attr.default)) for attr in dataclasses.fields(cls)]
return cls(
**{attr: attr_type(getattr(args, attr)) for attr, attr_type in attrs}
)


def prepare_synthetic_inputs_for_throughput_test(
batch_size: int, input_len: int, output_len: int
):
input_ids = [[1] * input_len for _ in range(batch_size)]
merrymercy marked this conversation as resolved.
Show resolved Hide resolved
sampling_params = {
"temperature": 0,
"min_new_tokens": output_len,
"max_new_tokens": output_len,
zolinthecow marked this conversation as resolved.
Show resolved Hide resolved
}
return input_ids, sampling_params


def throughput_test_once(
run_name: str,
engine: Engine,
reqs: Tuple[List[List[int]], Dict],
output_len: int,
):
measurement_results = {
"run_name": run_name,
"batch_size": len(reqs[0]),
"input_len": len(reqs[0][0]),
"output_len": output_len,
}

st = time.perf_counter()
gen_out = engine.generate(input_ids=reqs[0], sampling_params=reqs[1])
latency = time.perf_counter() - st

measurement_results["total_latency"] = latency
measurement_results["throughput"] = (
(measurement_results["input_len"] + output_len)
* measurement_results["batch_size"]
) / latency

print(
f"Throughput: BSZ {measurement_results['batch_size']} tokens, "
f"Num sequences {len(reqs[0])}, throughput: "
f"{measurement_results['throughput']} tokens/s"
)
return measurement_results


def throughput_test(
server_args: ServerArgs,
bench_args: BenchArgs,
):
engine = getEngine(**dataclasses.asdict(server_args))
if not engine:
raise ValueError("Please provide valid engine arguments")

warmup_reqs = prepare_synthetic_inputs_for_throughput_test(
bench_args.batch_size[0], bench_args.input_len[0], bench_args.output_len[0]
)

# Warm up
throughput_test_once("warmup", engine, warmup_reqs, bench_args.output_len[0])

result_list = []
for bs, il, ol in itertools.product(
bench_args.batch_size, bench_args.input_len, bench_args.output_len
):
reqs = prepare_synthetic_inputs_for_throughput_test(bs, il, ol)
ret = throughput_test_once(
bench_args.run_name, engine, reqs, bench_args.output_len[0]
)
if ret is not None:
result_list.append(ret)

if bench_args.result_filename:
with jsonlines.open(bench_args.result_filename, "a") as f:
merrymercy marked this conversation as resolved.
Show resolved Hide resolved
f.write_all(result_list)
else:
print(result_list)


if __name__ == "__main__":
parser = argparse.ArgumentParser()
ServerArgs.add_cli_args(parser)
BenchArgs.add_cli_args(parser)
args = parser.parse_args()
server_args = ServerArgs.from_cli_args(args)
bench_args = BenchArgs.from_cli_args(args)

logging.basicConfig(
level=getattr(logging, server_args.log_level.upper()),
format="%(message)s",
)

try:
zolinthecow marked this conversation as resolved.
Show resolved Hide resolved
throughput_test(server_args, bench_args)
except Exception as e:
raise e
Loading