szl-engine-bench 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- benchmark_manifest.py +236 -0
- engine_bench.py +716 -0
- szl_engine_bench-0.3.0.dist-info/METADATA +188 -0
- szl_engine_bench-0.3.0.dist-info/RECORD +7 -0
- szl_engine_bench-0.3.0.dist-info/WHEEL +5 -0
- szl_engine_bench-0.3.0.dist-info/licenses/LICENSE +201 -0
- szl_engine_bench-0.3.0.dist-info/top_level.txt +2 -0
benchmark_manifest.py
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
"""Bounded, non-executing benchmark declarations and exact request commitments.
|
|
3
|
+
|
|
4
|
+
Declarations are supplied by an operator. Validating and hashing them does NOT
|
|
5
|
+
attest what a remote server loaded, measure model quality, or admit a release.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import hashlib
|
|
10
|
+
import json
|
|
11
|
+
import math
|
|
12
|
+
import re
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
SCHEMA = "szl.engine-comparison/v1"
|
|
17
|
+
BOUNDARY = "OPERATOR_DECLARED_NOT_RUNTIME_ATTESTED"
|
|
18
|
+
MAX_MANIFEST_BYTES = 65536
|
|
19
|
+
ENGINE_NAMES = frozenset({"vllm", "sglang", "llamacpp", "mlx", "tgi", "transformers"})
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ManifestError(ValueError):
|
|
23
|
+
"""A declaration is incomplete, ambiguous, or incomparable."""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def canonical(value: Any) -> bytes:
|
|
27
|
+
return json.dumps(value, sort_keys=True, separators=(",", ":"),
|
|
28
|
+
ensure_ascii=False, allow_nan=False).encode("utf-8")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def digest(value: Any) -> str:
|
|
32
|
+
return hashlib.sha256(canonical(value)).hexdigest()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _keys(value: Any, expected: set[str], field: str) -> dict:
|
|
36
|
+
if not isinstance(value, dict) or set(value) != expected:
|
|
37
|
+
raise ManifestError(f"{field}: missing or unrecognized fields")
|
|
38
|
+
return value
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _hex(value: Any, size: int, field: str) -> None:
|
|
42
|
+
if not isinstance(value, str) or re.fullmatch(r"[0-9a-f]{%d}" % size, value) is None:
|
|
43
|
+
raise ManifestError(f"{field}: expected exact lowercase hexadecimal digest")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _identifier(value: Any, field: str) -> None:
|
|
47
|
+
if (not isinstance(value, str) or not 1 <= len(value) <= 200
|
|
48
|
+
or re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._/:+-]*", value) is None):
|
|
49
|
+
raise ManifestError(f"{field}: expected bounded ASCII identifier")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _integer(value: Any, minimum: int, maximum: int, field: str) -> None:
|
|
53
|
+
if type(value) is not int or not minimum <= value <= maximum:
|
|
54
|
+
raise ManifestError(f"{field}: integer outside allowed range")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _number(value: Any, minimum: float, maximum: float, field: str) -> None:
|
|
58
|
+
if (type(value) not in (int, float) or not minimum <= value <= maximum
|
|
59
|
+
or not math.isfinite(value)):
|
|
60
|
+
raise ManifestError(f"{field}: finite number outside allowed range")
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _metric_triplet(value: Any, field: str) -> None:
|
|
64
|
+
"""Require one physically possible p50/p95/p99 latency summary."""
|
|
65
|
+
value = _keys(value, {"p50", "p95", "p99"}, field)
|
|
66
|
+
metrics = []
|
|
67
|
+
for percentile in ("p50", "p95", "p99"):
|
|
68
|
+
metric = value[percentile]
|
|
69
|
+
if (type(metric) not in (int, float) or not math.isfinite(metric)
|
|
70
|
+
or metric < 0):
|
|
71
|
+
raise ManifestError(f"{field}: percentiles must be finite non-negative numbers")
|
|
72
|
+
metrics.append(float(metric))
|
|
73
|
+
if metrics != sorted(metrics):
|
|
74
|
+
raise ManifestError(f"{field}: percentiles must be monotonic p50 <= p95 <= p99")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def sampling_parameters(value: Any) -> dict:
|
|
78
|
+
value = _keys(value, {"temperature", "top_p", "seed"}, "sampling")
|
|
79
|
+
_number(value["temperature"], 0, 2, "temperature")
|
|
80
|
+
_number(value["top_p"], 0, 1, "top_p")
|
|
81
|
+
if value["top_p"] == 0:
|
|
82
|
+
raise ManifestError("top_p: must be positive")
|
|
83
|
+
_integer(value["seed"], 0, 2147483647, "seed")
|
|
84
|
+
return dict(value)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def validate_manifest(value: Any) -> dict:
|
|
88
|
+
"""Validate a closed declaration; return a detached canonical JSON snapshot."""
|
|
89
|
+
value = _keys(value, {"schema", "claim_boundary", "subject", "workload", "engines"}, "manifest")
|
|
90
|
+
if value["schema"] != SCHEMA or value["claim_boundary"] != BOUNDARY:
|
|
91
|
+
raise ManifestError("manifest: unsupported schema or claim boundary")
|
|
92
|
+
subject = _keys(value["subject"], {
|
|
93
|
+
"model_id", "model_revision", "weights_sha256", "tokenizer_revision",
|
|
94
|
+
"tokenizer_sha256", "template_sha256", "adapter_sha256", "quantization", "precision",
|
|
95
|
+
}, "subject")
|
|
96
|
+
for field in ("model_id", "quantization", "precision"):
|
|
97
|
+
_identifier(subject[field], field)
|
|
98
|
+
for field in ("model_revision", "tokenizer_revision"):
|
|
99
|
+
_hex(subject[field], 40, field)
|
|
100
|
+
for field in ("weights_sha256", "tokenizer_sha256", "template_sha256"):
|
|
101
|
+
_hex(subject[field], 64, field)
|
|
102
|
+
if subject["adapter_sha256"] is not None:
|
|
103
|
+
_hex(subject["adapter_sha256"], 64, "adapter_sha256")
|
|
104
|
+
workload = _keys(value["workload"], {
|
|
105
|
+
"suite_sha256", "prompt_sha256", "runs", "max_tokens", "timeout_seconds",
|
|
106
|
+
"sampling", "concurrency", "cache_state",
|
|
107
|
+
}, "workload")
|
|
108
|
+
for field in ("suite_sha256", "prompt_sha256"):
|
|
109
|
+
_hex(workload[field], 64, field)
|
|
110
|
+
_integer(workload["runs"], 1, 1000, "runs")
|
|
111
|
+
_integer(workload["max_tokens"], 1, 65536, "max_tokens")
|
|
112
|
+
_number(workload["timeout_seconds"], 0.01, 600, "timeout_seconds")
|
|
113
|
+
sampling_parameters(workload["sampling"])
|
|
114
|
+
if type(workload["concurrency"]) is not int or workload["concurrency"] != 1:
|
|
115
|
+
raise ManifestError("concurrency: this client measures serial requests only")
|
|
116
|
+
if workload["cache_state"] != "UNCONTROLLED":
|
|
117
|
+
raise ManifestError("cache_state: this client does not establish server cache state")
|
|
118
|
+
engines = value["engines"]
|
|
119
|
+
if (not isinstance(engines, dict) or not 2 <= len(engines) <= len(ENGINE_NAMES)
|
|
120
|
+
or not set(engines).issubset(ENGINE_NAMES)):
|
|
121
|
+
raise ManifestError("engines: expected two or more distinct supported engines")
|
|
122
|
+
for engine in engines.values():
|
|
123
|
+
_keys(engine, {"build_sha256", "configuration_sha256", "hardware_sha256", "endpoint_sha256"}, "engine")
|
|
124
|
+
for field, field_value in engine.items():
|
|
125
|
+
_hex(field_value, 64, field)
|
|
126
|
+
if len({engine["hardware_sha256"] for engine in engines.values()}) != 1:
|
|
127
|
+
raise ManifestError("hardware_sha256: different hardware is not an engine-only comparison")
|
|
128
|
+
return json.loads(canonical(value))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _unique_pairs(pairs: list[tuple[str, Any]]) -> dict:
|
|
132
|
+
result: dict = {}
|
|
133
|
+
for key, value in pairs:
|
|
134
|
+
if key in result:
|
|
135
|
+
raise ManifestError("manifest JSON contains duplicate object fields")
|
|
136
|
+
result[key] = value
|
|
137
|
+
return result
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _reject_constant(_: str) -> None:
|
|
141
|
+
raise ManifestError("manifest JSON contains a non-finite constant")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def load_manifest(path: str | Path) -> dict:
|
|
145
|
+
try:
|
|
146
|
+
with Path(path).open("rb") as source:
|
|
147
|
+
payload = source.read(MAX_MANIFEST_BYTES + 1)
|
|
148
|
+
if len(payload) > MAX_MANIFEST_BYTES:
|
|
149
|
+
raise ManifestError("manifest exceeds byte budget")
|
|
150
|
+
value = json.loads(payload.decode("utf-8"), object_pairs_hook=_unique_pairs,
|
|
151
|
+
parse_constant=_reject_constant)
|
|
152
|
+
return validate_manifest(value)
|
|
153
|
+
except ManifestError:
|
|
154
|
+
raise
|
|
155
|
+
except (OSError, UnicodeError, ValueError, RecursionError, OverflowError):
|
|
156
|
+
# Never echo an operator-controlled filename, JSON value, or exception.
|
|
157
|
+
raise ManifestError("manifest is unreadable or invalid JSON") from None
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def request_payload(model: str, prompt: str, max_tokens: int, sampling: dict | None = None) -> dict:
|
|
161
|
+
payload = {"model": model, "prompt": prompt, "max_tokens": max_tokens,
|
|
162
|
+
"stream": True, "stream_options": {"include_usage": True}}
|
|
163
|
+
if sampling is not None:
|
|
164
|
+
payload.update(sampling_parameters(sampling))
|
|
165
|
+
return payload
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def endpoint_digest(endpoint: str) -> str:
|
|
169
|
+
# The caller validates the URL. Only trailing path separators are normalized.
|
|
170
|
+
return hashlib.sha256(endpoint.rstrip("/").encode("utf-8")).hexdigest()
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def preflight(value: dict, *, model: str, prompt: str, runs: int, max_tokens: int,
|
|
174
|
+
timeout: float, endpoints: dict[str, str]) -> dict:
|
|
175
|
+
manifest = validate_manifest(value)
|
|
176
|
+
workload = manifest["workload"]
|
|
177
|
+
if set(endpoints) != set(manifest["engines"]):
|
|
178
|
+
raise ManifestError("selected engines must exactly match the manifest")
|
|
179
|
+
if (model != manifest["subject"]["model_id"] or runs != workload["runs"]
|
|
180
|
+
or max_tokens != workload["max_tokens"] or timeout != workload["timeout_seconds"]
|
|
181
|
+
or hashlib.sha256(prompt.encode("utf-8")).hexdigest() != workload["prompt_sha256"]):
|
|
182
|
+
raise ManifestError("requested model or workload differs from its declaration")
|
|
183
|
+
for name, endpoint in endpoints.items():
|
|
184
|
+
if endpoint_digest(endpoint) != manifest["engines"][name]["endpoint_sha256"]:
|
|
185
|
+
raise ManifestError("configured endpoint differs from its declaration")
|
|
186
|
+
return manifest
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def run_binding(manifest: dict, name: str, request_sha256: str) -> dict:
|
|
190
|
+
"""Commit the declaration and wire request, not an assertion about remote weights."""
|
|
191
|
+
_hex(request_sha256, 64, "request_sha256")
|
|
192
|
+
engine = manifest["engines"][name]
|
|
193
|
+
return {
|
|
194
|
+
"schema": "szl.engine-run-binding/v1", "claim_boundary": BOUNDARY,
|
|
195
|
+
"engine": name, "manifest_sha256": digest(manifest),
|
|
196
|
+
"subject_sha256": digest(manifest["subject"]),
|
|
197
|
+
"workload_sha256": digest(manifest["workload"]),
|
|
198
|
+
"request_sha256": request_sha256, **engine,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def verify_result_bindings(manifest: dict, results: list[dict]) -> None:
|
|
203
|
+
"""Refuse partial cohorts, changed declarations, or changed request bodies."""
|
|
204
|
+
names = [result.get("engine") for result in results]
|
|
205
|
+
if (any(not isinstance(name, str) for name in names)
|
|
206
|
+
or len(names) != len(set(names)) or set(names) != set(manifest["engines"])):
|
|
207
|
+
raise ManifestError("comparison cohort is incomplete, duplicated, or unexpected")
|
|
208
|
+
requests = set()
|
|
209
|
+
for result in results:
|
|
210
|
+
name = result["engine"]
|
|
211
|
+
if result.get("state") != "MEASURED":
|
|
212
|
+
raise ManifestError("every declared engine must produce measurements")
|
|
213
|
+
binding = result.get("binding")
|
|
214
|
+
if not isinstance(binding, dict):
|
|
215
|
+
raise ManifestError("measured result lacks an exact request binding")
|
|
216
|
+
request_hash = binding.get("request_sha256")
|
|
217
|
+
_hex(request_hash, 64, "request_sha256")
|
|
218
|
+
if binding != run_binding(manifest, name, request_hash):
|
|
219
|
+
raise ManifestError("result binding differs from the declared experiment")
|
|
220
|
+
if result.get("model") != manifest["subject"]["model_id"]:
|
|
221
|
+
raise ManifestError("result model differs from the declaration")
|
|
222
|
+
if type(result.get("runs")) is not int or result["runs"] != manifest["workload"]["runs"]:
|
|
223
|
+
raise ManifestError("result run count differs from the declaration")
|
|
224
|
+
_metric_triplet(result.get("itl_ms"), "itl_ms")
|
|
225
|
+
endpoint = result.get("endpoint")
|
|
226
|
+
if not isinstance(endpoint, str) or endpoint_digest(endpoint) != binding["endpoint_sha256"]:
|
|
227
|
+
raise ManifestError("result endpoint differs from its binding")
|
|
228
|
+
samples = result.get("run_samples")
|
|
229
|
+
if not isinstance(samples, list) or len(samples) != result["runs"]:
|
|
230
|
+
raise ManifestError("bound run samples are incomplete")
|
|
231
|
+
if any(not isinstance(sample, dict) or sample.get("request_sha256") != request_hash
|
|
232
|
+
for sample in samples):
|
|
233
|
+
raise ManifestError("a wire request differs from the bound request")
|
|
234
|
+
requests.add(request_hash)
|
|
235
|
+
if len(requests) != 1:
|
|
236
|
+
raise ManifestError("wire requests differ across engines")
|