Compare commits
6 Commits
master
...
ralph/dist
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eaf00f6add | ||
|
|
c035bad5b7 | ||
|
|
a508768e8a | ||
|
|
e6f6782995 | ||
|
|
5b33bf8b99 | ||
|
|
c7554ef7d8 |
127
.scratch/distributed-gguf-runtime/evidence/DGR-001/README.md
Normal file
127
.scratch/distributed-gguf-runtime/evidence/DGR-001/README.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# DGR-001 — performance contract baseline
|
||||||
|
|
||||||
|
## Files changed
|
||||||
|
|
||||||
|
- `packages/node/meshnet_node/performance_contract.py`
|
||||||
|
- `tests/test_performance_contract.py`
|
||||||
|
- `.scratch/distributed-gguf-runtime/issues/01-lock-the-safetensors-versus-gguf-performance-contract.md`
|
||||||
|
- `.scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json`
|
||||||
|
|
||||||
|
## What this slice does
|
||||||
|
|
||||||
|
- Locks the DGR-001 benchmark contract in code.
|
||||||
|
- Pins the architecture-aligned baseline to **DeepSeek-V2-Lite-Chat** (`deepseek2`).
|
||||||
|
- Uses the same model on both sides of the comparison:
|
||||||
|
- **safetensors:** `deepseek-ai/DeepSeek-V2-Lite-Chat` in **BF16**
|
||||||
|
- **GGUF:** `second-state/DeepSeek-V2-Lite-Chat-GGUF` in **Q2_K**
|
||||||
|
- Exposes a machine-readable JSON contract with:
|
||||||
|
- benchmark lanes for `transformers` safetensors and `llama.cpp` GGUF on **CPU** and **GPU**
|
||||||
|
- concurrency levels `1` and `4`
|
||||||
|
- the required metrics list
|
||||||
|
- an explicit stop condition for “no meaningful speed or fit benefit”
|
||||||
|
- Adds a deterministic stub benchmark report so the contract now has an executable report shape end to end.
|
||||||
|
|
||||||
|
## Recent benchmark runner slice
|
||||||
|
|
||||||
|
The runner currently uses a deterministic stub backend to exercise the comparison matrix without downloading a model. It emits:
|
||||||
|
|
||||||
|
- `.scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json`
|
||||||
|
- `.scratch/distributed-gguf-runtime/evidence/DGR-001/stub-benchmark-report.json`
|
||||||
|
|
||||||
|
The report includes per-device comparisons for:
|
||||||
|
|
||||||
|
- `transformers-safetensors-cpu` vs `llama-cpp-gguf-cpu`
|
||||||
|
- `transformers-safetensors-gpu` vs `llama-cpp-gguf-gpu`
|
||||||
|
|
||||||
|
and records the memory metric (`rss_bytes` on CPU, `vram_bytes` on GPU), decode speedup, artifact ratio, and output drift.
|
||||||
|
|
||||||
|
## Live endpoint CLI wiring
|
||||||
|
|
||||||
|
The contract CLI can now drive the live endpoint runner. Passing one `--live-endpoint LANE_ID=URL` mapping per contract lane (plus `--live-benchmark-out`) invokes `run_real_model_endpoint_benchmark` against already-running OpenAI-compatible servers and writes the report using the same schema as the stub:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PYTHONPATH=packages/node python -m meshnet_node.performance_contract \
|
||||||
|
--live-endpoint transformers-safetensors-cpu=http://127.0.0.1:8001 \
|
||||||
|
--live-endpoint llama-cpp-gguf-cpu=http://127.0.0.1:8002 \
|
||||||
|
--live-endpoint transformers-safetensors-gpu=http://127.0.0.1:8003 \
|
||||||
|
--live-endpoint llama-cpp-gguf-gpu=http://127.0.0.1:8004 \
|
||||||
|
--live-benchmark-out .scratch/distributed-gguf-runtime/evidence/DGR-001/live-benchmark-report.json
|
||||||
|
```
|
||||||
|
|
||||||
|
`--live-model` overrides the model name sent in requests (defaults to the contract's safetensors repo). Without any `--live-endpoint` flags the CLI behaves exactly as before: it writes the contract JSON and, with `--benchmark-out`, the deterministic stub report.
|
||||||
|
|
||||||
|
## Exact commands and real results
|
||||||
|
|
||||||
|
### Targeted tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PYTHONPATH=packages/node pytest -q tests/test_performance_contract.py tests/test_route_session_benchmark.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: `19 passed in 0.11s`
|
||||||
|
|
||||||
|
### Contract artifact generation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PYTHONPATH=packages/node python -m meshnet_node.performance_contract --json-out .scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: wrote `.scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json`
|
||||||
|
|
||||||
|
### Python compile check
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m compileall packages/node/meshnet_node/performance_contract.py tests/test_performance_contract.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Result: passed
|
||||||
|
|
||||||
|
## Public relay smoke benchmark (2026-07-15)
|
||||||
|
|
||||||
|
A real streamed request was run through the public tracker — **not** by connecting directly to the private node address:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://meshnet.2.d-popov.com/v1/chat/completions
|
||||||
|
-> wss://meshnet.2.d-popov.com/ws
|
||||||
|
-> wss://meshnet.2.d-popov.com/rpc/7j77FsPY1evV8tuf-7000
|
||||||
|
-> local CUDA node, Qwen/Qwen2.5-0.5B-Instruct layers 0-23
|
||||||
|
```
|
||||||
|
|
||||||
|
The local public-tracker node had an expired proof and a wedged HTTP server. A graceful restart refreshed its CUDA capability proof in `336 ms`, restored `admitted`/`routable` status, and reconnected its relay endpoint.
|
||||||
|
|
||||||
|
Measured streaming results after recovery:
|
||||||
|
|
||||||
|
| metric | result |
|
||||||
|
| --- | ---: |
|
||||||
|
| warm-up TTFT | 420.80 ms |
|
||||||
|
| warm-up elapsed | 610.23 ms |
|
||||||
|
| p50 TTFT (3 runs) | 288.26 ms |
|
||||||
|
| p50 elapsed (3 runs) | 363.20 ms |
|
||||||
|
| tracker-recorded relay throughput | 58.18-65.25 tok/s |
|
||||||
|
| HTTP status | 200 for all runs |
|
||||||
|
|
||||||
|
The tracker recorded `relay: true` and the local node ID `7j77FsPY-b32476219492` for each completion. Full redacted evidence is in `public-relay-smoke-benchmark.json`.
|
||||||
|
|
||||||
|
The other connected node is still alive but **not routable** because its capability proof is stale. It must revalidate before a multi-node shard/relay test can run.
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- This slice still uses a deterministic stub backend for the core comparison matrix.
|
||||||
|
- It now also includes a live endpoint runner, reachable from the CLI via `--live-endpoint`/`--live-benchmark-out`, that fans out one OpenAI-compatible request per lane when the caller provides endpoints; the CLI does not start those servers.
|
||||||
|
- It does **not** download or run a real model from within the repo.
|
||||||
|
- Real safetensors vs GGUF execution, TTFT/prefill/decode measurements, RSS/VRAM capture, and output-drift comparison are still to be implemented against the contract.
|
||||||
|
|
||||||
|
## Compatibility notes
|
||||||
|
|
||||||
|
- The contract stays on the DeepSeek2 family to remain close to the DeepSeek-V4-Flash end goal.
|
||||||
|
- A smaller non-DeepSeek model can still be used later for loader-plumbing smoke tests, but it does not replace this baseline.
|
||||||
|
- Model artifacts must stay on the mounted drive and not under `/home`.
|
||||||
|
|
||||||
|
## Dependent-story handoff
|
||||||
|
|
||||||
|
Next implementation work should attach to this contract and add the live benchmark runner that actually compares:
|
||||||
|
|
||||||
|
1. current Transformers/safetensors recipe
|
||||||
|
2. whole-model llama.cpp GGUF recipe
|
||||||
|
|
||||||
|
using the same model architecture/revision and the same prompt/context/concurrency settings.
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"benchmark_lanes": [
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "cpu",
|
||||||
|
"id": "transformers-safetensors-cpu",
|
||||||
|
"recipe": "current safetensors recipe",
|
||||||
|
"runtime": "transformers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "cpu",
|
||||||
|
"id": "llama-cpp-gguf-cpu",
|
||||||
|
"recipe": "whole-model GGUF recipe",
|
||||||
|
"runtime": "llama.cpp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "gpu",
|
||||||
|
"id": "transformers-safetensors-gpu",
|
||||||
|
"recipe": "current safetensors recipe",
|
||||||
|
"runtime": "transformers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "gpu",
|
||||||
|
"id": "llama-cpp-gguf-gpu",
|
||||||
|
"recipe": "whole-model GGUF recipe",
|
||||||
|
"runtime": "llama.cpp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metrics": [
|
||||||
|
"ttft_ms",
|
||||||
|
"prefill_tok_per_sec",
|
||||||
|
"decode_tok_per_sec",
|
||||||
|
"p50_latency_ms",
|
||||||
|
"p95_latency_ms",
|
||||||
|
"aggregate_throughput_tok_per_sec",
|
||||||
|
"rss_bytes",
|
||||||
|
"vram_bytes",
|
||||||
|
"artifact_bytes",
|
||||||
|
"failure_count",
|
||||||
|
"output_drift"
|
||||||
|
],
|
||||||
|
"model_target": {
|
||||||
|
"architecture": "deepseek2",
|
||||||
|
"comparison_policy": "same model/revision, closest practical low-footprint precision pair: BF16 safetensors versus Q2_K GGUF",
|
||||||
|
"gguf_quant": "Q2_K",
|
||||||
|
"gguf_repo": "second-state/DeepSeek-V2-Lite-Chat-GGUF",
|
||||||
|
"gguf_size_gb": 6.43,
|
||||||
|
"name": "DeepSeek-V2-Lite-Chat",
|
||||||
|
"rationale": "Smallest DeepSeek-family benchmark anchor that still points toward DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead of falling back to a tiny but architecture-mismatched smoke model.",
|
||||||
|
"safetensors_precision": "bfloat16",
|
||||||
|
"safetensors_repo": "deepseek-ai/DeepSeek-V2-Lite-Chat"
|
||||||
|
},
|
||||||
|
"notes": [
|
||||||
|
"Real model execution stays opt-in and must keep model artifacts on the mounted drive.",
|
||||||
|
"Use the tiny fallback only for loader plumbing smoke tests; it does not replace the architecture-aligned baseline."
|
||||||
|
],
|
||||||
|
"schema_version": 1,
|
||||||
|
"stop_condition": "Stop if GGUF does not provide a meaningful speed or fit benefit over the safetensors baseline for the chosen DeepSeek-family model target.",
|
||||||
|
"story_id": "DGR-001"
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"schema_version": 1,
|
||||||
|
"executed_at_utc": "2026-07-15T10:41:14Z",
|
||||||
|
"test_kind": "public-relay-single-node-streaming-smoke-benchmark",
|
||||||
|
"target": {
|
||||||
|
"public_chat_endpoint": "https://meshnet.2.d-popov.com/v1/chat/completions",
|
||||||
|
"relay_url": "wss://meshnet.2.d-popov.com/ws",
|
||||||
|
"model": "qwen2.5-0.5b-instruct",
|
||||||
|
"quantization": "bfloat16"
|
||||||
|
},
|
||||||
|
"recovery": {
|
||||||
|
"problem": "The local node's capability proof had expired and its port-7000 HTTP server had wedged with CLOSE-WAIT sockets.",
|
||||||
|
"action": "Gracefully restarted the local public-tracker meshnet-node process on port 7000.",
|
||||||
|
"startup_validation": {
|
||||||
|
"device": "cuda",
|
||||||
|
"capability_proof_ms": 336,
|
||||||
|
"node_id": "7j77FsPY-b32476219492",
|
||||||
|
"relay_addr": "wss://meshnet.2.d-popov.com/rpc/7j77FsPY1evV8tuf-7000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tracker_admission_after_recovery": {
|
||||||
|
"node_id": "7j77FsPY-b32476219492",
|
||||||
|
"alive": true,
|
||||||
|
"status": "ready",
|
||||||
|
"capability_state": "admitted",
|
||||||
|
"routable": true,
|
||||||
|
"route_hops": 1
|
||||||
|
},
|
||||||
|
"client_measurements": {
|
||||||
|
"warmup": {
|
||||||
|
"http_status": 200,
|
||||||
|
"ttft_ms": 420.8,
|
||||||
|
"elapsed_ms": 610.23,
|
||||||
|
"response_text": "MeshNet Relay Benchmark Passed"
|
||||||
|
},
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"run": 1,
|
||||||
|
"ttft_ms": 376.04,
|
||||||
|
"elapsed_ms": 458.65,
|
||||||
|
"response_text": "relay benchmark pass"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"run": 2,
|
||||||
|
"ttft_ms": 258.33,
|
||||||
|
"elapsed_ms": 336.71,
|
||||||
|
"response_text": "relay benchmark pass"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"run": 3,
|
||||||
|
"ttft_ms": 288.26,
|
||||||
|
"elapsed_ms": 363.2,
|
||||||
|
"response_text": "relay benchmark pass"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"p50_ttft_ms": 288.26,
|
||||||
|
"p50_elapsed_ms": 363.2
|
||||||
|
},
|
||||||
|
"tracker_relay_evidence": [
|
||||||
|
{
|
||||||
|
"status": 200,
|
||||||
|
"relay": true,
|
||||||
|
"node_id": "7j77FsPY-b32476219492",
|
||||||
|
"tokens": 11,
|
||||||
|
"elapsed_seconds": 0.1686,
|
||||||
|
"tokens_per_sec": 65.2541
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"status": 200,
|
||||||
|
"relay": true,
|
||||||
|
"node_id": "7j77FsPY-b32476219492",
|
||||||
|
"tokens": 11,
|
||||||
|
"elapsed_seconds": 0.1891,
|
||||||
|
"tokens_per_sec": 58.1799
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scope_and_remaining_work": {
|
||||||
|
"validated": "Public HTTPS chat endpoint routed a streaming request through the tracker relay to the local CUDA node and completed with HTTP 200.",
|
||||||
|
"not_validated": "Two-node shard routing was not run because the remote node 5gMLrmyB-88f5cba044d0 still had an expired capability proof and was not routable.",
|
||||||
|
"next_gate": "Refresh the remote node capability proof, then load a multi-node-compatible assignment and repeat the benchmark through the public tracker relay."
|
||||||
|
},
|
||||||
|
"reproduction": "Use a valid bearer API key with the public /v1/chat/completions endpoint and stream a short qwen2.5-0.5b-instruct request. Do not connect directly to private node HTTP endpoints; the tracker relay is the required path."
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
{
|
||||||
|
"comparisons": {
|
||||||
|
"cpu": {
|
||||||
|
"artifact_bytes_ratio": 0.2048,
|
||||||
|
"decode_speedup": 2.3333,
|
||||||
|
"gguf_benefit": true,
|
||||||
|
"gguf_lane": "llama-cpp-gguf-cpu",
|
||||||
|
"memory_bytes_ratio": 0.2152,
|
||||||
|
"memory_metric": "rss_bytes",
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"safetensors_lane": "transformers-safetensors-cpu",
|
||||||
|
"ttft_speedup": 1.8947
|
||||||
|
},
|
||||||
|
"gpu": {
|
||||||
|
"artifact_bytes_ratio": 0.2048,
|
||||||
|
"decode_speedup": 1.5294,
|
||||||
|
"gguf_benefit": true,
|
||||||
|
"gguf_lane": "llama-cpp-gguf-gpu",
|
||||||
|
"memory_bytes_ratio": 0.2273,
|
||||||
|
"memory_metric": "vram_bytes",
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"safetensors_lane": "transformers-safetensors-gpu",
|
||||||
|
"ttft_speedup": 1.6154
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lanes": [
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "cpu",
|
||||||
|
"id": "transformers-safetensors-cpu",
|
||||||
|
"output_tokens": [
|
||||||
|
"mesh",
|
||||||
|
"activation",
|
||||||
|
"seam",
|
||||||
|
"baseline"
|
||||||
|
],
|
||||||
|
"recipe": "current safetensors recipe",
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"concurrency": 1,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 6.0,
|
||||||
|
"artifact_bytes": 33715493273,
|
||||||
|
"decode_tok_per_sec": 6.0,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 166.6667,
|
||||||
|
"p95_latency_ms": 208.3334,
|
||||||
|
"prefill_tok_per_sec": 45.0,
|
||||||
|
"rss_bytes": 35433480192,
|
||||||
|
"ttft_ms": 1800.0,
|
||||||
|
"vram_bytes": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency": 4,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 20.4,
|
||||||
|
"artifact_bytes": 33715493273,
|
||||||
|
"decode_tok_per_sec": 5.1,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 196.0784,
|
||||||
|
"p95_latency_ms": 245.098,
|
||||||
|
"prefill_tok_per_sec": 38.25,
|
||||||
|
"rss_bytes": 35433480192,
|
||||||
|
"ttft_ms": 2340.0,
|
||||||
|
"vram_bytes": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"runtime": "transformers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "cpu",
|
||||||
|
"id": "llama-cpp-gguf-cpu",
|
||||||
|
"output_tokens": [
|
||||||
|
"mesh",
|
||||||
|
"activation",
|
||||||
|
"seam",
|
||||||
|
"baseline"
|
||||||
|
],
|
||||||
|
"recipe": "whole-model GGUF recipe",
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"concurrency": 1,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 14.0,
|
||||||
|
"artifact_bytes": 6904159928,
|
||||||
|
"decode_tok_per_sec": 14.0,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 71.4286,
|
||||||
|
"p95_latency_ms": 89.2858,
|
||||||
|
"prefill_tok_per_sec": 90.0,
|
||||||
|
"rss_bytes": 7623566950,
|
||||||
|
"ttft_ms": 950.0,
|
||||||
|
"vram_bytes": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency": 4,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 47.6,
|
||||||
|
"artifact_bytes": 6904159928,
|
||||||
|
"decode_tok_per_sec": 11.9,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 84.0336,
|
||||||
|
"p95_latency_ms": 105.042,
|
||||||
|
"prefill_tok_per_sec": 76.5,
|
||||||
|
"rss_bytes": 7623566950,
|
||||||
|
"ttft_ms": 1235.0,
|
||||||
|
"vram_bytes": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"runtime": "llama.cpp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "gpu",
|
||||||
|
"id": "transformers-safetensors-gpu",
|
||||||
|
"output_tokens": [
|
||||||
|
"mesh",
|
||||||
|
"activation",
|
||||||
|
"seam",
|
||||||
|
"baseline"
|
||||||
|
],
|
||||||
|
"recipe": "current safetensors recipe",
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"concurrency": 1,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 34.0,
|
||||||
|
"artifact_bytes": 33715493273,
|
||||||
|
"decode_tok_per_sec": 34.0,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 29.4118,
|
||||||
|
"p95_latency_ms": 36.7647,
|
||||||
|
"prefill_tok_per_sec": 850.0,
|
||||||
|
"rss_bytes": 4294967296,
|
||||||
|
"ttft_ms": 420.0,
|
||||||
|
"vram_bytes": 35433480192
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency": 4,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 115.6,
|
||||||
|
"artifact_bytes": 33715493273,
|
||||||
|
"decode_tok_per_sec": 28.9,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 34.6021,
|
||||||
|
"p95_latency_ms": 43.2526,
|
||||||
|
"prefill_tok_per_sec": 722.5,
|
||||||
|
"rss_bytes": 4294967296,
|
||||||
|
"ttft_ms": 546.0,
|
||||||
|
"vram_bytes": 35433480192
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"runtime": "transformers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency_levels": [
|
||||||
|
1,
|
||||||
|
4
|
||||||
|
],
|
||||||
|
"device": "gpu",
|
||||||
|
"id": "llama-cpp-gguf-gpu",
|
||||||
|
"output_tokens": [
|
||||||
|
"mesh",
|
||||||
|
"activation",
|
||||||
|
"seam",
|
||||||
|
"baseline"
|
||||||
|
],
|
||||||
|
"recipe": "whole-model GGUF recipe",
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"concurrency": 1,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 52.0,
|
||||||
|
"artifact_bytes": 6904159928,
|
||||||
|
"decode_tok_per_sec": 52.0,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 19.2308,
|
||||||
|
"p95_latency_ms": 24.0385,
|
||||||
|
"prefill_tok_per_sec": 640.0,
|
||||||
|
"rss_bytes": 1610612736,
|
||||||
|
"ttft_ms": 260.0,
|
||||||
|
"vram_bytes": 8053063680
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"concurrency": 4,
|
||||||
|
"metrics": {
|
||||||
|
"aggregate_throughput_tok_per_sec": 176.8,
|
||||||
|
"artifact_bytes": 6904159928,
|
||||||
|
"decode_tok_per_sec": 44.2,
|
||||||
|
"failure_count": 0,
|
||||||
|
"output_drift": 0.0,
|
||||||
|
"p50_latency_ms": 22.6244,
|
||||||
|
"p95_latency_ms": 28.2805,
|
||||||
|
"prefill_tok_per_sec": 544.0,
|
||||||
|
"rss_bytes": 1610612736,
|
||||||
|
"ttft_ms": 338.0,
|
||||||
|
"vram_bytes": 8053063680
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"runtime": "llama.cpp"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"model_target": {
|
||||||
|
"architecture": "deepseek2",
|
||||||
|
"comparison_policy": "same model/revision, closest practical low-footprint precision pair: BF16 safetensors versus Q2_K GGUF",
|
||||||
|
"gguf_quant": "Q2_K",
|
||||||
|
"gguf_repo": "second-state/DeepSeek-V2-Lite-Chat-GGUF",
|
||||||
|
"gguf_size_gb": 6.43,
|
||||||
|
"name": "DeepSeek-V2-Lite-Chat",
|
||||||
|
"rationale": "Smallest DeepSeek-family benchmark anchor that still points toward DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead of falling back to a tiny but architecture-mismatched smoke model.",
|
||||||
|
"safetensors_precision": "bfloat16",
|
||||||
|
"safetensors_repo": "deepseek-ai/DeepSeek-V2-Lite-Chat"
|
||||||
|
},
|
||||||
|
"schema_version": 1,
|
||||||
|
"source": "stub-backend",
|
||||||
|
"stop_condition": {
|
||||||
|
"gguf_benefit": true,
|
||||||
|
"text": "Stop if GGUF does not provide a meaningful speed or fit benefit over the safetensors baseline for the chosen DeepSeek-family model target.",
|
||||||
|
"triggered": false
|
||||||
|
},
|
||||||
|
"story_id": "DGR-001"
|
||||||
|
}
|
||||||
@@ -13,6 +13,15 @@ Status: ready-for-agent
|
|||||||
|
|
||||||
As a runtime engineer, I need a controlled baseline so that GGUF work proceeds from measured speed, memory, and quality rather than reputation.
|
As a runtime engineer, I need a controlled baseline so that GGUF work proceeds from measured speed, memory, and quality rather than reputation.
|
||||||
|
|
||||||
|
## Baseline model target
|
||||||
|
|
||||||
|
Use the same model on both sides of the comparison, with the closest practical low-footprint precision pair:
|
||||||
|
|
||||||
|
- **safetensors:** `deepseek-ai/DeepSeek-V2-Lite-Chat` in **BF16**
|
||||||
|
- **GGUF:** `second-state/DeepSeek-V2-Lite-Chat-GGUF` in **Q2_K** (~6.5GB)
|
||||||
|
|
||||||
|
Keep the benchmark matrix explicit for **CPU** and **GPU** runs. Reserve smaller non-DeepSeek fallback models only for loader plumbing smoke tests if needed; they do not count as the DGR-001 architecture-aligned baseline.
|
||||||
|
|
||||||
## Expected durable outputs
|
## Expected durable outputs
|
||||||
|
|
||||||
- Benchmark harness and deterministic tests
|
- Benchmark harness and deterministic tests
|
||||||
|
|||||||
495
packages/node/meshnet_node/performance_contract.py
Normal file
495
packages/node/meshnet_node/performance_contract.py
Normal file
@@ -0,0 +1,495 @@
|
|||||||
|
"""Versioned performance contract metadata and stub benchmark runner for DGR-001.
|
||||||
|
|
||||||
|
This module captures the *contract* first: the model family, architecture
|
||||||
|
alignment, benchmark lanes, and stop condition that benchmark runs must
|
||||||
|
satisfy. It also runs the contract's lanes through a deterministic stub
|
||||||
|
backend so the report data shape exists end to end. It never downloads or
|
||||||
|
executes a model; real transformers / llama.cpp backends plug in behind the
|
||||||
|
same ``run()`` seam later.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import urllib.request
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Mapping
|
||||||
|
|
||||||
|
SCHEMA_VERSION = 1
|
||||||
|
CONTRACT_ID = "DGR-001"
|
||||||
|
DEFAULT_OUTPUT_PATH = Path(".scratch/distributed-gguf-runtime/evidence/DGR-001/performance-contract.json")
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ModelTarget:
|
||||||
|
"""Architecture-aligned model target for the DGR-001 benchmark contract."""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
architecture: str
|
||||||
|
safetensors_repo: str
|
||||||
|
safetensors_precision: str
|
||||||
|
gguf_repo: str
|
||||||
|
gguf_quant: str
|
||||||
|
gguf_size_gb: float
|
||||||
|
comparison_policy: str
|
||||||
|
rationale: str
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"name": self.name,
|
||||||
|
"architecture": self.architecture,
|
||||||
|
"safetensors_repo": self.safetensors_repo,
|
||||||
|
"safetensors_precision": self.safetensors_precision,
|
||||||
|
"gguf_repo": self.gguf_repo,
|
||||||
|
"gguf_quant": self.gguf_quant,
|
||||||
|
"gguf_size_gb": self.gguf_size_gb,
|
||||||
|
"comparison_policy": self.comparison_policy,
|
||||||
|
"rationale": self.rationale,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class BenchmarkLane:
|
||||||
|
"""One side of the comparison the contract requires."""
|
||||||
|
|
||||||
|
id: str
|
||||||
|
runtime: str
|
||||||
|
device: str
|
||||||
|
recipe: str
|
||||||
|
concurrency_levels: tuple[int, ...]
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"id": self.id,
|
||||||
|
"runtime": self.runtime,
|
||||||
|
"device": self.device,
|
||||||
|
"recipe": self.recipe,
|
||||||
|
"concurrency_levels": list(self.concurrency_levels),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class PerformanceContract:
|
||||||
|
"""Machine-readable contract for the DGR-001 benchmark story."""
|
||||||
|
|
||||||
|
schema_version: int
|
||||||
|
story_id: str
|
||||||
|
model_target: ModelTarget
|
||||||
|
benchmark_lanes: tuple[BenchmarkLane, ...]
|
||||||
|
metrics: tuple[str, ...]
|
||||||
|
stop_condition: str
|
||||||
|
notes: tuple[str, ...] = ()
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
"schema_version": self.schema_version,
|
||||||
|
"story_id": self.story_id,
|
||||||
|
"model_target": self.model_target.to_dict(),
|
||||||
|
"benchmark_lanes": [lane.to_dict() for lane in self.benchmark_lanes],
|
||||||
|
"metrics": list(self.metrics),
|
||||||
|
"stop_condition": self.stop_condition,
|
||||||
|
"notes": list(self.notes),
|
||||||
|
}
|
||||||
|
|
||||||
|
def write_json(self, path: str | Path) -> Path:
|
||||||
|
path = Path(path)
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(json.dumps(self.to_dict(), indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_CONTRACT = PerformanceContract(
|
||||||
|
schema_version=SCHEMA_VERSION,
|
||||||
|
story_id=CONTRACT_ID,
|
||||||
|
model_target=ModelTarget(
|
||||||
|
name="DeepSeek-V2-Lite-Chat",
|
||||||
|
architecture="deepseek2",
|
||||||
|
safetensors_repo="deepseek-ai/DeepSeek-V2-Lite-Chat",
|
||||||
|
safetensors_precision="bfloat16",
|
||||||
|
gguf_repo="second-state/DeepSeek-V2-Lite-Chat-GGUF",
|
||||||
|
gguf_quant="Q2_K",
|
||||||
|
gguf_size_gb=6.43,
|
||||||
|
comparison_policy=(
|
||||||
|
"same model/revision, closest practical low-footprint precision pair: "
|
||||||
|
"BF16 safetensors versus Q2_K GGUF"
|
||||||
|
),
|
||||||
|
rationale=(
|
||||||
|
"Smallest DeepSeek-family benchmark anchor that still points toward "
|
||||||
|
"DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead "
|
||||||
|
"of falling back to a tiny but architecture-mismatched smoke model."
|
||||||
|
),
|
||||||
|
),
|
||||||
|
benchmark_lanes=(
|
||||||
|
BenchmarkLane(
|
||||||
|
id="transformers-safetensors-cpu",
|
||||||
|
runtime="transformers",
|
||||||
|
device="cpu",
|
||||||
|
recipe="current safetensors recipe",
|
||||||
|
concurrency_levels=(1, 4),
|
||||||
|
),
|
||||||
|
BenchmarkLane(
|
||||||
|
id="llama-cpp-gguf-cpu",
|
||||||
|
runtime="llama.cpp",
|
||||||
|
device="cpu",
|
||||||
|
recipe="whole-model GGUF recipe",
|
||||||
|
concurrency_levels=(1, 4),
|
||||||
|
),
|
||||||
|
BenchmarkLane(
|
||||||
|
id="transformers-safetensors-gpu",
|
||||||
|
runtime="transformers",
|
||||||
|
device="gpu",
|
||||||
|
recipe="current safetensors recipe",
|
||||||
|
concurrency_levels=(1, 4),
|
||||||
|
),
|
||||||
|
BenchmarkLane(
|
||||||
|
id="llama-cpp-gguf-gpu",
|
||||||
|
runtime="llama.cpp",
|
||||||
|
device="gpu",
|
||||||
|
recipe="whole-model GGUF recipe",
|
||||||
|
concurrency_levels=(1, 4),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
metrics=(
|
||||||
|
"ttft_ms",
|
||||||
|
"prefill_tok_per_sec",
|
||||||
|
"decode_tok_per_sec",
|
||||||
|
"p50_latency_ms",
|
||||||
|
"p95_latency_ms",
|
||||||
|
"aggregate_throughput_tok_per_sec",
|
||||||
|
"rss_bytes",
|
||||||
|
"vram_bytes",
|
||||||
|
"artifact_bytes",
|
||||||
|
"failure_count",
|
||||||
|
"output_drift",
|
||||||
|
),
|
||||||
|
stop_condition=(
|
||||||
|
"Stop if GGUF does not provide a meaningful speed or fit benefit over the "
|
||||||
|
"safetensors baseline for the chosen DeepSeek-family model target."
|
||||||
|
),
|
||||||
|
notes=(
|
||||||
|
"Real model execution stays opt-in and must keep model artifacts on the mounted drive.",
|
||||||
|
"Use the tiny fallback only for loader plumbing smoke tests; it does not replace the architecture-aligned baseline.",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_default_contract() -> PerformanceContract:
|
||||||
|
return DEFAULT_CONTRACT
|
||||||
|
|
||||||
|
|
||||||
|
BENCHMARK_SCHEMA_VERSION = 1
|
||||||
|
STUB_OUTPUT_TOKENS = ("mesh", "activation", "seam", "baseline")
|
||||||
|
# DeepSeek-V2-Lite is ~15.7B params at 2 bytes each; metadata only, nothing downloaded.
|
||||||
|
_SAFETENSORS_BF16_ARTIFACT_GB = 31.4
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class LaneSample:
|
||||||
|
"""Raw single-stream measurements one backend produces for a lane."""
|
||||||
|
|
||||||
|
ttft_ms: float
|
||||||
|
prefill_tok_per_sec: float
|
||||||
|
decode_tok_per_sec: float
|
||||||
|
rss_bytes: int
|
||||||
|
vram_bytes: int
|
||||||
|
artifact_bytes: int
|
||||||
|
output_tokens: tuple[str, ...]
|
||||||
|
failure_count: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
def _gb(value: float) -> int:
|
||||||
|
return int(value * 1024**3)
|
||||||
|
|
||||||
|
|
||||||
|
class StubLaneBackend:
|
||||||
|
"""Deterministic placeholder measurements until real lane execution lands.
|
||||||
|
|
||||||
|
The numbers are synthetic but directionally shaped — the Q2_K GGUF loads a
|
||||||
|
far smaller artifact and decodes faster than BF16 safetensors — so the
|
||||||
|
comparison and stop-condition plumbing can be exercised in CI.
|
||||||
|
"""
|
||||||
|
|
||||||
|
source = "stub-backend"
|
||||||
|
|
||||||
|
# (runtime, device) -> (ttft_ms, prefill tok/s, decode tok/s, rss GB, vram GB)
|
||||||
|
_PROFILES = {
|
||||||
|
("transformers", "cpu"): (1800.0, 45.0, 6.0, 33.0, 0.0),
|
||||||
|
("llama.cpp", "cpu"): (950.0, 90.0, 14.0, 7.1, 0.0),
|
||||||
|
("transformers", "gpu"): (420.0, 850.0, 34.0, 4.0, 33.0),
|
||||||
|
("llama.cpp", "gpu"): (260.0, 640.0, 52.0, 1.5, 7.5),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, contract: PerformanceContract) -> None:
|
||||||
|
self._contract = contract
|
||||||
|
|
||||||
|
def run(self, lane: BenchmarkLane) -> LaneSample:
|
||||||
|
ttft_ms, prefill, decode, rss_gb, vram_gb = self._PROFILES[(lane.runtime, lane.device)]
|
||||||
|
artifact_gb = (
|
||||||
|
self._contract.model_target.gguf_size_gb
|
||||||
|
if lane.runtime == "llama.cpp"
|
||||||
|
else _SAFETENSORS_BF16_ARTIFACT_GB
|
||||||
|
)
|
||||||
|
return LaneSample(
|
||||||
|
ttft_ms=ttft_ms,
|
||||||
|
prefill_tok_per_sec=prefill,
|
||||||
|
decode_tok_per_sec=decode,
|
||||||
|
rss_bytes=_gb(rss_gb),
|
||||||
|
vram_bytes=_gb(vram_gb),
|
||||||
|
artifact_bytes=_gb(artifact_gb),
|
||||||
|
output_tokens=STUB_OUTPUT_TOKENS,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _output_drift(tokens: tuple[str, ...], reference: tuple[str, ...]) -> float:
|
||||||
|
"""Fraction of positions where a lane's output diverges from its reference."""
|
||||||
|
length = max(len(tokens), len(reference))
|
||||||
|
if length == 0:
|
||||||
|
return 0.0
|
||||||
|
mismatches = sum(a != b for a, b in zip(tokens, reference)) + abs(len(tokens) - len(reference))
|
||||||
|
return round(mismatches / length, 4)
|
||||||
|
|
||||||
|
|
||||||
|
def _metrics_for(sample: LaneSample, concurrency: int, output_drift: float) -> dict:
|
||||||
|
# Stub concurrency model: batching scales throughput at 85% efficiency and
|
||||||
|
# stretches per-request token latency and TTFT accordingly.
|
||||||
|
efficiency = 1.0 if concurrency == 1 else 0.85
|
||||||
|
p50_latency_ms = round(1000.0 / (sample.decode_tok_per_sec * efficiency), 4)
|
||||||
|
return {
|
||||||
|
"ttft_ms": round(sample.ttft_ms * (1 + 0.1 * (concurrency - 1)), 4),
|
||||||
|
"prefill_tok_per_sec": round(sample.prefill_tok_per_sec * efficiency, 4),
|
||||||
|
"decode_tok_per_sec": round(sample.decode_tok_per_sec * efficiency, 4),
|
||||||
|
"p50_latency_ms": p50_latency_ms,
|
||||||
|
"p95_latency_ms": round(p50_latency_ms * 1.25, 4),
|
||||||
|
"aggregate_throughput_tok_per_sec": round(sample.decode_tok_per_sec * concurrency * efficiency, 4),
|
||||||
|
"rss_bytes": sample.rss_bytes,
|
||||||
|
"vram_bytes": sample.vram_bytes,
|
||||||
|
"artifact_bytes": sample.artifact_bytes,
|
||||||
|
"failure_count": sample.failure_count,
|
||||||
|
"output_drift": output_drift,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _compare_device(lanes: list[tuple[BenchmarkLane, LaneSample]], device: str) -> dict:
|
||||||
|
by_runtime = {lane.runtime: (lane, sample) for lane, sample in lanes if lane.device == device}
|
||||||
|
safetensors_lane, safetensors = by_runtime["transformers"]
|
||||||
|
gguf_lane, gguf = by_runtime["llama.cpp"]
|
||||||
|
memory_metric = "vram_bytes" if device == "gpu" else "rss_bytes"
|
||||||
|
decode_speedup = round(gguf.decode_tok_per_sec / safetensors.decode_tok_per_sec, 4)
|
||||||
|
artifact_bytes_ratio = round(gguf.artifact_bytes / max(1, safetensors.artifact_bytes), 4)
|
||||||
|
return {
|
||||||
|
"safetensors_lane": safetensors_lane.id,
|
||||||
|
"gguf_lane": gguf_lane.id,
|
||||||
|
"decode_speedup": decode_speedup,
|
||||||
|
"ttft_speedup": round(safetensors.ttft_ms / max(0.001, gguf.ttft_ms), 4),
|
||||||
|
"artifact_bytes_ratio": artifact_bytes_ratio,
|
||||||
|
"memory_metric": memory_metric,
|
||||||
|
"memory_bytes_ratio": round(
|
||||||
|
getattr(gguf, memory_metric) / max(1, getattr(safetensors, memory_metric)), 4
|
||||||
|
),
|
||||||
|
"output_drift": _output_drift(gguf.output_tokens, safetensors.output_tokens),
|
||||||
|
"gguf_benefit": decode_speedup >= 1.10 or artifact_bytes_ratio <= 0.5,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def run_performance_benchmark(
|
||||||
|
contract: PerformanceContract = DEFAULT_CONTRACT,
|
||||||
|
backend: StubLaneBackend | None = None,
|
||||||
|
) -> dict:
|
||||||
|
"""Run every contract lane through a backend and compare GGUF to safetensors."""
|
||||||
|
backend = backend if backend is not None else StubLaneBackend(contract)
|
||||||
|
lanes = [(lane, backend.run(lane)) for lane in contract.benchmark_lanes]
|
||||||
|
references = {
|
||||||
|
lane.device: sample.output_tokens for lane, sample in lanes if lane.runtime == "transformers"
|
||||||
|
}
|
||||||
|
lane_reports = []
|
||||||
|
for lane, sample in lanes:
|
||||||
|
drift = _output_drift(sample.output_tokens, references.get(lane.device, sample.output_tokens))
|
||||||
|
lane_reports.append({
|
||||||
|
**lane.to_dict(),
|
||||||
|
"output_tokens": list(sample.output_tokens),
|
||||||
|
"results": [
|
||||||
|
{"concurrency": level, "metrics": _metrics_for(sample, level, drift)}
|
||||||
|
for level in lane.concurrency_levels
|
||||||
|
],
|
||||||
|
})
|
||||||
|
devices = sorted({lane.device for lane, _ in lanes})
|
||||||
|
comparisons = {device: _compare_device(lanes, device) for device in devices}
|
||||||
|
gguf_benefit = any(comparison["gguf_benefit"] for comparison in comparisons.values())
|
||||||
|
return {
|
||||||
|
"schema_version": BENCHMARK_SCHEMA_VERSION,
|
||||||
|
"story_id": contract.story_id,
|
||||||
|
"source": getattr(backend, "source", "custom-backend"),
|
||||||
|
"model_target": contract.model_target.to_dict(),
|
||||||
|
"lanes": lane_reports,
|
||||||
|
"comparisons": comparisons,
|
||||||
|
"stop_condition": {
|
||||||
|
"text": contract.stop_condition,
|
||||||
|
"gguf_benefit": gguf_benefit,
|
||||||
|
"triggered": not gguf_benefit,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def run_real_model_endpoint_benchmark(
|
||||||
|
endpoints: Mapping[str, str],
|
||||||
|
*,
|
||||||
|
model: str,
|
||||||
|
contract: PerformanceContract = DEFAULT_CONTRACT,
|
||||||
|
timeout: float = 120.0,
|
||||||
|
) -> dict:
|
||||||
|
"""Run one live OpenAI-compatible request per lane against supplied endpoints.
|
||||||
|
|
||||||
|
The caller provides one URL per benchmark lane. The runner measures the
|
||||||
|
request/response round-trip at the client boundary and reuses the same
|
||||||
|
contract schema as the deterministic stub.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _sample_for_lane(lane: BenchmarkLane, endpoint: str) -> LaneSample:
|
||||||
|
prompt = " ".join(contract.model_target.rationale.split()[:6])
|
||||||
|
body = json.dumps(
|
||||||
|
{
|
||||||
|
"model": model,
|
||||||
|
"messages": [{"role": "user", "content": prompt}],
|
||||||
|
"max_tokens": len(STUB_OUTPUT_TOKENS),
|
||||||
|
"temperature": 0,
|
||||||
|
}
|
||||||
|
).encode("utf-8")
|
||||||
|
request = urllib.request.Request(
|
||||||
|
f"{endpoint.rstrip('/')}/v1/chat/completions",
|
||||||
|
data=body,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Meshnet-Lane": lane.id,
|
||||||
|
},
|
||||||
|
method="POST",
|
||||||
|
)
|
||||||
|
started = time.monotonic()
|
||||||
|
with urllib.request.urlopen(request, timeout=timeout) as response:
|
||||||
|
response_body = response.read()
|
||||||
|
session_id = response.headers.get("X-Meshnet-Session", f"{lane.id}-session")
|
||||||
|
elapsed_ms = round((time.monotonic() - started) * 1000, 4)
|
||||||
|
payload = json.loads(response_body)
|
||||||
|
content = payload["choices"][0]["message"]["content"]
|
||||||
|
tokens = tuple(content.split())
|
||||||
|
token_count = max(1, len(tokens))
|
||||||
|
artifact_gb = (
|
||||||
|
contract.model_target.gguf_size_gb
|
||||||
|
if lane.runtime == "llama.cpp"
|
||||||
|
else _SAFETENSORS_BF16_ARTIFACT_GB
|
||||||
|
)
|
||||||
|
return LaneSample(
|
||||||
|
ttft_ms=elapsed_ms,
|
||||||
|
prefill_tok_per_sec=round(token_count / max(0.001, elapsed_ms / 1000), 4),
|
||||||
|
decode_tok_per_sec=round(token_count / max(0.001, elapsed_ms / 1000), 4),
|
||||||
|
rss_bytes=0,
|
||||||
|
vram_bytes=0,
|
||||||
|
artifact_bytes=_gb(artifact_gb),
|
||||||
|
output_tokens=tokens,
|
||||||
|
)
|
||||||
|
|
||||||
|
lanes = []
|
||||||
|
for lane in contract.benchmark_lanes:
|
||||||
|
if lane.id not in endpoints:
|
||||||
|
raise KeyError(f"missing endpoint for lane {lane.id}")
|
||||||
|
lanes.append((lane, _sample_for_lane(lane, endpoints[lane.id])))
|
||||||
|
references = {
|
||||||
|
lane.device: sample.output_tokens for lane, sample in lanes if lane.runtime == "transformers"
|
||||||
|
}
|
||||||
|
lane_reports = []
|
||||||
|
for lane, sample in lanes:
|
||||||
|
drift = _output_drift(sample.output_tokens, references.get(lane.device, sample.output_tokens))
|
||||||
|
lane_reports.append({
|
||||||
|
**lane.to_dict(),
|
||||||
|
"output_tokens": list(sample.output_tokens),
|
||||||
|
"results": [
|
||||||
|
{"concurrency": level, "metrics": _metrics_for(sample, level, drift)}
|
||||||
|
for level in lane.concurrency_levels
|
||||||
|
],
|
||||||
|
})
|
||||||
|
devices = sorted({lane.device for lane, _ in lanes})
|
||||||
|
comparisons = {device: _compare_device(lanes, device) for device in devices}
|
||||||
|
gguf_benefit = any(comparison["gguf_benefit"] for comparison in comparisons.values())
|
||||||
|
return {
|
||||||
|
"schema_version": BENCHMARK_SCHEMA_VERSION,
|
||||||
|
"story_id": contract.story_id,
|
||||||
|
"source": "real-model-endpoints",
|
||||||
|
"model_target": contract.model_target.to_dict(),
|
||||||
|
"lanes": lane_reports,
|
||||||
|
"comparisons": comparisons,
|
||||||
|
"stop_condition": {
|
||||||
|
"text": contract.stop_condition,
|
||||||
|
"gguf_benefit": gguf_benefit,
|
||||||
|
"triggered": not gguf_benefit,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_lane_endpoints(pairs: list[str], parser: argparse.ArgumentParser) -> dict[str, str]:
|
||||||
|
endpoints: dict[str, str] = {}
|
||||||
|
for pair in pairs:
|
||||||
|
lane_id, sep, url = pair.partition("=")
|
||||||
|
if not sep or not lane_id or not url:
|
||||||
|
parser.error(f"--live-endpoint expects LANE_ID=URL, got {pair!r}")
|
||||||
|
endpoints[lane_id] = url
|
||||||
|
return endpoints
|
||||||
|
|
||||||
|
|
||||||
|
def _write_report(report: dict, path: Path) -> None:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv: list[str] | None = None) -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Write the DGR-001 performance contract JSON")
|
||||||
|
parser.add_argument("--json-out", type=Path, default=DEFAULT_OUTPUT_PATH, help="output JSON path")
|
||||||
|
parser.add_argument(
|
||||||
|
"--benchmark-out",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
help="also run the deterministic stub benchmark and write its JSON report here",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--live-endpoint",
|
||||||
|
action="append",
|
||||||
|
default=None,
|
||||||
|
metavar="LANE_ID=URL",
|
||||||
|
help="lane-to-endpoint mapping for the live benchmark; repeat once per contract lane",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--live-model",
|
||||||
|
default=None,
|
||||||
|
help="model name sent to live endpoints (default: contract safetensors repo)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--live-benchmark-out",
|
||||||
|
type=Path,
|
||||||
|
default=None,
|
||||||
|
help="run the live endpoint benchmark against --live-endpoint lanes and write its JSON report here",
|
||||||
|
)
|
||||||
|
args = parser.parse_args(argv)
|
||||||
|
if args.live_endpoint and args.live_benchmark_out is None:
|
||||||
|
parser.error("--live-endpoint requires --live-benchmark-out")
|
||||||
|
if args.live_benchmark_out is not None and not args.live_endpoint:
|
||||||
|
parser.error("--live-benchmark-out requires at least one --live-endpoint")
|
||||||
|
contract = build_default_contract()
|
||||||
|
path = contract.write_json(args.json_out)
|
||||||
|
print(path)
|
||||||
|
if args.benchmark_out is not None:
|
||||||
|
_write_report(run_performance_benchmark(contract), args.benchmark_out)
|
||||||
|
print(args.benchmark_out)
|
||||||
|
if args.live_endpoint:
|
||||||
|
report = run_real_model_endpoint_benchmark(
|
||||||
|
_parse_lane_endpoints(args.live_endpoint, parser),
|
||||||
|
model=args.live_model or contract.model_target.safetensors_repo,
|
||||||
|
contract=contract,
|
||||||
|
)
|
||||||
|
_write_report(report, args.live_benchmark_out)
|
||||||
|
print(args.live_benchmark_out)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": # pragma: no cover - CLI entry point
|
||||||
|
raise SystemExit(main())
|
||||||
286
tests/test_performance_contract.py
Normal file
286
tests/test_performance_contract.py
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
"""Tests for the DGR-001 performance contract metadata."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from meshnet_node.performance_contract import (
|
||||||
|
BENCHMARK_SCHEMA_VERSION,
|
||||||
|
DEFAULT_CONTRACT,
|
||||||
|
SCHEMA_VERSION,
|
||||||
|
main,
|
||||||
|
run_performance_benchmark,
|
||||||
|
run_real_model_endpoint_benchmark,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_contract_is_architecture_aligned_and_small():
|
||||||
|
"""The baseline stays on DeepSeek2 and uses the smallest DeepSeek-family GGUF.
|
||||||
|
|
||||||
|
Tags: performance, model, gguf
|
||||||
|
"""
|
||||||
|
payload = DEFAULT_CONTRACT.to_dict()
|
||||||
|
|
||||||
|
assert payload["schema_version"] == SCHEMA_VERSION
|
||||||
|
assert payload["story_id"] == "DGR-001"
|
||||||
|
assert payload["model_target"] == {
|
||||||
|
"name": "DeepSeek-V2-Lite-Chat",
|
||||||
|
"architecture": "deepseek2",
|
||||||
|
"safetensors_repo": "deepseek-ai/DeepSeek-V2-Lite-Chat",
|
||||||
|
"safetensors_precision": "bfloat16",
|
||||||
|
"gguf_repo": "second-state/DeepSeek-V2-Lite-Chat-GGUF",
|
||||||
|
"gguf_quant": "Q2_K",
|
||||||
|
"gguf_size_gb": 6.43,
|
||||||
|
"comparison_policy": (
|
||||||
|
"same model/revision, closest practical low-footprint precision pair: "
|
||||||
|
"BF16 safetensors versus Q2_K GGUF"
|
||||||
|
),
|
||||||
|
"rationale": (
|
||||||
|
"Smallest DeepSeek-family benchmark anchor that still points toward "
|
||||||
|
"DeepSeek-V4-Flash; keeps the runtime on the DeepSeek2 path instead "
|
||||||
|
"of falling back to a tiny but architecture-mismatched smoke model."
|
||||||
|
),
|
||||||
|
}
|
||||||
|
assert payload["benchmark_lanes"] == [
|
||||||
|
{
|
||||||
|
"id": "transformers-safetensors-cpu",
|
||||||
|
"runtime": "transformers",
|
||||||
|
"device": "cpu",
|
||||||
|
"recipe": "current safetensors recipe",
|
||||||
|
"concurrency_levels": [1, 4],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "llama-cpp-gguf-cpu",
|
||||||
|
"runtime": "llama.cpp",
|
||||||
|
"device": "cpu",
|
||||||
|
"recipe": "whole-model GGUF recipe",
|
||||||
|
"concurrency_levels": [1, 4],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "transformers-safetensors-gpu",
|
||||||
|
"runtime": "transformers",
|
||||||
|
"device": "gpu",
|
||||||
|
"recipe": "current safetensors recipe",
|
||||||
|
"concurrency_levels": [1, 4],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "llama-cpp-gguf-gpu",
|
||||||
|
"runtime": "llama.cpp",
|
||||||
|
"device": "gpu",
|
||||||
|
"recipe": "whole-model GGUF recipe",
|
||||||
|
"concurrency_levels": [1, 4],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
assert "ttft_ms" in payload["metrics"]
|
||||||
|
assert "output_drift" in payload["metrics"]
|
||||||
|
assert "meaningful speed or fit benefit" in payload["stop_condition"]
|
||||||
|
assert any("mounted drive" in note for note in payload["notes"])
|
||||||
|
|
||||||
|
|
||||||
|
def test_contract_cli_writes_json(tmp_path, capsys):
|
||||||
|
"""The contract can be emitted as a machine-readable artifact.
|
||||||
|
|
||||||
|
Tags: performance, artifact
|
||||||
|
"""
|
||||||
|
output = tmp_path / "performance-contract.json"
|
||||||
|
|
||||||
|
assert main(["--json-out", str(output)]) == 0
|
||||||
|
written = json.loads(output.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
assert written == DEFAULT_CONTRACT.to_dict()
|
||||||
|
assert str(output) in capsys.readouterr().out
|
||||||
|
|
||||||
|
|
||||||
|
def test_stub_benchmark_covers_every_lane_concurrency_and_metric():
|
||||||
|
"""The runner exercises all four CPU/GPU lanes with the full metric set.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, gguf
|
||||||
|
"""
|
||||||
|
report = run_performance_benchmark()
|
||||||
|
|
||||||
|
assert report["schema_version"] == BENCHMARK_SCHEMA_VERSION
|
||||||
|
assert report["story_id"] == "DGR-001"
|
||||||
|
assert report["source"] == "stub-backend"
|
||||||
|
assert report["model_target"] == DEFAULT_CONTRACT.model_target.to_dict()
|
||||||
|
assert [lane["id"] for lane in report["lanes"]] == [
|
||||||
|
lane.id for lane in DEFAULT_CONTRACT.benchmark_lanes
|
||||||
|
]
|
||||||
|
for lane in report["lanes"]:
|
||||||
|
assert [result["concurrency"] for result in lane["results"]] == [1, 4]
|
||||||
|
for result in lane["results"]:
|
||||||
|
assert set(result["metrics"]) == set(DEFAULT_CONTRACT.metrics)
|
||||||
|
assert result["metrics"]["failure_count"] == 0
|
||||||
|
assert result["metrics"]["decode_tok_per_sec"] > 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_stub_benchmark_is_deterministic():
|
||||||
|
"""Two runs produce byte-identical reports; no clocks or randomness leak in.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, deterministic
|
||||||
|
"""
|
||||||
|
first = run_performance_benchmark()
|
||||||
|
second = run_performance_benchmark()
|
||||||
|
|
||||||
|
assert first == second
|
||||||
|
assert json.dumps(first, sort_keys=True) == json.dumps(second, sort_keys=True)
|
||||||
|
|
||||||
|
|
||||||
|
def test_stub_benchmark_compares_gguf_against_safetensors_per_device():
|
||||||
|
"""Each device gets a GGUF-vs-safetensors comparison and a stop-condition verdict.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, gguf
|
||||||
|
"""
|
||||||
|
report = run_performance_benchmark()
|
||||||
|
|
||||||
|
assert set(report["comparisons"]) == {"cpu", "gpu"}
|
||||||
|
cpu, gpu = report["comparisons"]["cpu"], report["comparisons"]["gpu"]
|
||||||
|
assert cpu["safetensors_lane"] == "transformers-safetensors-cpu"
|
||||||
|
assert cpu["gguf_lane"] == "llama-cpp-gguf-cpu"
|
||||||
|
assert cpu["memory_metric"] == "rss_bytes"
|
||||||
|
assert gpu["safetensors_lane"] == "transformers-safetensors-gpu"
|
||||||
|
assert gpu["gguf_lane"] == "llama-cpp-gguf-gpu"
|
||||||
|
assert gpu["memory_metric"] == "vram_bytes"
|
||||||
|
for comparison in (cpu, gpu):
|
||||||
|
assert comparison["decode_speedup"] > 1.0
|
||||||
|
assert comparison["artifact_bytes_ratio"] < 0.5
|
||||||
|
assert comparison["memory_bytes_ratio"] < 1.0
|
||||||
|
assert comparison["output_drift"] == 0.0
|
||||||
|
assert comparison["gguf_benefit"] is True
|
||||||
|
assert report["stop_condition"]["gguf_benefit"] is True
|
||||||
|
assert report["stop_condition"]["triggered"] is False
|
||||||
|
assert report["stop_condition"]["text"] == DEFAULT_CONTRACT.stop_condition
|
||||||
|
|
||||||
|
|
||||||
|
def test_contract_cli_writes_benchmark_report(tmp_path, capsys):
|
||||||
|
"""--benchmark-out emits the stub benchmark report next to the contract.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, artifact
|
||||||
|
"""
|
||||||
|
contract_out = tmp_path / "performance-contract.json"
|
||||||
|
benchmark_out = tmp_path / "artifacts" / "stub-benchmark-report.json"
|
||||||
|
|
||||||
|
assert main(["--json-out", str(contract_out), "--benchmark-out", str(benchmark_out)]) == 0
|
||||||
|
report = json.loads(benchmark_out.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
assert report == run_performance_benchmark()
|
||||||
|
output = capsys.readouterr().out
|
||||||
|
assert str(contract_out) in output
|
||||||
|
assert str(benchmark_out) in output
|
||||||
|
|
||||||
|
|
||||||
|
def test_real_model_endpoint_benchmark_uses_lane_specific_endpoints_and_shared_schema():
|
||||||
|
"""The live client path fans out to one endpoint per CPU/GPU lane.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, live
|
||||||
|
"""
|
||||||
|
response = MagicMock()
|
||||||
|
response.read.return_value = json.dumps({"choices": [{"message": {"content": "mesh activation"}}]}).encode()
|
||||||
|
response.headers.get.return_value = "lane-session"
|
||||||
|
response.__enter__.return_value = response
|
||||||
|
|
||||||
|
endpoints = {
|
||||||
|
"transformers-safetensors-cpu": "http://cpu-safetensors",
|
||||||
|
"llama-cpp-gguf-cpu": "http://cpu-gguf",
|
||||||
|
"transformers-safetensors-gpu": "http://gpu-safetensors",
|
||||||
|
"llama-cpp-gguf-gpu": "http://gpu-gguf",
|
||||||
|
}
|
||||||
|
|
||||||
|
with patch("meshnet_node.performance_contract.urllib.request.urlopen", return_value=response) as urlopen:
|
||||||
|
report = run_real_model_endpoint_benchmark(endpoints=endpoints, model="deepseek-ai/DeepSeek-V2-Lite-Chat")
|
||||||
|
|
||||||
|
assert report["source"] == "real-model-endpoints"
|
||||||
|
assert report["model_target"] == DEFAULT_CONTRACT.model_target.to_dict()
|
||||||
|
assert set(report["comparisons"]) == {"cpu", "gpu"}
|
||||||
|
assert urlopen.call_count == len(endpoints)
|
||||||
|
called_urls = [call.args[0].full_url for call in urlopen.call_args_list]
|
||||||
|
assert called_urls == [f"{url}/v1/chat/completions" for url in endpoints.values()]
|
||||||
|
for lane in report["lanes"]:
|
||||||
|
assert lane["results"][0]["metrics"]["decode_tok_per_sec"] > 0
|
||||||
|
assert lane["results"][0]["metrics"]["ttft_ms"] > 0
|
||||||
|
assert lane["output_tokens"] == ["mesh", "activation"]
|
||||||
|
assert report["comparisons"]["cpu"]["gguf_lane"] == "llama-cpp-gguf-cpu"
|
||||||
|
assert report["comparisons"]["gpu"]["gguf_lane"] == "llama-cpp-gguf-gpu"
|
||||||
|
|
||||||
|
|
||||||
|
def test_contract_cli_runs_live_endpoint_benchmark(tmp_path, capsys):
|
||||||
|
"""--live-endpoint mappings drive the live runner and write its report.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, live, artifact
|
||||||
|
"""
|
||||||
|
contract_out = tmp_path / "performance-contract.json"
|
||||||
|
live_out = tmp_path / "artifacts" / "live-benchmark-report.json"
|
||||||
|
endpoints = {
|
||||||
|
"transformers-safetensors-cpu": "http://cpu-safetensors",
|
||||||
|
"llama-cpp-gguf-cpu": "http://cpu-gguf",
|
||||||
|
"transformers-safetensors-gpu": "http://gpu-safetensors",
|
||||||
|
"llama-cpp-gguf-gpu": "http://gpu-gguf",
|
||||||
|
}
|
||||||
|
fake_report = {"schema_version": BENCHMARK_SCHEMA_VERSION, "source": "real-model-endpoints"}
|
||||||
|
argv = ["--json-out", str(contract_out), "--live-benchmark-out", str(live_out)]
|
||||||
|
for lane_id, url in endpoints.items():
|
||||||
|
argv += ["--live-endpoint", f"{lane_id}={url}"]
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"meshnet_node.performance_contract.run_real_model_endpoint_benchmark",
|
||||||
|
return_value=fake_report,
|
||||||
|
) as runner:
|
||||||
|
assert main(argv) == 0
|
||||||
|
|
||||||
|
runner.assert_called_once_with(
|
||||||
|
endpoints,
|
||||||
|
model=DEFAULT_CONTRACT.model_target.safetensors_repo,
|
||||||
|
contract=DEFAULT_CONTRACT,
|
||||||
|
)
|
||||||
|
assert json.loads(live_out.read_text(encoding="utf-8")) == fake_report
|
||||||
|
output = capsys.readouterr().out
|
||||||
|
assert str(contract_out) in output
|
||||||
|
assert str(live_out) in output
|
||||||
|
|
||||||
|
|
||||||
|
def test_contract_cli_passes_explicit_live_model(tmp_path):
|
||||||
|
"""--live-model overrides the contract's safetensors repo default.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, live
|
||||||
|
"""
|
||||||
|
live_out = tmp_path / "live-benchmark-report.json"
|
||||||
|
argv = [
|
||||||
|
"--json-out", str(tmp_path / "performance-contract.json"),
|
||||||
|
"--live-benchmark-out", str(live_out),
|
||||||
|
"--live-endpoint", "transformers-safetensors-cpu=http://cpu-safetensors",
|
||||||
|
"--live-model", "local/DeepSeek-V2-Lite-Chat-Q2_K",
|
||||||
|
]
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"meshnet_node.performance_contract.run_real_model_endpoint_benchmark",
|
||||||
|
return_value={},
|
||||||
|
) as runner:
|
||||||
|
assert main(argv) == 0
|
||||||
|
|
||||||
|
assert runner.call_args.kwargs["model"] == "local/DeepSeek-V2-Lite-Chat-Q2_K"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"argv",
|
||||||
|
[
|
||||||
|
["--live-endpoint", "transformers-safetensors-cpu=http://cpu"],
|
||||||
|
["--live-benchmark-out", "live-report.json"],
|
||||||
|
[
|
||||||
|
"--live-endpoint", "not-a-mapping",
|
||||||
|
"--live-benchmark-out", "live-report.json",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
ids=["endpoint-without-out", "out-without-endpoint", "malformed-mapping"],
|
||||||
|
)
|
||||||
|
def test_contract_cli_rejects_incomplete_live_arguments(tmp_path, argv, capsys):
|
||||||
|
"""Live flags must arrive as a consistent LANE_ID=URL + output-path set.
|
||||||
|
|
||||||
|
Tags: performance, benchmark, live, cli
|
||||||
|
"""
|
||||||
|
with pytest.raises(SystemExit) as excinfo:
|
||||||
|
main(["--json-out", str(tmp_path / "performance-contract.json"), *argv])
|
||||||
|
|
||||||
|
assert excinfo.value.code == 2
|
||||||
|
assert "--live-" in capsys.readouterr().err
|
||||||
Reference in New Issue
Block a user