mirror of
https://github.com/vale981/ray
synced 2025-03-11 13:46:40 -04:00
162 lines
5.4 KiB
Python
162 lines
5.4 KiB
Python
#!/usr/bin/env python3
|
|
import re
|
|
|
|
|
|
def parse_time_to_ms(time_string: str) -> float:
|
|
"""Given a time string with various unit, convert
|
|
to ms in float:
|
|
|
|
wrk time unit reference
|
|
https://github.com/wg/wrk/blob/master/src/units.c#L17-L21
|
|
|
|
Example:
|
|
"71.91ms" -> 71.91
|
|
"50us" -> 0.05
|
|
"1.5s" -> 1500
|
|
"""
|
|
# Group 1 - (one or more digits + optional dot + one or more digits)
|
|
# 71.91 / 50 / 1.5
|
|
# Group 2 - (All words)
|
|
# ms / us / s
|
|
parsed = re.split(r"(\d+.?\d+)(\w+)", time_string)
|
|
values = [val for val in parsed if val]
|
|
|
|
if values[1] == "ms":
|
|
return float(values[0])
|
|
elif values[1] == "us":
|
|
return float(values[0]) / 1000
|
|
elif values[1] == "s":
|
|
return float(values[0]) * 1000
|
|
|
|
# Should not return here in common benchmark
|
|
return values[1]
|
|
|
|
|
|
def parse_size_to_KB(size_string: str) -> float:
|
|
"""Given a size string with various unit, convert
|
|
to KB in float:
|
|
|
|
wrk binary unit reference
|
|
https://github.com/wg/wrk/blob/master/src/units.c#L29-L33
|
|
|
|
Example:
|
|
"200.56KB" -> 200.56
|
|
"50MB" -> 51200
|
|
"0.5GB" -> 524288
|
|
"""
|
|
# Group 1 - (one or more digits + optional dot + one or more digits)
|
|
# 200.56 / 50 / 0.5
|
|
# Group 2 - (All words)
|
|
# KB / MB / GB
|
|
parsed = re.split(r"(\d+.?\d+)(\w+)", size_string)
|
|
values = [val for val in parsed if val]
|
|
|
|
if values[1] == "KB":
|
|
return float(values[0])
|
|
elif values[1] == "MB":
|
|
return float(values[0]) * 1024
|
|
elif values[1] == "GB":
|
|
return float(values[0]) * 1024 * 1024
|
|
|
|
# Should not return here in common benchmark
|
|
return values[1]
|
|
|
|
|
|
def parse_metric_to_base(metric_string: str) -> float:
|
|
"""Given a metric string with various unit, convert
|
|
to original base
|
|
|
|
wrk metric unit reference
|
|
https://github.com/wg/wrk/blob/master/src/units.c#L35-L39
|
|
|
|
Example:
|
|
"71.91" -> 71.91
|
|
"1.32k" -> 1320
|
|
"1.5M" -> 1500000
|
|
"""
|
|
|
|
parsed = re.split(r"(\d+.?\d+)(\w+)", metric_string)
|
|
values = [val for val in parsed if val]
|
|
|
|
if len(values) == 1:
|
|
return float(values[0])
|
|
if values[1] == "k":
|
|
return float(values[0]) * 1000
|
|
elif values[1] == "M":
|
|
return float(values[0]) * 1000 * 1000
|
|
|
|
# Should not return here in common benchmark
|
|
return values[1]
|
|
|
|
|
|
def parse_wrk_decoded_stdout(decoded_out):
|
|
"""
|
|
Parse decoded wrk stdout to a dictionary.
|
|
|
|
# Sample wrk stdout:
|
|
#
|
|
Running 10s test @ http://127.0.0.1:8000/echo
|
|
8 threads and 96 connections
|
|
Thread Stats Avg Stdev Max +/- Stdev
|
|
Latency 72.32ms 6.00ms 139.00ms 91.60%
|
|
Req/Sec 165.99 34.84 242.00 57.20%
|
|
Latency Distribution
|
|
50% 70.78ms
|
|
75% 72.59ms
|
|
90% 75.67ms
|
|
99% 98.71ms
|
|
13306 requests in 10.10s, 1.95MB read
|
|
Requests/sec: 1317.73
|
|
Transfer/sec: 198.19KB
|
|
|
|
Returns:
|
|
{'latency_avg_ms': 72.32, 'latency_stdev_ms': 6.0,
|
|
'latency_max_ms': 139.0, 'latency_+/-_stdev %': 91.6,
|
|
'req/sec_avg': 165.99, 'req/sec_stdev': 34.84,
|
|
'req/sec_max': 242.0, 'req/sec_+/-_stdev %': 57.2,
|
|
'P50_latency_ms': 70.78, 'P75_latency_ms': 72.59,
|
|
'P90_latency_ms': 75.67, 'P99_latency_ms': 98.71,
|
|
'requests/sec': 1317.73, 'transfer/sec_KB': 198.19
|
|
"""
|
|
metrics_dict = {}
|
|
for line in decoded_out.splitlines():
|
|
parsed = re.split(r"\s+", line.strip())
|
|
# Statistics section
|
|
# Thread Stats Avg Stdev Max +/- Stdev
|
|
# Latency 72.32ms 6.00ms 139.00ms 91.60%
|
|
# Req/Sec 165.99 34.84 242.00 57.20%
|
|
if parsed[0] == "Latency" and len(parsed) == 5:
|
|
metrics_dict["latency_avg_ms"] = parse_time_to_ms(parsed[1])
|
|
metrics_dict["latency_stdev_ms"] = parse_time_to_ms(parsed[2])
|
|
metrics_dict["latency_max_ms"] = parse_time_to_ms(parsed[3])
|
|
metrics_dict["latency_+/-_stdev %"] = float(parsed[4][:-1])
|
|
elif parsed[0] == "Req/Sec" and len(parsed) == 5:
|
|
metrics_dict["req/sec_avg"] = parse_metric_to_base(parsed[1])
|
|
metrics_dict["req/sec_stdev"] = parse_metric_to_base(parsed[2])
|
|
metrics_dict["req/sec_max"] = parse_metric_to_base(parsed[3])
|
|
metrics_dict["req/sec_+/-_stdev %"] = float(parsed[4][:-1])
|
|
# Latency Distribution header, ignored
|
|
elif parsed[0] == "Latency" and parsed[1] == "Distribution":
|
|
continue
|
|
# Percentile section
|
|
# 50% 70.78ms
|
|
# 75% 72.59ms
|
|
# 90% 75.67ms
|
|
# 99% 98.71ms
|
|
elif parsed[0] == "50%":
|
|
metrics_dict["P50_latency_ms"] = parse_time_to_ms(parsed[1])
|
|
elif parsed[0] == "75%":
|
|
metrics_dict["P75_latency_ms"] = parse_time_to_ms(parsed[1])
|
|
elif parsed[0] == "90%":
|
|
metrics_dict["P90_latency_ms"] = parse_time_to_ms(parsed[1])
|
|
elif parsed[0] == "99%":
|
|
metrics_dict["P99_latency_ms"] = parse_time_to_ms(parsed[1])
|
|
# Summary section
|
|
# Requests/sec: 1317.73
|
|
# Transfer/sec: 198.19KB
|
|
elif parsed[0] == "Requests/sec:":
|
|
metrics_dict["requests/sec"] = parse_metric_to_base(parsed[1])
|
|
elif parsed[0] == "Transfer/sec:":
|
|
metrics_dict["transfer/sec_KB"] = parse_size_to_KB(parsed[1])
|
|
|
|
return metrics_dict
|