diff --git a/src/code/issue5/.gitattributes b/src/code/issue5/.gitattributes new file mode 100644 index 0000000..555fa7e --- /dev/null +++ b/src/code/issue5/.gitattributes @@ -0,0 +1,2 @@ +# Preserve machine-generated raw logs byte-for-byte; their manifest hashes are evidence. +results/raw/** -whitespace diff --git a/src/code/issue5/.gitignore b/src/code/issue5/.gitignore new file mode 100644 index 0000000..cedb147 --- /dev/null +++ b/src/code/issue5/.gitignore @@ -0,0 +1,13 @@ +.venv/ +.uv-bootstrap/ +__pycache__/ +.pytest_cache/ +.ruff_cache/ +*.egg-info/ +dist/ +build/ +configs/*.env +results/runtime/ +results/logs/ +results/derived/fixture/ +results/.last_*_run_id diff --git a/src/code/issue5/Makefile b/src/code/issue5/Makefile new file mode 100644 index 0000000..9a5935a --- /dev/null +++ b/src/code/issue5/Makefile @@ -0,0 +1,20 @@ +.PHONY: test lint check model-example analyze-fixture + +test: + uv run python -m pytest -q + +lint: + uv run ruff check kvbreak benchmarks tests + uv run ruff format --check kvbreak benchmarks tests + +check: lint test + bash -n orchestration/*.sh orchestration/gates/*.sh + git diff --check + +model-example: + uv run python -m kvbreak.cli model --full-prefill-ms 800 --suffix-prefill-ms 360 \ + --hit-rate 0.5 --kv-bytes 1073741824 --metadata-ms 2 --startup-ms 1 --restore-ms 20 + +analyze-fixture: + uv run python -m kvbreak.cli analyze --input tests/fixtures/requests.jsonl \ + --measurement-s 60 --output-dir results/derived/fixture diff --git a/src/code/issue5/README.md b/src/code/issue5/README.md new file mode 100644 index 0000000..e54be72 --- /dev/null +++ b/src/code/issue5/README.md @@ -0,0 +1,162 @@ +# Issue 5:KV Cache 以存代算临界带宽与 TCP/RDMA 对照实验 + +本目录实现 `src/test/issue5/README.md` 的可复现实验骨架:从实测 prefill 分解计算临界带宽,使用 Mooncake Store + vLLM `MooncakeStoreConnector` 在相同模型、提示词、命中率和 TTFT SLO 下对照 TCP 与 RDMA,并把原始记录、失败请求、运行配置和文件哈希一起保留下来。 + +> 证据边界:仓库当前包含已通过本地测试的模型、负载统计、证据判定和双机编排代码;不包含伪造的 A40/Mooncake 性能数字。`report/RESULTS.md` 中只有完成远端 Gate 并校验 manifest 后,才允许填写 `MEASURED` 结果。2026-08-01 已完成 Pythia 14M 单请求 peermem GPUDirect RDMA 兼容性闭环,但 Qwen 7B 正式性能矩阵仍为 `UNKNOWN`。 + +## 方法概览 + +串行临界条件为: + +```text +Tcache(B) = Tmeta + Tstartup + KVbytes / B + Trestore + Tprefill(suffix) +Bcrit = KVbytes / (Tprefill(full) - Tprefill(suffix) - Tmeta - Tstartup - Trestore) +``` + +只有 `B > Bcrit` 才判为有收益;分母不大于零时报告 `never_profitable`,命中率为零时报告 `no_hit`,不会用无穷大或零掩盖边界情况。重叠执行使用数值求根的独立模型,模型的所有输入都写入结果。 + +KV 容量采用实际模型的 GQA 维度: + +```text +KVbytes = 2 × layers × cached_tokens × num_kv_heads × head_dim × bytes_per_element +``` + +## 本地快速验证 + +需要 Python 3.10–3.12 和 [uv](https://docs.astral.sh/uv/): + +```bash +cd src/code/issue5 +uv sync --extra dev +make check +make model-example +make analyze-fixture +``` + +示例模型命令只演示计算路径,不是实测结论。分析器会把 timeout/error/OOM 保留在分母中,QPM 只按成功完成请求计算。 + +## 双机实验 + +建议拓扑:GPU 节点运行 Writer/Reader/recompute,独立节点持有 Mooncake Store。两个 vLLM 实例的 `global_segment_size` 都是 `0`,避免把 requester 本机内存误当成共享远端 Store。 + +1. 在 Linux/CUDA 节点解析 `requirements-remote.in`,记录最终锁文件和包版本。 +2. 复制并检查 `configs/tcp.env.example`、`configs/rdma.env.example`;不要把密钥写进配置。 +3. 两台机器分别运行 `orchestration/preflight.sh`,保存完整输出。 +4. 运行原始链路 Gate;RDMA 使用 `mlx5_0` 与明确 GID index,保留 perftest stdout/stderr。 +5. 启动 Store Owner,再分别启动 Writer、Reader 或 recompute。三种角色共享同一模型 revision、tokenizer revision、RoPE、TP、dtype 和随机种子。 +6. 按 `run_matrix.sh` 的固定 Gate 顺序逐步放大;任一 Gate 失败就停止,不把部分数据升级成正式结果。 +7. 收集 `results/raw`,生成 manifest 哈希,再用 `kvbreak analyze` 生成派生表。 + +脚本只停止本项目 PID 文件指向、且工作目录仍位于本项目下的进程,不使用全局进程名清理。 + +Store 与 requester 的 RoCE IP 不再写死在版本库。启动 vLLM 前显式传入: + +```bash +export MOONCAKE_STORE_HOST= +export MOONCAKE_REQUESTER_HOST= +export ISSUE5_WRITER_GPUS=0,1 +export ISSUE5_READER_GPUS=0,1 +export ISSUE5_RECOMPUTE_GPUS=0,1 +``` + +RDMA 还必须显式选择 GPU 内存注册路径,不允许继承 Mooncake 的版本默认值: + +```bash +# 开放内核模块、且所选 GPU 的 CUDA attribute 124 为 1 时使用 +export ISSUE5_RDMA_GPU_REGISTRATION=dmabuf + +# 管理员已加载 nvidia-peermem 或 nv_peer_mem 时使用 +export ISSUE5_RDMA_GPU_REGISTRATION=peermem +``` + +`start_vllm.sh` 会在进程启动前查询所选物理 GPU 的 +`GPU_DIRECT_RDMA_SUPPORTED`(CUDA attribute 116)和 `DMA_BUF_SUPPORTED` +(attribute 124),并检查 peer-memory 模块是否已经加载。校验通过后,脚本才把 +`dmabuf` 映射为 `WITH_NVIDIA_PEERMEM=0`、把 `peermem` 映射为 +`WITH_NVIDIA_PEERMEM=1`。未设置、拼写错误或能力不满足都会 fail closed。 + +远端模型不在默认路径,或目标 vLLM 需要改变加载策略时,可显式覆盖: + +```bash +export ISSUE5_MODEL_CONFIG=$PWD/results/runtime/model.resolved.yaml +export ISSUE5_SAFETENSORS_LOAD_STRATEGY=eager # lazy|eager|prefetch +export ISSUE5_ENFORCE_EAGER=1 # 0|1 +``` + +这些值会进入环境 provenance 白名单。每次启动前,脚本会生成 +`results/runtime/vllm--.environment.json`,脱敏记录最终 +`CUDA_VISIBLE_DEVICES`、注册策略与派生的 `WITH_NVIDIA_PEERMEM`;未在白名单内的 +token/secret 不会落盘。`start_vllm.sh` 对 vLLM 0.23 使用 +`--hf-overrides` 传递 RoPE 配置,并拒绝未知加载策略,避免参数静默失效。 + +脚本会从只含 transport 差异的模板生成 `results/runtime/*.resolved.json`,使 TCP/RDMA 的拓扑完全一致,同时把解析后的配置纳入运行证据。Writer、Reader 和 recompute 共用 GPU 时必须串行执行,不允许服务重叠。 + +## 远端命中与 RDMA 证明标准 + +- 远端命中同时要求:cached token 非零、Store GET 字节达到理论 KV 字节的 80%、Reader 单次使用或经过可证明的本地驱逐环、Reader 本地 cache hit 为零、输出摘要匹配 recompute 对照。 +- `protocol=rdma` 只是配置意图。只有 RDMA 传输已加载、无 fallback、RDMA 计数器增量与 payload 相符,且 TCP payload 增量足够小,才升级成 `RDMA_HOST_STAGING`。 +- 只有进一步证明 CUDA 内存注册且没有 host staging,才标为 `GPUDIRECT_RDMA`。否则绝不宣传 GPUDirect。 + +请求完成后还可把 recompute JSONL、Reader JSONL 与 vLLM Prometheus 快照交叉验证: + +```bash +uv run kvbreak verify-remote-hit \ + --baseline results/raw//node1/requests/recompute.jsonl \ + --reader results/raw//node1/requests/reader.jsonl \ + --metrics results/raw//node1/mooncake/vllm-reader-prometheus.txt \ + --model-name \ + --output results/raw//remote-hit-verdict.json +``` + +只有请求集合一致、全部成功、输出摘要逐项一致、Store GET 字节和外部命中 token +至少达到期望值的 80%,且 GET 失败键为零时,命令才以成功状态退出。 + +Mooncake 0.3.12 发布源码的实际默认值是 `WITH_NVIDIA_PEERMEM=true`,即 GPU 指针 +默认进入依赖 `nvidia-peermem`/`nv_peer_mem` 的 legacy `ibv_reg_mr` 路径;运行时显式 +设置 `WITH_NVIDIA_PEERMEM=0` 才选择 DMA-BUF 导出与 `ibv_reg_dmabuf_mr`。若日志出现 +`Failed to register memory: Bad address`、`register_buffer failed` 或 +`AddressNotRegistered`,即使裸 `ib_write_bw` 通过,也必须停止 RDMA 端到端 Gate。 +`MC_STORE_MEMCPY=1` 控制本地端点 memcpy,不能当成可靠的 GPU→Host staging 回退。 + +2026-08-01 的双节点诊断进一步确认:Requester node1 的所有 A40 均报告 attribute +116=1、attribute 124=0,而当时 peer-memory 模块存在于磁盘但未加载;强制 DMA-BUF +后,旧的 `Bad address` 消失,Mooncake 明确报告该 GPU 不支持 DMA-BUF。Store node3 +的开放 NVIDIA 内核模块下 attribute 124=1。这组根因证据见 +`results/raw/remote-20260801/`。 + +在用户明确授权后,node1 加载了版本与 kernel/driver 匹配的 +`nvidia_peermem` 580.95.05,并使用空闲 GPU 0 重跑单请求 Writer/Reader smoke。 +Writer 63/63 PUT keys、Reader 63/63 GET keys 全部成功,Reader 读取的 +3,096,576 bytes 与理论 KV payload 一致,1008/1008 cached tokens 被外部前缀 +cache 命中,输出摘要与 fresh recompute 一致。显式 peermem 注册、成功的 +CUDA-backed KV arena 注册、禁用的 endpoint memcpy/host staging、运行时 +`nvidia_peermem` use count 与方向匹配的 RDMA 计数器增量共同将这次功能试验升级为 +`GPUDIRECT_RDMA_COMPATIBILITY`。原始证据、机器判定和 manifest 见 +`results/raw/remote-20260801-peermem-smoke/`。该结论只证明单请求 Pythia 14M +兼容性,不是 Qwen 7B、长上下文、QPM、SLO 或 RDMA-over-TCP 加速结论。 + +## 目录 + +```text +kvbreak/ 临界模型、统计、证据分级、分析和 manifest 校验 +benchmarks/ 确定性工作负载、开放环负载统计、Store payload 校验 +configs/ 锁定模型与只改变 transport 字段的 TCP/RDMA 配置 +orchestration/ 预检、部署、启停、网络基准和分阶段 Gate +tests/ 单元测试、失败样本和安全性回归测试 +report/ 正式结果模板与限制 +``` + +## 上游与版本 + +- vLLM:`>=0.23,<0.24` +- Mooncake Transfer Engine:`>=0.3.12,<0.4` +- 模型:`Qwen/Qwen2.5-7B-Instruct`,配置锁到 upstream verified commit `a09a354`;正式 run manifest 还应记录解析后的完整 SHA。 + +这些范围只用于目标 Linux/CUDA 环境解析;macOS 本地锁文件不冒充 GPU 节点依赖锁。 + +接口与数据路径依据:[Mooncake Store 设计文档](https://github.com/kvcache-ai/Mooncake/blob/main/docs/source/design/mooncake-store.md)、 +[vLLM 0.23 Mooncake Store Connector 指南](https://docs.vllm.ai/en/v0.23.0/features/mooncake_store_connector_usage/)、 +[Mooncake v0.3.12 环境变量源码](https://github.com/kvcache-ai/Mooncake/blob/v0.3.12/mooncake-common/src/environ.cpp#L126)、 +[Mooncake v0.3.12 RDMA 注册实现](https://github.com/kvcache-ai/Mooncake/blob/v0.3.12/mooncake-transfer-engine/src/transport/rdma_transport/rdma_context.cpp)、 +[DMA-BUF 引入 PR #2164](https://github.com/kvcache-ai/Mooncake/pull/2164) 与 +[恢复 legacy 默认值 PR #2192](https://github.com/kvcache-ai/Mooncake/pull/2192)。 diff --git a/src/code/issue5/benchmarks/__init__.py b/src/code/issue5/benchmarks/__init__.py new file mode 100644 index 0000000..b63f92e --- /dev/null +++ b/src/code/issue5/benchmarks/__init__.py @@ -0,0 +1 @@ +"""Benchmark entry points for issue 5.""" diff --git a/src/code/issue5/benchmarks/loadgen.py b/src/code/issue5/benchmarks/loadgen.py new file mode 100644 index 0000000..0d0a59d --- /dev/null +++ b/src/code/issue5/benchmarks/loadgen.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +import math +from dataclasses import dataclass + +import numpy as np + + +@dataclass(frozen=True) +class RequestTiming: + request_id: str + scheduled_at_s: float + sent_at_s: float + first_token_at_s: float | None + completed_at_s: float + success: bool + + @property + def ttft_ms(self) -> float | None: + if self.first_token_at_s is None: + return None + return (self.first_token_at_s - self.sent_at_s) * 1_000 + + +@dataclass(frozen=True) +class LoadPointSummary: + successful_requests: int + total_requests: int + error_rate: float + median_ttft_ms: float + p95_ttft_ms: float + actual_qpm: float + max_inflight: int + compliant: bool + + +def arrival_schedule(*, offered_qps: float, count: int, start_s: float = 0) -> list[float]: + """Return fixed open-loop arrival times; completions never delay later sends.""" + if offered_qps <= 0: + raise ValueError("offered_qps must be positive") + if count < 0: + raise ValueError("count must be non-negative") + interval = 1 / offered_qps + return [start_s + index * interval for index in range(count)] + + +def max_inflight(timings: list[RequestTiming]) -> int: + events: list[tuple[float, int]] = [] + for timing in timings: + if timing.completed_at_s < timing.sent_at_s: + raise ValueError("completion cannot precede send") + events.extend(((timing.sent_at_s, 1), (timing.completed_at_s, -1))) + # Count a request sent exactly when another completes as overlapping. + events.sort(key=lambda item: (item[0], -item[1])) + current = peak = 0 + for _, delta in events: + current += delta + peak = max(peak, current) + return peak + + +def summarize_load_point( + timings: list[RequestTiming], + *, + measurement_s: float, + slo_ms: float, + max_error_rate: float = 0.01, +) -> LoadPointSummary: + if measurement_s <= 0 or slo_ms <= 0: + raise ValueError("measurement_s and slo_ms must be positive") + if not 0 <= max_error_rate <= 1: + raise ValueError("max_error_rate must be in [0, 1]") + total = len(timings) + successes = [timing for timing in timings if timing.success and timing.ttft_ms is not None] + values = [float(timing.ttft_ms) for timing in successes if timing.ttft_ms is not None] + successful = len(successes) + error_rate = (total - successful) / total if total else 1.0 + median = float(np.median(values)) if values else math.inf + p95 = float(np.percentile(values, 95)) if values else math.inf + actual_qpm = successful * 60 / measurement_s + compliant = bool(values) and p95 <= slo_ms and error_rate <= max_error_rate + return LoadPointSummary( + successful_requests=successful, + total_requests=total, + error_rate=error_rate, + median_ttft_ms=median, + p95_ttft_ms=p95, + actual_qpm=actual_qpm, + max_inflight=max_inflight(timings), + compliant=compliant, + ) diff --git a/src/code/issue5/benchmarks/mooncake_store_bench.py b/src/code/issue5/benchmarks/mooncake_store_bench.py new file mode 100644 index 0000000..d1b53f5 --- /dev/null +++ b/src/code/issue5/benchmarks/mooncake_store_bench.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +import hashlib +import random + + +def make_payload(size_bytes: int, *, seed: int) -> bytes: + if size_bytes < 0: + raise ValueError("size_bytes must be non-negative") + return random.Random(seed).randbytes(size_bytes) + + +def verify_payload(expected: bytes, actual: bytes) -> bool: + return ( + len(expected) == len(actual) + and hashlib.sha256(expected).digest() == hashlib.sha256(actual).digest() + ) + + +def bandwidth_bytes_per_s(*, completed_bytes: int, wall_s: float) -> float: + if completed_bytes < 0: + raise ValueError("completed_bytes must be non-negative") + if wall_s <= 0: + raise ValueError("wall_s must be positive") + return completed_bytes / wall_s diff --git a/src/code/issue5/benchmarks/network_probe.py b/src/code/issue5/benchmarks/network_probe.py new file mode 100644 index 0000000..100ca45 --- /dev/null +++ b/src/code/issue5/benchmarks/network_probe.py @@ -0,0 +1,291 @@ +from __future__ import annotations + +import argparse +import hashlib +import json +import socket +import struct +import threading +import time +from concurrent.futures import ThreadPoolExecutor +from pathlib import Path +from typing import Any + +import numpy as np + +HEADER = struct.Struct("!QI32s") +MAX_FRAME_BYTES = 1 << 30 + + +def encode_frame(sequence: int, payload: bytes) -> bytes: + if sequence < 0 or len(payload) > MAX_FRAME_BYTES: + raise ValueError("invalid frame dimensions") + return HEADER.pack(sequence, len(payload), hashlib.sha256(payload).digest()) + payload + + +def _recv_exact(connection: socket.socket, size: int) -> bytes: + chunks: list[bytes] = [] + remaining = size + while remaining: + chunk = connection.recv(remaining) + if not chunk: + raise EOFError(f"connection closed with {remaining} bytes missing") + chunks.append(chunk) + remaining -= len(chunk) + return b"".join(chunks) + + +def recv_frame(connection: socket.socket) -> tuple[int, bytes]: + sequence, size, expected_digest = HEADER.unpack(_recv_exact(connection, HEADER.size)) + if size > MAX_FRAME_BYTES: + raise ValueError("frame exceeds maximum size") + payload = _recv_exact(connection, size) + if hashlib.sha256(payload).digest() != expected_digest: + raise ValueError(f"checksum mismatch at sequence {sequence}") + return sequence, payload + + +def summarize_bandwidth( + *, + completed_bytes: list[int], + started_at_s: list[float], + completed_at_s: list[float], +) -> dict[str, float | int]: + if not completed_bytes or not ( + len(completed_bytes) == len(started_at_s) == len(completed_at_s) + ): + raise ValueError("bandwidth vectors must have the same non-zero length") + if any(value < 0 for value in completed_bytes): + raise ValueError("completed bytes must be non-negative") + wall_s = max(completed_at_s) - min(started_at_s) + if wall_s <= 0: + raise ValueError("aggregate wall time must be positive") + total = sum(completed_bytes) + return { + "connections": len(completed_bytes), + "completed_bytes": total, + "wall_s": wall_s, + "bandwidth_gbit_s": total * 8 / wall_s / 1e9, + } + + +def summarize_latency_us(values: list[float]) -> dict[str, float | int]: + if not values or any(value < 0 for value in values): + raise ValueError("latency samples must be non-empty and non-negative") + samples = np.asarray(values, dtype=float) + return { + "samples": len(values), + "median_us": float(np.median(samples)), + "p95_us": float(np.percentile(samples, 95)), + "p99_us": float(np.percentile(samples, 99)), + "max_us": float(np.max(samples)), + } + + +def _payload(sequence: int, size: int, seed: int) -> bytes: + prefix = struct.pack("!QQ", seed, sequence) + digest = hashlib.sha256(prefix).digest() + return (prefix + digest * ((size + 31) // 32))[:size] + + +def _serve_connection(connection: socket.socket, mode: str) -> dict[str, int]: + received = frames = 0 + with connection: + while True: + sequence, payload = recv_frame(connection) + if not payload: + break + received += len(payload) + frames += 1 + if mode == "latency": + connection.sendall(encode_frame(sequence, payload)) + acknowledgement = json.dumps({"bytes": received, "frames": frames}).encode() + connection.sendall(encode_frame(frames, acknowledgement)) + return {"bytes": received, "frames": frames} + + +def serve(*, host: str, port: int, mode: str, connections: int) -> dict[str, Any]: + if connections <= 0: + raise ValueError("connections must be positive") + with ( + socket.create_server((host, port), backlog=connections, reuse_port=False) as listener, + ThreadPoolExecutor(max_workers=connections) as executor, + ): + futures = [ + executor.submit(_serve_connection, listener.accept()[0], mode) + for _ in range(connections) + ] + results = [future.result() for future in futures] + return { + "role": "server", + "mode": mode, + "connections": connections, + "validated_bytes": sum(result["bytes"] for result in results), + "validated_frames": sum(result["frames"] for result in results), + } + + +def _bandwidth_connection( + host: str, + port: int, + barrier: threading.Barrier, + total_bytes: int, + block_size: int, + seed: int, +) -> tuple[int, float, float]: + completed = 0 + with socket.create_connection((host, port), timeout=30) as connection: + connection.settimeout(120) + barrier.wait() + started = time.perf_counter() + sequence = 0 + while completed < total_bytes: + size = min(block_size, total_bytes - completed) + connection.sendall(encode_frame(sequence, _payload(sequence, size, seed))) + completed += size + sequence += 1 + connection.sendall(encode_frame(sequence, b"")) + _, acknowledgement = recv_frame(connection) + completed_at = time.perf_counter() + confirmed = json.loads(acknowledgement) + if confirmed != {"bytes": completed, "frames": sequence}: + raise ValueError(f"server acknowledgement mismatch: {confirmed}") + return completed, started, completed_at + + +def bandwidth_client( + *, + host: str, + port: int, + connections: int, + bytes_per_connection: int, + block_size: int, + seed: int, +) -> dict[str, Any]: + if min(connections, bytes_per_connection, block_size) <= 0: + raise ValueError("bandwidth dimensions must be positive") + barrier = threading.Barrier(connections) + with ThreadPoolExecutor(max_workers=connections) as executor: + futures = [ + executor.submit( + _bandwidth_connection, + host, + port, + barrier, + bytes_per_connection, + block_size, + seed + index, + ) + for index in range(connections) + ] + results = [future.result() for future in futures] + summary = summarize_bandwidth( + completed_bytes=[result[0] for result in results], + started_at_s=[result[1] for result in results], + completed_at_s=[result[2] for result in results], + ) + return {"role": "client", "mode": "bandwidth", **summary} + + +def latency_client( + *, + host: str, + port: int, + payload_size: int, + warmup: int, + iterations: int, + seed: int, +) -> dict[str, Any]: + if payload_size <= 0 or warmup < 0 or iterations <= 0: + raise ValueError("latency dimensions are invalid") + values: list[float] = [] + with socket.create_connection((host, port), timeout=30) as connection: + connection.settimeout(30) + for sequence in range(warmup + iterations): + payload = _payload(sequence, payload_size, seed) + started = time.perf_counter_ns() + connection.sendall(encode_frame(sequence, payload)) + echoed_sequence, echoed_payload = recv_frame(connection) + completed = time.perf_counter_ns() + if echoed_sequence != sequence or echoed_payload != payload: + raise ValueError(f"echo mismatch at sequence {sequence}") + if sequence >= warmup: + values.append((completed - started) / 1_000) + connection.sendall(encode_frame(warmup + iterations, b"")) + recv_frame(connection) + return { + "role": "client", + "mode": "latency", + "payload_bytes": payload_size, + **summarize_latency_us(values), + } + + +def _write_result(result: dict[str, Any], output: Path | None) -> None: + encoded = json.dumps(result, ensure_ascii=False, sort_keys=True) + print(encoded) + if output is not None: + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(encoded + "\n", encoding="utf-8") + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Validated TCP bandwidth and RTT probe") + subparsers = parser.add_subparsers(required=True) + server = subparsers.add_parser("server") + server.add_argument("--host", required=True) + server.add_argument("--port", type=int, default=18516) + server.add_argument("--mode", choices=("bandwidth", "latency"), required=True) + server.add_argument("--connections", type=int, default=1) + server.add_argument("--output", type=Path) + + client = subparsers.add_parser("client") + client.add_argument("--host", required=True) + client.add_argument("--port", type=int, default=18516) + client.add_argument("--mode", choices=("bandwidth", "latency"), required=True) + client.add_argument("--connections", type=int, default=1) + client.add_argument("--bytes-per-connection", type=int, default=128 * 1024 * 1024) + client.add_argument("--block-size", type=int, default=1024 * 1024) + client.add_argument("--payload-size", type=int, default=64) + client.add_argument("--warmup", type=int, default=100) + client.add_argument("--iterations", type=int, default=10_000) + client.add_argument("--seed", type=int, default=20260731) + client.add_argument("--output", type=Path) + return parser + + +def main() -> int: + args = build_parser().parse_args() + if args.mode == "bandwidth" and hasattr(args, "bytes_per_connection"): + result = bandwidth_client( + host=args.host, + port=args.port, + connections=args.connections, + bytes_per_connection=args.bytes_per_connection, + block_size=args.block_size, + seed=args.seed, + ) + elif args.mode == "latency" and hasattr(args, "iterations"): + if args.connections != 1: + raise SystemExit("latency client requires --connections 1") + result = latency_client( + host=args.host, + port=args.port, + payload_size=args.payload_size, + warmup=args.warmup, + iterations=args.iterations, + seed=args.seed, + ) + else: + result = serve( + host=args.host, + port=args.port, + mode=args.mode, + connections=args.connections, + ) + _write_result(result, args.output) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/code/issue5/benchmarks/prefill_probe.py b/src/code/issue5/benchmarks/prefill_probe.py new file mode 100644 index 0000000..f2d94a3 --- /dev/null +++ b/src/code/issue5/benchmarks/prefill_probe.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from dataclasses import dataclass + +from kvbreak.evidence import remote_hit_is_proven + + +@dataclass(frozen=True) +class ProbeObservation: + cached_tokens: int + store_get_bytes: int + expected_kv_bytes: int + reader_use_count: int + local_cache_hit_tokens: int + workload_mode: str + expected_output_digest: str + actual_output_digest: str + eviction_ring_size: int = 0 + local_capacity_prefixes: int = 0 + + +def classify_probe(observation: ProbeObservation) -> str: + """Classify a cache probe without equating low TTFT with a remote hit.""" + if not observation.expected_output_digest or ( + observation.expected_output_digest != observation.actual_output_digest + ): + return "output_mismatch" + proven = remote_hit_is_proven( + cached_tokens=observation.cached_tokens, + store_get_bytes=observation.store_get_bytes, + expected_kv_bytes=observation.expected_kv_bytes, + reader_use_count=observation.reader_use_count, + local_cache_hit_tokens=observation.local_cache_hit_tokens, + workload_mode=observation.workload_mode, + eviction_ring_size=observation.eviction_ring_size, + local_capacity_prefixes=observation.local_capacity_prefixes, + ) + return "success" if proven else "unproven_remote_hit" diff --git a/src/code/issue5/benchmarks/run_cell.py b/src/code/issue5/benchmarks/run_cell.py new file mode 100644 index 0000000..64d82a2 --- /dev/null +++ b/src/code/issue5/benchmarks/run_cell.py @@ -0,0 +1,214 @@ +from __future__ import annotations + +import argparse +import asyncio +import hashlib +import json +import time +import uuid +from dataclasses import asdict, dataclass +from pathlib import Path +from typing import Any + +import httpx + +from benchmarks.loadgen import arrival_schedule +from benchmarks.workload import build_request_plan, build_token_payload +from kvbreak.model import kv_cache_bytes + + +@dataclass(frozen=True) +class RawRequestRecord: + run_id: str + request_id: str + phase: str + protocol: str + sequence_budget_tokens: int + context_tokens: int + max_output_tokens: int + target_hit_rate: float + actual_hit_rate: float + cached_tokens: int + kv_bytes: int + scheduled_at_ns: int + sent_at_ns: int + first_token_at_ns: int + completed_at_ns: int + ttft_ms: float + status: str + evidence_level: str + output_digest: str + store_get_bytes: int = 0 + local_cache_hit_tokens: int = 0 + remote_hit_evidence: str = "unproven_remote_hit" + error: str = "" + + +def _parse_data_line(line: str) -> dict[str, Any] | None: + if not line.startswith("data: ") or line == "data: [DONE]": + return None + return json.loads(line[6:]) + + +async def _request( + *, + client: httpx.AsyncClient, + endpoint: str, + model: str, + prompt: tuple[int, ...], + max_output_tokens: int, + timeout_s: float, +) -> tuple[int, int, int, str, str]: + sent = time.monotonic_ns() + first = 0 + completed = sent + fragments: list[str] = [] + status = "success" + error = "" + try: + async with client.stream( + "POST", + endpoint.rstrip("/") + "/v1/completions", + json={ + "model": model, + "prompt": list(prompt), + "max_tokens": max_output_tokens, + "temperature": 0, + "stream": True, + }, + timeout=timeout_s, + ) as response: + response.raise_for_status() + async for line in response.aiter_lines(): + event = _parse_data_line(line) + if event is None: + continue + text = str(event.get("choices", [{}])[0].get("text", "")) + if first == 0: + first = time.monotonic_ns() + fragments.append(text) + completed = time.monotonic_ns() + if first == 0: + status = "error" + error = "stream completed without a token event" + except httpx.TimeoutException as exc: + completed = time.monotonic_ns() + status = "timeout" + error = str(exc) + except (httpx.HTTPError, KeyError, TypeError, ValueError, json.JSONDecodeError) as exc: + completed = time.monotonic_ns() + status = "error" + error = str(exc) + digest = hashlib.sha256("".join(fragments).encode()).hexdigest() if fragments else "" + return sent, first, completed, status, error + (f"|digest={digest}" if digest else "") + + +async def run(args: argparse.Namespace) -> list[RawRequestRecord]: + plans = build_request_plan( + sequence_budget_tokens=args.sequence_budget, + max_output_tokens=args.max_output_tokens, + hit_rate=args.hit_rate, + count=args.count, + seed=args.seed, + ) + schedule = arrival_schedule( + offered_qps=args.offered_qps, + count=args.count, + start_s=time.monotonic(), + ) + run_id = args.run_id or str(uuid.uuid4()) + + async with httpx.AsyncClient() as client: + + async def execute(index: int) -> RawRequestRecord: + plan = plans[index] + payload = build_token_payload(plan, seed=args.seed, vocab_size=args.vocab_size) + prompt = ( + payload.writer_prompt_token_ids + if args.phase == "writer" + else payload.reader_prompt_token_ids + ) + wait_s = schedule[index] - time.monotonic() + if wait_s > 0: + await asyncio.sleep(wait_s) + scheduled_ns = int(schedule[index] * 1e9) + sent, first, completed, status, error_and_digest = await _request( + client=client, + endpoint=args.endpoint, + model=args.model, + prompt=prompt, + max_output_tokens=args.max_output_tokens, + timeout_s=args.timeout_s, + ) + error, _, digest = error_and_digest.partition("|digest=") + ttft_ms = (first - sent) / 1e6 if first else 0.0 + expected_kv_bytes = kv_cache_bytes( + cached_tokens=plan.cached_tokens, + layers=args.layers, + num_key_value_heads=args.num_key_value_heads, + head_dim=args.head_dim, + bytes_per_element=args.bytes_per_element, + ) + return RawRequestRecord( + run_id=run_id, + request_id=plan.prefix_id, + phase=args.phase, + protocol=args.protocol, + sequence_budget_tokens=plan.sequence_budget_tokens, + context_tokens=plan.context_tokens, + max_output_tokens=plan.max_output_tokens, + target_hit_rate=plan.target_hit_rate, + actual_hit_rate=plan.cached_tokens / plan.context_tokens, + cached_tokens=plan.cached_tokens, + kv_bytes=expected_kv_bytes, + scheduled_at_ns=scheduled_ns, + sent_at_ns=sent, + first_token_at_ns=first, + completed_at_ns=completed, + ttft_ms=ttft_ms, + status=status, + evidence_level="MEASURED", + output_digest=digest, + error=error, + ) + + return list(await asyncio.gather(*(execute(index) for index in range(args.count)))) + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Run one deterministic vLLM experiment cell") + parser.add_argument("--endpoint", required=True) + parser.add_argument("--model", required=True) + parser.add_argument("--phase", choices=("writer", "reader", "recompute"), required=True) + parser.add_argument("--protocol", choices=("recompute", "tcp", "rdma"), required=True) + parser.add_argument("--sequence-budget", type=int, required=True) + parser.add_argument("--hit-rate", type=float, required=True) + parser.add_argument("--count", type=int, default=1) + parser.add_argument("--max-output-tokens", type=int, default=1) + parser.add_argument("--offered-qps", type=float, default=1) + parser.add_argument("--timeout-s", type=float, default=300) + parser.add_argument("--seed", type=int, default=20260731) + parser.add_argument("--vocab-size", type=int, default=152064) + parser.add_argument("--layers", type=int, default=28) + parser.add_argument("--num-key-value-heads", type=int, default=4) + parser.add_argument("--head-dim", type=int, default=128) + parser.add_argument("--bytes-per-element", type=int, default=2) + parser.add_argument("--run-id") + parser.add_argument("--output", type=Path, required=True) + return parser + + +def main() -> int: + args = build_parser().parse_args() + records = asyncio.run(run(args)) + args.output.parent.mkdir(parents=True, exist_ok=True) + with args.output.open("a", encoding="utf-8") as output: + for record in records: + output.write(json.dumps(asdict(record), ensure_ascii=False, allow_nan=True) + "\n") + failed = sum(record.status != "success" for record in records) + print(json.dumps({"requests": len(records), "failed": failed, "output": str(args.output)})) + return 1 if failed else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/code/issue5/benchmarks/workload.py b/src/code/issue5/benchmarks/workload.py new file mode 100644 index 0000000..d576f36 --- /dev/null +++ b/src/code/issue5/benchmarks/workload.py @@ -0,0 +1,140 @@ +from __future__ import annotations + +import hashlib +import random +from dataclasses import dataclass + + +@dataclass(frozen=True) +class RequestPlan: + prefix_id: str + sequence_budget_tokens: int + context_tokens: int + max_output_tokens: int + cached_tokens: int + suffix_tokens: int + target_hit_rate: float + reader_use_count: int = 1 + + +@dataclass(frozen=True) +class TokenPayload: + prefix_id: str + writer_prompt_token_ids: tuple[int, ...] + reader_prompt_token_ids: tuple[int, ...] + prefix_sha256: str + reader_sha256: str + + +@dataclass(frozen=True) +class EvictionRingPlan: + local_capacity_prefixes: int + ring_size: int + required_store_bytes: int + store_safe_limit_bytes: int + + +def aligned_cached_tokens(context_tokens: int, hit_rate: float, block_size: int) -> int: + if context_tokens <= 0 or block_size <= 0 or not 0 <= hit_rate <= 1: + raise ValueError("invalid workload dimensions") + target = int(context_tokens * hit_rate) + return target - target % block_size + + +def build_request_plan( + *, + sequence_budget_tokens: int, + max_output_tokens: int, + hit_rate: float, + count: int, + seed: int, + block_size: int = 16, +) -> list[RequestPlan]: + if count <= 0 or max_output_tokens <= 0: + raise ValueError("count and max_output_tokens must be positive") + context_tokens = sequence_budget_tokens - max_output_tokens + if context_tokens <= 0: + raise ValueError("sequence budget must leave prompt tokens") + cached = aligned_cached_tokens(context_tokens, hit_rate, block_size) + identifiers = list(range(count)) + random.Random(seed).shuffle(identifiers) + return [ + RequestPlan( + prefix_id=( + f"budget{sequence_budget_tokens}-prompt{context_tokens}-" + f"hit{cached}-seed{seed}-item{index}" + ), + sequence_budget_tokens=sequence_budget_tokens, + context_tokens=context_tokens, + max_output_tokens=max_output_tokens, + cached_tokens=cached, + suffix_tokens=context_tokens - cached, + target_hit_rate=hit_rate, + ) + for index in identifiers + ] + + +def _stable_seed(seed: int, namespace: str) -> int: + return int.from_bytes(hashlib.sha256(f"{seed}:{namespace}".encode()).digest()[:8], "big") + + +def _token_ids(*, count: int, seed: int, token_id_min: int, vocab_size: int) -> tuple[int, ...]: + if count < 0 or token_id_min < 0 or vocab_size <= token_id_min: + raise ValueError("invalid token payload dimensions") + rng = random.Random(seed) + return tuple(rng.randrange(token_id_min, vocab_size) for _ in range(count)) + + +def _digest(token_ids: tuple[int, ...]) -> str: + return hashlib.sha256(",".join(map(str, token_ids)).encode()).hexdigest() + + +def build_token_payload( + plan: RequestPlan, *, seed: int, vocab_size: int, token_id_min: int = 1000 +) -> TokenPayload: + prefix = _token_ids( + count=plan.cached_tokens, + seed=_stable_seed(seed, f"{plan.prefix_id}:prefix"), + token_id_min=token_id_min, + vocab_size=vocab_size, + ) + suffix = _token_ids( + count=plan.suffix_tokens, + seed=_stable_seed(seed, f"{plan.prefix_id}:suffix"), + token_id_min=token_id_min, + vocab_size=vocab_size, + ) + reader = prefix + suffix + return TokenPayload(plan.prefix_id, prefix, reader, _digest(prefix), _digest(reader)) + + +def plan_eviction_ring( + *, + local_capacity_tokens: int, + cached_tokens_per_prefix: int, + kv_bytes_per_prefix: int, + store_capacity_bytes: int, + store_safe_fraction: float = 0.8, +) -> EvictionRingPlan: + if ( + min( + local_capacity_tokens, + cached_tokens_per_prefix, + kv_bytes_per_prefix, + store_capacity_bytes, + ) + <= 0 + ): + raise ValueError("eviction dimensions must be positive") + if not 0 < store_safe_fraction <= 1: + raise ValueError("store_safe_fraction must be in (0, 1]") + local_prefixes = local_capacity_tokens // cached_tokens_per_prefix + if local_prefixes < 1: + raise ValueError("Reader cannot hold one target prefix") + ring_size = local_prefixes + 1 + required = ring_size * kv_bytes_per_prefix + safe_limit = int(store_capacity_bytes * store_safe_fraction) + if required > safe_limit: + raise ValueError("eviction ring exceeds Store safe capacity") + return EvictionRingPlan(local_prefixes, ring_size, required, safe_limit) diff --git a/src/code/issue5/configs/experiment.yaml b/src/code/issue5/configs/experiment.yaml new file mode 100644 index 0000000..8d71013 --- /dev/null +++ b/src/code/issue5/configs/experiment.yaml @@ -0,0 +1,12 @@ +sequence_budgets: [8192, 32768, 131072] +target_hit_rates: [0.0, 0.3, 0.5, 0.7, 0.9] +max_output_tokens: 1 +repetitions: 5 +warmup_requests: 3 +request_timeout_s: 300 +ttft_slo_ms: 2000 +max_error_rate: 0.01 +open_loop: + warmup_s: 30 + measurement_s: 120 + offered_qpm: [1, 2, 4, 8, 16, 32, 64] diff --git a/src/code/issue5/configs/model.yaml b/src/code/issue5/configs/model.yaml new file mode 100644 index 0000000..100e698 --- /dev/null +++ b/src/code/issue5/configs/model.yaml @@ -0,0 +1,13 @@ +model_id: Qwen/Qwen2.5-7B-Instruct +# Short form of the verified upstream commit; resolve and record the full SHA in each run manifest. +revision: a09a354 +tokenizer_revision: a09a354 +served_model_name: issue5-qwen2.5-7b +tensor_parallel_size: 2 +max_model_len: 131072 +dtype: bfloat16 +seed: 20260731 +rope_scaling: + rope_type: yarn + factor: 4.0 + original_max_position_embeddings: 32768 diff --git a/src/code/issue5/configs/mooncake-store-rdma.json b/src/code/issue5/configs/mooncake-store-rdma.json new file mode 100644 index 0000000..7500329 --- /dev/null +++ b/src/code/issue5/configs/mooncake-store-rdma.json @@ -0,0 +1,10 @@ +{ + "mode": "standalone-store", + "metadata_server": "http://STORE_HOST:8080/metadata", + "master_server_address": "STORE_HOST:50051", + "global_segment_size": 0, + "local_buffer_size": "8GB", + "protocol": "rdma", + "device_name": "mlx5_0", + "enable_offload": false +} diff --git a/src/code/issue5/configs/mooncake-store-tcp.json b/src/code/issue5/configs/mooncake-store-tcp.json new file mode 100644 index 0000000..21bc309 --- /dev/null +++ b/src/code/issue5/configs/mooncake-store-tcp.json @@ -0,0 +1,10 @@ +{ + "mode": "standalone-store", + "metadata_server": "http://STORE_HOST:8080/metadata", + "master_server_address": "STORE_HOST:50051", + "global_segment_size": 0, + "local_buffer_size": "8GB", + "protocol": "tcp", + "device_name": "", + "enable_offload": false +} diff --git a/src/code/issue5/configs/rdma.env.example b/src/code/issue5/configs/rdma.env.example new file mode 100644 index 0000000..2663799 --- /dev/null +++ b/src/code/issue5/configs/rdma.env.example @@ -0,0 +1,12 @@ +MOONCAKE_PROTOCOL=rdma +MOONCAKE_DEVICE=mlx5_0 +MOONCAKE_MASTER=STORE_ROCE_IP:50051 +MOONCAKE_TE_META_DATA_SERVER=http://STORE_ROCE_IP:8080/metadata +MOONCAKE_LOCAL_HOSTNAME=STORE_ROCE_IP +MOONCAKE_GLOBAL_SEGMENT_SIZE=256GB +MOONCAKE_LOCAL_BUFFER_SIZE=8GB +MOONCAKE_STORE_OWNER=STORE_ROCE_IP:50052 +# Mooncake 0.3.12 actual default is the legacy peer-memory path. Never inherit it. +# Choose dmabuf only when the selected GPU reports CUDA DMA-BUF support; otherwise +# choose peermem after an administrator loads nvidia-peermem (or nv_peer_mem). +ISSUE5_RDMA_GPU_REGISTRATION=dmabuf diff --git a/src/code/issue5/configs/tcp.env.example b/src/code/issue5/configs/tcp.env.example new file mode 100644 index 0000000..c9cc982 --- /dev/null +++ b/src/code/issue5/configs/tcp.env.example @@ -0,0 +1,8 @@ +MOONCAKE_PROTOCOL=tcp +MOONCAKE_DEVICE= +MOONCAKE_MASTER=STORE_ROCE_IP:50051 +MOONCAKE_TE_META_DATA_SERVER=http://STORE_ROCE_IP:8080/metadata +MOONCAKE_LOCAL_HOSTNAME=STORE_ROCE_IP +MOONCAKE_GLOBAL_SEGMENT_SIZE=256GB +MOONCAKE_LOCAL_BUFFER_SIZE=8GB +MOONCAKE_STORE_OWNER=STORE_ROCE_IP:50052 diff --git a/src/code/issue5/kvbreak/__init__.py b/src/code/issue5/kvbreak/__init__.py new file mode 100644 index 0000000..233cb52 --- /dev/null +++ b/src/code/issue5/kvbreak/__init__.py @@ -0,0 +1,3 @@ +"""KV-cache break-even bandwidth experiment utilities.""" + +__version__ = "0.1.0" diff --git a/src/code/issue5/kvbreak/analysis.py b/src/code/issue5/kvbreak/analysis.py new file mode 100644 index 0000000..78fc146 --- /dev/null +++ b/src/code/issue5/kvbreak/analysis.py @@ -0,0 +1,102 @@ +from __future__ import annotations + +import csv +import json +import math +from dataclasses import asdict, dataclass +from pathlib import Path +from statistics import median +from typing import Any + + +@dataclass(frozen=True) +class AnalysisCell: + protocol: str + sequence_budget_tokens: int + target_hit_rate: float + successful_requests: int + total_requests: int + error_rate: float + median_ttft_ms: float + actual_qpm: float + source_run_ids: tuple[str, ...] + + +@dataclass(frozen=True) +class AnalysisResult: + cells: tuple[AnalysisCell, ...] + + +def _cell_key(record: dict[str, Any]) -> tuple[str, int, float]: + return ( + str(record["protocol"]), + int(record["sequence_budget_tokens"]), + float(record["target_hit_rate"]), + ) + + +def analyze_requests(path: Path, *, measurement_s: float) -> AnalysisResult: + if measurement_s <= 0: + raise ValueError("measurement_s must be positive") + groups: dict[tuple[str, int, float], list[dict[str, Any]]] = {} + with path.open(encoding="utf-8") as source: + for line_number, line in enumerate(source, start=1): + if not line.strip(): + continue + try: + record = json.loads(line) + groups.setdefault(_cell_key(record), []).append(record) + except (json.JSONDecodeError, KeyError, TypeError, ValueError) as exc: + raise ValueError(f"invalid record at {path}:{line_number}: {exc}") from exc + + cells: list[AnalysisCell] = [] + for key in sorted(groups): + records = groups[key] + success = [record for record in records if record.get("status") == "success"] + ttfts = [float(record["ttft_ms"]) for record in success] + cells.append( + AnalysisCell( + protocol=key[0], + sequence_budget_tokens=key[1], + target_hit_rate=key[2], + successful_requests=len(success), + total_requests=len(records), + error_rate=(len(records) - len(success)) / len(records), + median_ttft_ms=median(ttfts) if ttfts else math.inf, + actual_qpm=len(success) * 60 / measurement_s, + source_run_ids=tuple(sorted(str(record["run_id"]) for record in records)), + ) + ) + return AnalysisResult(cells=tuple(cells)) + + +def write_analysis(result: AnalysisResult, output_dir: Path) -> tuple[Path, ...]: + output_dir.mkdir(parents=True, exist_ok=True) + csv_path = output_dir / "summary.csv" + fields = [ + "protocol", + "sequence_budget_tokens", + "target_hit_rate", + "successful_requests", + "total_requests", + "error_rate", + "median_ttft_ms", + "actual_qpm", + "source_run_ids", + ] + with csv_path.open("w", encoding="utf-8", newline="") as output: + writer = csv.DictWriter(output, fieldnames=fields) + writer.writeheader() + for cell in result.cells: + row = asdict(cell) + row["source_run_ids"] = ";".join(cell.source_run_ids) + writer.writerow(row) + + json_path = output_dir / "summary.json" + json_path.write_text( + json.dumps( + {"cells": [asdict(cell) for cell in result.cells]}, indent=2, ensure_ascii=False + ), + encoding="utf-8", + ) + return csv_path, json_path diff --git a/src/code/issue5/kvbreak/cli.py b/src/code/issue5/kvbreak/cli.py new file mode 100644 index 0000000..b0310e1 --- /dev/null +++ b/src/code/issue5/kvbreak/cli.py @@ -0,0 +1,194 @@ +from __future__ import annotations + +import argparse +import json +import os +import sys +from dataclasses import asdict +from pathlib import Path + +from kvbreak.analysis import analyze_requests, write_analysis +from kvbreak.configuration import render_mooncake_config +from kvbreak.gpu_registration import ( + inspect_registration_capabilities, + select_registration_path, +) +from kvbreak.model import serial_break_even +from kvbreak.provenance import ( + build_manifest, + sanitize_environment, + verify_manifest, + write_json_atomic, +) +from kvbreak.remote_verification import verify_remote_hit + + +def _model(args: argparse.Namespace) -> int: + result = serial_break_even( + full_prefill_s=args.full_prefill_ms / 1_000, + suffix_prefill_s=args.suffix_prefill_ms / 1_000, + hit_rate=args.hit_rate, + kv_bytes=args.kv_bytes, + metadata_s=args.metadata_ms / 1_000, + transfer_startup_s=args.startup_ms / 1_000, + restore_s=args.restore_ms / 1_000, + ) + payload = asdict(result) + bandwidth = result.bandwidth_bytes_per_s + payload["bandwidth_gb_per_s"] = None if bandwidth is None else bandwidth / 1e9 + print(json.dumps(payload, indent=2, allow_nan=True)) + return 0 + + +def _analyze(args: argparse.Namespace) -> int: + result = analyze_requests(args.input, measurement_s=args.measurement_s) + for path in write_analysis(result, args.output_dir): + print(path) + return 0 + + +def _verify(args: argparse.Namespace) -> int: + failed = False + for manifest in args.manifests: + errors = verify_manifest(manifest) + if errors: + failed = True + print(f"{manifest}: {','.join(errors)}", file=sys.stderr) + else: + print(f"{manifest}: ok") + return 1 if failed else 0 + + +def _render_config(args: argparse.Namespace) -> int: + config = render_mooncake_config( + args.template, + args.output, + args.store_host, + args.requester_host, + master_port=args.master_port, + owner_port=args.owner_port, + metadata_port=args.metadata_port, + ) + print(json.dumps(config, indent=2)) + return 0 + + +def _create_manifest(args: argparse.Namespace) -> int: + metadata = {"commit": args.commit, "node": args.node} + manifest = build_manifest(args.run_dir, metadata=metadata) + print(json.dumps(manifest, indent=2)) + return 0 + + +def _verify_remote_hit(args: argparse.Namespace) -> int: + verdict = verify_remote_hit( + baseline_path=args.baseline, + reader_path=args.reader, + metrics_path=args.metrics, + model_name=args.model_name, + ) + payload = asdict(verdict) + write_json_atomic(args.output, payload) + print(json.dumps(payload, indent=2)) + return 0 if verdict.proven else 1 + + +def _validate_gpu_registration(args: argparse.Namespace) -> int: + indices = tuple(int(value) for value in args.gpu_indices.split(",")) + capabilities = inspect_registration_capabilities(indices) + try: + mooncake_value = select_registration_path(args.mode, capabilities) + except ValueError as error: + print(f"RDMA GPU registration preflight failed: {error}", file=sys.stderr) + print(json.dumps(capabilities.as_dict(), indent=2), file=sys.stderr) + return 2 + print(mooncake_value) + return 0 + + +def _snapshot_environment(args: argparse.Namespace) -> int: + payload = sanitize_environment(os.environ) + write_json_atomic(args.output, payload) + print(json.dumps(payload, indent=2)) + return 0 + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(prog="kvbreak") + subparsers = parser.add_subparsers(required=True) + + model = subparsers.add_parser("model", help="calculate the serial break-even bandwidth") + model.add_argument("--full-prefill-ms", type=float, required=True) + model.add_argument("--suffix-prefill-ms", type=float, required=True) + model.add_argument("--hit-rate", type=float, required=True) + model.add_argument("--kv-bytes", type=int, required=True) + model.add_argument("--metadata-ms", type=float, default=0) + model.add_argument("--startup-ms", type=float, default=0) + model.add_argument("--restore-ms", type=float, default=0) + model.set_defaults(handler=_model) + + analyze = subparsers.add_parser( + "analyze", help="aggregate request JSONL without hiding failures" + ) + analyze.add_argument("--input", type=Path, required=True) + analyze.add_argument("--output-dir", type=Path, required=True) + analyze.add_argument("--measurement-s", type=float, required=True) + analyze.set_defaults(handler=_analyze) + + verify = subparsers.add_parser("verify-manifests", help="verify run artifact hashes") + verify.add_argument("manifests", nargs="+", type=Path) + verify.set_defaults(handler=_verify) + + render = subparsers.add_parser( + "render-config", help="resolve a Mooncake transport template for a two-host run" + ) + render.add_argument("--template", type=Path, required=True) + render.add_argument("--output", type=Path, required=True) + render.add_argument("--store-host", required=True) + render.add_argument("--requester-host", required=True) + render.add_argument("--master-port", type=int, default=50051) + render.add_argument("--owner-port", type=int, default=50052) + render.add_argument("--metadata-port", type=int, default=8080) + render.set_defaults(handler=_render_config) + + create = subparsers.add_parser("create-manifest", help="hash all artifacts in a run") + create.add_argument("--run-dir", type=Path, required=True) + create.add_argument("--commit", required=True) + create.add_argument("--node", required=True) + create.set_defaults(handler=_create_manifest) + + remote = subparsers.add_parser( + "verify-remote-hit", + help="cross-check request digests and Mooncake GET metrics", + ) + remote.add_argument("--baseline", type=Path, required=True) + remote.add_argument("--reader", type=Path, required=True) + remote.add_argument("--metrics", type=Path, required=True) + remote.add_argument("--model-name", required=True) + remote.add_argument("--output", type=Path, required=True) + remote.set_defaults(handler=_verify_remote_hit) + + registration = subparsers.add_parser( + "validate-gpu-registration", + help="validate an explicit Mooncake GPU RDMA registration path", + ) + registration.add_argument("--mode", required=True, choices=("dmabuf", "peermem")) + registration.add_argument("--gpu-indices", required=True) + registration.set_defaults(handler=_validate_gpu_registration) + + snapshot = subparsers.add_parser( + "snapshot-environment", + help="write a secret-filtered runtime environment snapshot", + ) + snapshot.add_argument("--output", type=Path, required=True) + snapshot.set_defaults(handler=_snapshot_environment) + return parser + + +def main() -> int: + args = build_parser().parse_args() + return int(args.handler(args)) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/code/issue5/kvbreak/configuration.py b/src/code/issue5/kvbreak/configuration.py new file mode 100644 index 0000000..44c9730 --- /dev/null +++ b/src/code/issue5/kvbreak/configuration.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import ipaddress +import json +from pathlib import Path +from typing import Any + +from kvbreak.provenance import write_json_atomic + + +def _ip(value: str) -> str: + try: + return str(ipaddress.ip_address(value)) + except ValueError as exc: + raise ValueError(f"expected an IP address, got {value!r}") from exc + + +def render_mooncake_config( + template_path: Path, + output_path: Path, + store_host: str, + requester_host: str, + *, + master_port: int = 50051, + owner_port: int = 50052, + metadata_port: int = 8080, +) -> dict[str, Any]: + """Resolve topology fields while retaining transport-controlled template fields.""" + store = _ip(store_host) + requester = _ip(requester_host) + if store == requester: + raise ValueError("store and requester hosts must be distinct") + if any(not 1 <= port <= 65535 for port in (master_port, owner_port, metadata_port)): + raise ValueError("ports must be in [1, 65535]") + + config = json.loads(template_path.read_text(encoding="utf-8")) + if config.get("mode") != "standalone-store": + raise ValueError("template mode must be standalone-store") + if config.get("protocol") not in {"tcp", "rdma"}: + raise ValueError("template protocol must be tcp or rdma") + config.update( + { + "metadata_server": f"http://{store}:{metadata_port}/metadata", + "master_server_address": f"{store}:{master_port}", + "local_hostname": requester, + "preferred_segment": f"{store}:{owner_port}", + } + ) + write_json_atomic(output_path, config) + return config diff --git a/src/code/issue5/kvbreak/evidence.py b/src/code/issue5/kvbreak/evidence.py new file mode 100644 index 0000000..0a069c9 --- /dev/null +++ b/src/code/issue5/kvbreak/evidence.py @@ -0,0 +1,68 @@ +from __future__ import annotations + +from dataclasses import dataclass + + +@dataclass(frozen=True) +class DataPathEvidence: + configured_protocol: str + rdma_transport_loaded: bool + fallback_warning: bool + rdma_counter_delta_bytes: int + tcp_payload_delta_bytes: int + expected_payload_bytes: int + cuda_memory_registered: bool + host_staging_observed: bool + + def __post_init__(self) -> None: + if self.configured_protocol not in {"tcp", "rdma"}: + raise ValueError("configured_protocol must be tcp or rdma") + if self.expected_payload_bytes <= 0: + raise ValueError("expected_payload_bytes must be positive") + if self.rdma_counter_delta_bytes < 0 or self.tcp_payload_delta_bytes < 0: + raise ValueError("counter deltas must be non-negative") + + +def remote_hit_is_proven( + *, + cached_tokens: int, + store_get_bytes: int, + expected_kv_bytes: int, + reader_use_count: int, + local_cache_hit_tokens: int, + workload_mode: str, + eviction_ring_size: int = 0, + local_capacity_prefixes: int = 0, +) -> bool: + common = ( + cached_tokens > 0 + and expected_kv_bytes > 0 + and store_get_bytes >= int(expected_kv_bytes * 0.8) + and local_cache_hit_tokens == 0 + ) + if workload_mode == "single_use": + return common and reader_use_count == 1 + if workload_mode == "verified_eviction_ring": + return ( + common and reader_use_count >= 1 and eviction_ring_size > local_capacity_prefixes >= 1 + ) + return False + + +def classify_data_path(evidence: DataPathEvidence) -> str: + if evidence.configured_protocol == "tcp": + return "TCP" + payload_matches = evidence.rdma_counter_delta_bytes >= int( + evidence.expected_payload_bytes * 0.8 + ) + tcp_is_small = evidence.tcp_payload_delta_bytes <= int(evidence.expected_payload_bytes * 0.05) + if ( + not evidence.rdma_transport_loaded + or evidence.fallback_warning + or not payload_matches + or not tcp_is_small + ): + return "UNPROVEN_RDMA" + if evidence.cuda_memory_registered and not evidence.host_staging_observed: + return "GPUDIRECT_RDMA" + return "RDMA_HOST_STAGING" diff --git a/src/code/issue5/kvbreak/gpu_registration.py b/src/code/issue5/kvbreak/gpu_registration.py new file mode 100644 index 0000000..f4a8aae --- /dev/null +++ b/src/code/issue5/kvbreak/gpu_registration.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +import ctypes +from collections.abc import Sequence +from dataclasses import asdict, dataclass +from pathlib import Path + +CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_SUPPORTED = 116 +CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED = 124 + + +@dataclass(frozen=True) +class GpuDeviceCapabilities: + index: int + gpu_direct_rdma_supported: bool + dma_buf_supported: bool + + +@dataclass(frozen=True) +class GpuRegistrationCapabilities: + dma_buf_supported: bool + gpu_direct_rdma_supported: bool + nvidia_peermem_loaded: bool + nv_peer_mem_loaded: bool + devices: tuple[GpuDeviceCapabilities, ...] = () + + def as_dict(self) -> dict[str, object]: + payload = asdict(self) + payload["peermem_module_loaded"] = self.nvidia_peermem_loaded or self.nv_peer_mem_loaded + return payload + + +def select_registration_path(mode: str, capabilities: GpuRegistrationCapabilities) -> str: + """Map an explicit project mode to Mooncake 0.3.12's legacy boolean switch.""" + if mode not in {"dmabuf", "peermem"}: + raise ValueError("RDMA GPU registration mode must be dmabuf or peermem") + if not capabilities.gpu_direct_rdma_supported: + raise ValueError("one or more selected GPUs do not report GPUDirect RDMA support") + if mode == "dmabuf": + if not capabilities.dma_buf_supported: + raise ValueError("one or more selected GPUs do not report DMA-BUF support") + return "0" + if not (capabilities.nvidia_peermem_loaded or capabilities.nv_peer_mem_loaded): + raise ValueError( + "peermem mode requires a loaded nvidia-peermem or nv_peer_mem kernel module" + ) + return "1" + + +def _check_cuda(result: int, operation: str) -> None: + if result != 0: + raise RuntimeError(f"CUDA driver call {operation} failed with code {result}") + + +def inspect_registration_capabilities( + gpu_indices: Sequence[int] | None = None, +) -> GpuRegistrationCapabilities: + """Inspect the CUDA driver attributes Mooncake checks before GPU RDMA registration.""" + cuda = ctypes.CDLL("libcuda.so.1") + _check_cuda(cuda.cuInit(0), "cuInit") + + device_count = ctypes.c_int() + _check_cuda(cuda.cuDeviceGetCount(ctypes.byref(device_count)), "cuDeviceGetCount") + indices = tuple(range(device_count.value)) if gpu_indices is None else tuple(gpu_indices) + if not indices: + raise ValueError("at least one GPU index is required") + + devices: list[GpuDeviceCapabilities] = [] + for index in indices: + device = ctypes.c_int() + _check_cuda(cuda.cuDeviceGet(ctypes.byref(device), index), f"cuDeviceGet({index})") + values: dict[int, bool] = {} + for attribute in ( + CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_SUPPORTED, + CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED, + ): + value = ctypes.c_int() + _check_cuda( + cuda.cuDeviceGetAttribute(ctypes.byref(value), attribute, device), + f"cuDeviceGetAttribute({attribute}, {index})", + ) + values[attribute] = bool(value.value) + devices.append( + GpuDeviceCapabilities( + index=index, + gpu_direct_rdma_supported=values[CU_DEVICE_ATTRIBUTE_GPU_DIRECT_RDMA_SUPPORTED], + dma_buf_supported=values[CU_DEVICE_ATTRIBUTE_DMA_BUF_SUPPORTED], + ) + ) + + return GpuRegistrationCapabilities( + dma_buf_supported=all(device.dma_buf_supported for device in devices), + gpu_direct_rdma_supported=all(device.gpu_direct_rdma_supported for device in devices), + nvidia_peermem_loaded=Path("/sys/module/nvidia_peermem").is_dir(), + nv_peer_mem_loaded=Path("/sys/module/nv_peer_mem").is_dir(), + devices=tuple(devices), + ) diff --git a/src/code/issue5/kvbreak/model.py b/src/code/issue5/kvbreak/model.py new file mode 100644 index 0000000..0744c20 --- /dev/null +++ b/src/code/issue5/kvbreak/model.py @@ -0,0 +1,269 @@ +from __future__ import annotations + +import math +from dataclasses import dataclass + +import numpy as np + + +@dataclass(frozen=True) +class BreakEvenResult: + status: str + bandwidth_bytes_per_s: float | None + transfer_budget_s: float + + +@dataclass(frozen=True) +class PrefillCurve: + linear_s_per_token: float + quadratic_s_per_token2: float + + def predict(self, tokens: float) -> float: + if tokens < 0: + raise ValueError("tokens must be non-negative") + return self.linear_s_per_token * tokens + self.quadratic_s_per_token2 * tokens**2 + + +@dataclass(frozen=True) +class OverlapRatioFit: + status: str + overlap_ratio: float | None + raw_overlap_ratio: float | None + + +@dataclass(frozen=True) +class OverlapBreakEvenResult: + status: str + bandwidth_bytes_per_s: float + inputs: dict[str, float | int] + + +@dataclass(frozen=True) +class ResourceCost: + gpu_seconds_per_query: float + cpu_seconds_per_query: float + network_gb_per_query: float + + +def serial_break_even( + *, + full_prefill_s: float, + suffix_prefill_s: float, + hit_rate: float, + kv_bytes: int, + metadata_s: float, + transfer_startup_s: float, + restore_s: float, +) -> BreakEvenResult: + times = { + "full_prefill_s": full_prefill_s, + "suffix_prefill_s": suffix_prefill_s, + "metadata_s": metadata_s, + "transfer_startup_s": transfer_startup_s, + "restore_s": restore_s, + } + for name, value in times.items(): + if value < 0: + raise ValueError(f"{name} must be non-negative") + if not 0 <= hit_rate <= 1: + raise ValueError("hit_rate must be in [0, 1]") + if kv_bytes < 0: + raise ValueError("kv_bytes must be non-negative") + if hit_rate == 0: + return BreakEvenResult("no_hit", None, 0) + if kv_bytes == 0: + return BreakEvenResult("no_payload", 0, 0) + budget = full_prefill_s - suffix_prefill_s - metadata_s - transfer_startup_s - restore_s + if budget <= 0: + return BreakEvenResult("never_profitable", math.inf, budget) + return BreakEvenResult("finite", kv_bytes / budget, budget) + + +def is_profitable(actual_bandwidth: float, result: BreakEvenResult) -> bool: + if actual_bandwidth < 0: + raise ValueError("actual_bandwidth must be non-negative") + return ( + result.status == "finite" + and result.bandwidth_bytes_per_s is not None + and actual_bandwidth > result.bandwidth_bytes_per_s + ) + + +def transformer_prefill_flops( + *, + tokens: int, + layers: int, + hidden_size: int, + intermediate_size: int, + num_attention_heads: int, + num_key_value_heads: int, + head_dim: int, +) -> int: + values = ( + tokens, + layers, + hidden_size, + intermediate_size, + num_attention_heads, + num_key_value_heads, + head_dim, + ) + if any(value <= 0 for value in values): + raise ValueError("all transformer dimensions must be positive") + query_width = num_attention_heads * head_dim + kv_width = num_key_value_heads * head_dim + if query_width != hidden_size: + raise ValueError("attention head width must equal hidden_size") + qkv_projection = 2 * tokens * hidden_size * (query_width + 2 * kv_width) + output_projection = 2 * tokens * hidden_size**2 + swiglu_mlp = 6 * tokens * hidden_size * intermediate_size + attention = 4 * tokens**2 * num_attention_heads * head_dim + return layers * (qkv_projection + output_projection + swiglu_mlp + attention) + + +def prefill_seconds_from_flops(*, prefill_flops: float, effective_flops_per_s: float) -> float: + if prefill_flops < 0: + raise ValueError("prefill_flops must be non-negative") + if effective_flops_per_s <= 0: + raise ValueError("effective_flops_per_s must be positive") + return float(prefill_flops / effective_flops_per_s) + + +def kv_cache_bytes( + *, + cached_tokens: int, + layers: int, + num_key_value_heads: int, + head_dim: int, + bytes_per_element: int, +) -> int: + if cached_tokens < 0: + raise ValueError("cached_tokens must be non-negative") + if min(layers, num_key_value_heads, head_dim, bytes_per_element) <= 0: + raise ValueError("KV dimensions must be positive") + return 2 * layers * cached_tokens * num_key_value_heads * head_dim * bytes_per_element + + +def resource_cost( + *, + active_gpu_count: int, + successful_qps: float, + allocated_cpu_cores: int, + transferred_bytes: int, + successful_requests: int, +) -> ResourceCost: + if min(active_gpu_count, allocated_cpu_cores, transferred_bytes) < 0: + raise ValueError("resource counts must be non-negative") + if successful_qps <= 0 or successful_requests <= 0: + raise ValueError("successful throughput and requests must be positive") + return ResourceCost( + active_gpu_count / successful_qps, + allocated_cpu_cores / successful_qps, + transferred_bytes / successful_requests / 1e9, + ) + + +def fit_prefill_curve(tokens: np.ndarray, seconds: np.ndarray) -> PrefillCurve: + if tokens.ndim != 1 or seconds.ndim != 1 or len(tokens) != len(seconds): + raise ValueError("tokens and seconds must be same-length vectors") + if len(tokens) < 2 or np.any(tokens <= 0) or np.any(seconds < 0): + raise ValueError("fit requires at least two positive token points") + design = np.column_stack((tokens, tokens**2)) + coefficients, _, _, _ = np.linalg.lstsq(design, seconds, rcond=None) + return PrefillCurve(float(coefficients[0]), float(coefficients[1])) + + +def overlap_cache_time( + *, + actual_bandwidth: float, + suffix_prefill_s: float, + kv_bytes: int, + metadata_s: float, + transfer_startup_s: float, + restore_s: float, + overlap_ratio: float, +) -> float: + if actual_bandwidth <= 0: + raise ValueError("actual_bandwidth must be positive") + if not 0 <= overlap_ratio <= 1: + raise ValueError("overlap_ratio must be in [0, 1]") + if min(suffix_prefill_s, kv_bytes, metadata_s, transfer_startup_s, restore_s) < 0: + raise ValueError("overlap components must be non-negative") + transfer_s = transfer_startup_s + kv_bytes / actual_bandwidth + overlap_s = overlap_ratio * min(transfer_s, suffix_prefill_s + restore_s) + return metadata_s + suffix_prefill_s + restore_s + transfer_s - overlap_s + + +def fit_overlap_ratio( + *, + observed_cache_s: float, + actual_bandwidth: float, + suffix_prefill_s: float, + kv_bytes: int, + metadata_s: float, + transfer_startup_s: float, + restore_s: float, +) -> OverlapRatioFit: + if observed_cache_s < 0: + raise ValueError("observed_cache_s must be non-negative") + serial = overlap_cache_time( + actual_bandwidth=actual_bandwidth, + suffix_prefill_s=suffix_prefill_s, + kv_bytes=kv_bytes, + metadata_s=metadata_s, + transfer_startup_s=transfer_startup_s, + restore_s=restore_s, + overlap_ratio=0, + ) + transfer_s = transfer_startup_s + kv_bytes / actual_bandwidth + window = min(transfer_s, suffix_prefill_s + restore_s) + if window == 0: + return OverlapRatioFit("unidentifiable", None, None) + raw = (serial - observed_cache_s) / window + ratio = min(1.0, max(0.0, raw)) + status = "clamped_low" if raw < 0 else "clamped_high" if raw > 1 else "finite" + return OverlapRatioFit(status, ratio, raw) + + +def overlap_break_even( + *, + full_prefill_s: float, + suffix_prefill_s: float, + kv_bytes: int, + metadata_s: float, + transfer_startup_s: float, + restore_s: float, + overlap_ratio: float, + lower_bandwidth: float, + upper_bandwidth: float, +) -> OverlapBreakEvenResult: + if full_prefill_s < 0: + raise ValueError("full_prefill_s must be non-negative") + if lower_bandwidth <= 0 or upper_bandwidth <= lower_bandwidth: + raise ValueError("bandwidth bounds are invalid") + inputs: dict[str, float | int] = { + "suffix_prefill_s": suffix_prefill_s, + "kv_bytes": kv_bytes, + "metadata_s": metadata_s, + "transfer_startup_s": transfer_startup_s, + "restore_s": restore_s, + "overlap_ratio": overlap_ratio, + } + + def residual(bandwidth: float) -> float: + return overlap_cache_time(actual_bandwidth=bandwidth, **inputs) - full_prefill_s + + if residual(lower_bandwidth) < 0: + return OverlapBreakEvenResult("always_profitable_in_range", lower_bandwidth, inputs) + if residual(upper_bandwidth) >= 0: + return OverlapBreakEvenResult("never_profitable", math.inf, inputs) + lower, upper = lower_bandwidth, upper_bandwidth + for _ in range(200): + midpoint = (lower + upper) / 2 + if residual(midpoint) >= 0: + lower = midpoint + else: + upper = midpoint + if (upper - lower) / midpoint <= 1e-6: + break + return OverlapBreakEvenResult("finite", (lower + upper) / 2, inputs) diff --git a/src/code/issue5/kvbreak/provenance.py b/src/code/issue5/kvbreak/provenance.py new file mode 100644 index 0000000..c0173fd --- /dev/null +++ b/src/code/issue5/kvbreak/provenance.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import hashlib +import json +import os +from collections.abc import Mapping +from pathlib import Path + +ALLOWED_ENV = { + "CUDA_VISIBLE_DEVICES", + "MOONCAKE_PROTOCOL", + "MOONCAKE_DEVICE", + "MOONCAKE_MASTER", + "MOONCAKE_STORE_HOST", + "MOONCAKE_REQUESTER_HOST", + "MOONCAKE_TE_META_DATA_SERVER", + "ISSUE5_WRITER_GPUS", + "ISSUE5_READER_GPUS", + "ISSUE5_RECOMPUTE_GPUS", + "ISSUE5_MODEL_CONFIG", + "ISSUE5_SAFETENSORS_LOAD_STRATEGY", + "ISSUE5_ENFORCE_EAGER", + "ISSUE5_RDMA_GPU_REGISTRATION", + "MC_TE_METRIC", + "MC_STORE_MEMCPY", + "WITH_NVIDIA_PEERMEM", + "VLLM_MOONCAKE_STORE_TIER_LOG", + "HF_HOME", + "VLLM_LOGGING_LEVEL", + "PYTHONHASHSEED", +} + + +def file_sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def sanitize_environment(environment: Mapping[str, str]) -> dict[str, str]: + return {key: environment[key] for key in sorted(ALLOWED_ENV & environment.keys())} + + +def write_json_atomic(path: Path, payload: Mapping[str, object]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + temporary = path.with_suffix(path.suffix + f".{os.getpid()}.tmp") + temporary.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + temporary.replace(path) + + +def build_manifest( + run_dir: Path, + *, + manifest_path: Path | None = None, + metadata: Mapping[str, object] | None = None, +) -> dict[str, object]: + root = run_dir.resolve() + if not root.is_dir(): + raise ValueError(f"run directory does not exist: {run_dir}") + destination = (manifest_path or run_dir / "manifest.json").resolve() + if destination != root and root not in destination.parents: + raise ValueError("manifest path must be inside the run directory") + files: dict[str, str] = {} + for candidate in sorted(run_dir.rglob("*")): + if candidate.is_symlink(): + raise ValueError(f"manifest input contains symlink: {candidate}") + if not candidate.is_file() or candidate.resolve() == destination: + continue + relative = candidate.resolve().relative_to(root).as_posix() + files[relative] = file_sha256(candidate) + manifest: dict[str, object] = { + "metadata": dict(metadata or {}), + "files": files, + } + write_json_atomic(destination, manifest) + return manifest + + +def verify_manifest(manifest_path: Path) -> list[str]: + payload = json.loads(manifest_path.read_text(encoding="utf-8")) + root = manifest_path.parent.resolve() + errors: list[str] = [] + for relative, expected in payload.get("files", {}).items(): + candidate = (root / relative).resolve() + if candidate != root and root not in candidate.parents: + raise ValueError(f"manifest path escapes run directory: {relative}") + if not candidate.is_file(): + errors.append(f"missing:{relative}") + elif file_sha256(candidate) != expected: + errors.append(f"sha256:{relative}") + return errors diff --git a/src/code/issue5/kvbreak/remote_verification.py b/src/code/issue5/kvbreak/remote_verification.py new file mode 100644 index 0000000..bdc4b5b --- /dev/null +++ b/src/code/issue5/kvbreak/remote_verification.py @@ -0,0 +1,232 @@ +from __future__ import annotations + +import json +import math +import re +from dataclasses import dataclass +from pathlib import Path +from typing import TYPE_CHECKING, Any + +if TYPE_CHECKING: + from collections.abc import Mapping + + +_SAMPLE_RE = re.compile( + r"^(?P[A-Za-z_:][A-Za-z0-9_:]*)" + r"(?:\{(?P.*)\})?\s+" + r"(?P[+-]?(?:(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?|Inf|NaN))" + r"(?:\s+\d+)?$" +) +_LABEL_RE = re.compile( + r"\s*(?P[A-Za-z_][A-Za-z0-9_]*)\s*=\s*" + r'(?P"(?:\\.|[^"\\])*")\s*(?:,|$)' +) +_PASS_FRACTION = 0.8 + + +@dataclass(frozen=True) +class RemoteHitVerdict: + proven: bool + baseline_requests: int + reader_requests: int + successful_reader_requests: int + matching_output_digests: int + expected_kv_bytes: int + observed_store_get_bytes: int + observed_store_get_failed_keys: int + expected_cached_tokens: int + observed_external_hit_tokens: int + reasons: tuple[str, ...] + + +@dataclass(frozen=True) +class _MetricSample: + name: str + labels: dict[str, str] + value: float + + +def _read_jsonl(path: Path) -> list[dict[str, Any]]: + records: list[dict[str, Any]] = [] + with path.open(encoding="utf-8") as handle: + for line_number, line in enumerate(handle, start=1): + if not line.strip(): + continue + try: + record = json.loads(line) + except json.JSONDecodeError as exc: + raise ValueError(f"invalid JSONL at {path}:{line_number}: {exc.msg}") from exc + if not isinstance(record, dict): + raise TypeError(f"JSONL record at {path}:{line_number} is not an object") + records.append(record) + return records + + +def _index_requests(path: Path) -> dict[str, dict[str, Any]]: + indexed: dict[str, dict[str, Any]] = {} + for record in _read_jsonl(path): + request_id = record.get("request_id") + if not isinstance(request_id, str) or not request_id: + raise ValueError(f"request without a non-empty request_id in {path}") + if request_id in indexed: + raise ValueError(f"duplicate request_id {request_id!r} in {path}") + indexed[request_id] = record + return indexed + + +def _parse_labels(raw: str | None, *, path: Path, line_number: int) -> dict[str, str]: + if raw is None or not raw.strip(): + return {} + labels: dict[str, str] = {} + position = 0 + while position < len(raw): + match = _LABEL_RE.match(raw, position) + if match is None: + raise ValueError(f"invalid Prometheus labels at {path}:{line_number}") + name = match.group("name") + if name in labels: + raise ValueError(f"duplicate Prometheus label {name!r} at {path}:{line_number}") + labels[name] = str(json.loads(match.group("value"))) + position = match.end() + return labels + + +def _read_metrics(path: Path) -> list[_MetricSample]: + samples: list[_MetricSample] = [] + with path.open(encoding="utf-8") as handle: + for line_number, line in enumerate(handle, start=1): + stripped = line.strip() + if not stripped or stripped.startswith("#"): + continue + match = _SAMPLE_RE.match(stripped) + if match is None: + raise ValueError(f"invalid Prometheus sample at {path}:{line_number}") + value = float(match.group("value")) + if not math.isfinite(value) or value < 0: + raise ValueError(f"non-finite or negative metric at {path}:{line_number}") + samples.append( + _MetricSample( + name=match.group("name"), + labels=_parse_labels(match.group("labels"), path=path, line_number=line_number), + value=value, + ) + ) + return samples + + +def _metric_total( + samples: list[_MetricSample], metric_name: str, required_labels: dict[str, str] +) -> int: + total = sum( + sample.value + for sample in samples + if sample.name == metric_name + and all(sample.labels.get(key) == value for key, value in required_labels.items()) + ) + if not total.is_integer(): + raise ValueError(f"metric {metric_name} must have an integral total, got {total}") + return int(total) + + +def _non_negative_int(record: Mapping[str, Any], field: str, request_id: str) -> int: + value = record.get(field) + if isinstance(value, bool) or not isinstance(value, int) or value < 0: + raise ValueError(f"request {request_id!r} has invalid {field}: {value!r}") + return value + + +def verify_remote_hit( + *, + baseline_path: Path, + reader_path: Path, + metrics_path: Path, + model_name: str, +) -> RemoteHitVerdict: + """Cross-check request outputs and Mooncake GET counters. + + A verdict is proven only when request identities and output digests match, + every reader request succeeds, at least 80% of the expected KV bytes and + cached tokens appear in the matching Prometheus series, and no Store GET + keys fail. The 80% threshold matches the project's transport-evidence gate. + """ + + if not model_name: + raise ValueError("model_name must be non-empty") + baseline = _index_requests(baseline_path) + reader = _index_requests(reader_path) + samples = _read_metrics(metrics_path) + + request_ids = sorted(set(baseline) & set(reader)) + successful_reader_requests = sum( + record.get("status") == "success" for record in reader.values() + ) + matching_output_digests = sum( + isinstance(baseline[request_id].get("output_digest"), str) + and bool(baseline[request_id].get("output_digest")) + and baseline[request_id].get("output_digest") == reader[request_id].get("output_digest") + for request_id in request_ids + ) + expected_kv_bytes = sum( + _non_negative_int(record, "kv_bytes", request_id) for request_id, record in reader.items() + ) + expected_cached_tokens = sum( + _non_negative_int(record, "cached_tokens", request_id) + for request_id, record in reader.items() + ) + operation_labels = { + "model_name": model_name, + "operation": "load_get", + "status": "ok", + } + observed_store_get_bytes = _metric_total( + samples, "vllm:mooncake_store_operation_bytes_total", operation_labels + ) + observed_store_get_failed_keys = _metric_total( + samples, "vllm:mooncake_store_operation_failed_keys_total", operation_labels + ) + observed_external_hit_tokens = _metric_total( + samples, + "vllm:external_prefix_cache_hits_total", + {"model_name": model_name}, + ) + + reasons: list[str] = [] + if not baseline or not reader: + reasons.append("no_requests") + if set(baseline) != set(reader): + reasons.append("request_id_set_mismatch") + if any(record.get("status") != "success" for record in baseline.values()): + reasons.append("baseline_request_failed") + if successful_reader_requests != len(reader): + reasons.append("reader_request_failed") + if any( + not isinstance(record.get("output_digest"), str) or not record.get("output_digest") + for record in (*baseline.values(), *reader.values()) + ): + reasons.append("missing_output_digest") + if matching_output_digests != len(reader): + reasons.append("output_digest_mismatch") + if expected_kv_bytes <= 0: + reasons.append("expected_kv_bytes_nonpositive") + elif observed_store_get_bytes < math.ceil(expected_kv_bytes * _PASS_FRACTION): + reasons.append("store_get_bytes_below_threshold") + if observed_store_get_failed_keys != 0: + reasons.append("store_get_failed_keys_nonzero") + if expected_cached_tokens <= 0: + reasons.append("expected_cached_tokens_nonpositive") + elif observed_external_hit_tokens < math.ceil(expected_cached_tokens * _PASS_FRACTION): + reasons.append("external_hit_tokens_below_threshold") + + return RemoteHitVerdict( + proven=not reasons, + baseline_requests=len(baseline), + reader_requests=len(reader), + successful_reader_requests=successful_reader_requests, + matching_output_digests=matching_output_digests, + expected_kv_bytes=expected_kv_bytes, + observed_store_get_bytes=observed_store_get_bytes, + observed_store_get_failed_keys=observed_store_get_failed_keys, + expected_cached_tokens=expected_cached_tokens, + observed_external_hit_tokens=observed_external_hit_tokens, + reasons=tuple(reasons), + ) diff --git a/src/code/issue5/kvbreak/statistics.py b/src/code/issue5/kvbreak/statistics.py new file mode 100644 index 0000000..818520d --- /dev/null +++ b/src/code/issue5/kvbreak/statistics.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +from collections.abc import Sequence +from dataclasses import dataclass + +import numpy as np + + +@dataclass(frozen=True) +class SampleSummary: + count: int + mean: float + median: float + p95: float + p99: float + stddev: float + + +def _array(values: Sequence[float]) -> np.ndarray: + result = np.asarray(values, dtype=float) + if result.size == 0: + raise ValueError("values must be non-empty") + if not np.all(np.isfinite(result)): + raise ValueError("values must be finite") + return result + + +def summarize(values: Sequence[float]) -> SampleSummary: + array = _array(values) + return SampleSummary( + count=int(array.size), + mean=float(np.mean(array)), + median=float(np.median(array)), + p95=float(np.percentile(array, 95)), + p99=float(np.percentile(array, 99)), + stddev=float(np.std(array, ddof=1)) if array.size > 1 else 0, + ) + + +def bootstrap_ci( + values: Sequence[float], *, seed: int, iterations: int = 10_000, confidence: float = 0.95 +) -> tuple[float, float]: + array = _array(values) + if iterations <= 0 or not 0 < confidence < 1: + raise ValueError("invalid bootstrap parameters") + rng = np.random.default_rng(seed) + medians = np.empty(iterations) + for index in range(iterations): + medians[index] = np.median(rng.choice(array, size=array.size, replace=True)) + tail = (1 - confidence) / 2 + return float(np.quantile(medians, tail)), float(np.quantile(medians, 1 - tail)) diff --git a/src/code/issue5/kvbreak/types.py b/src/code/issue5/kvbreak/types.py new file mode 100644 index 0000000..7874075 --- /dev/null +++ b/src/code/issue5/kvbreak/types.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +from dataclasses import asdict, dataclass +from enum import Enum +from typing import Any + + +class RunStatus(str, Enum): + SUCCESS = "success" + TIMEOUT = "timeout" + ERROR = "error" + OOM = "oom" + CAPACITY_LIMITED = "capacity_limited" + + +class EvidenceLevel(str, Enum): + MEASURED = "MEASURED" + CALCULATED = "CALCULATED" + EXTRAPOLATED = "EXTRAPOLATED" + UPSTREAM = "UPSTREAM" + UNKNOWN = "UNKNOWN" + + +@dataclass(frozen=True) +class RunRecord: + run_id: str + request_id: str + protocol: str + sequence_budget_tokens: int + context_tokens: int + max_output_tokens: int + target_hit_rate: float + cached_tokens: int + kv_bytes: int + ttft_ms: float + status: RunStatus + evidence_level: EvidenceLevel + workload_mode: str = "single_use" + scheduled_at_ns: int = 0 + sent_at_ns: int = 0 + first_token_at_ns: int = 0 + completed_at_ns: int = 0 + lookup_ms: float | None = None + transfer_ms: float | None = None + restore_ms: float | None = None + prefill_ms: float | None = None + output_digest: str = "" + remote_hit_evidence: str = "" + rdma_counter_delta_bytes: int = 0 + tcp_counter_delta_bytes: int = 0 + + def __post_init__(self) -> None: + if not self.run_id or not self.request_id: + raise ValueError("run_id and request_id must be non-empty") + if self.protocol not in {"recompute", "tcp", "rdma"}: + raise ValueError("protocol must be recompute, tcp, or rdma") + if self.workload_mode not in { + "no_hit_control", + "single_use", + "verified_eviction_ring", + }: + raise ValueError("workload_mode is invalid") + if self.sequence_budget_tokens <= 0 or self.context_tokens <= 0: + raise ValueError("token dimensions must be positive") + if self.max_output_tokens <= 0: + raise ValueError("max_output_tokens must be positive") + if self.context_tokens + self.max_output_tokens != self.sequence_budget_tokens: + raise ValueError("prompt and output must equal sequence budget") + if not 0 <= self.target_hit_rate <= 1: + raise ValueError("target_hit_rate must be in [0, 1]") + if not 0 <= self.cached_tokens <= self.context_tokens: + raise ValueError("cached_tokens must be in [0, context_tokens]") + if self.kv_bytes < 0: + raise ValueError("kv_bytes must be non-negative") + if self.ttft_ms < 0: + raise ValueError("ttft_ms must be non-negative") + timestamps = ( + self.scheduled_at_ns, + self.sent_at_ns, + self.first_token_at_ns, + self.completed_at_ns, + ) + if any(value < 0 for value in timestamps): + raise ValueError("timestamps must be non-negative") + breakdown = (self.lookup_ms, self.transfer_ms, self.restore_ms, self.prefill_ms) + if any(value is not None and value < 0 for value in breakdown): + raise ValueError("latency breakdown must be non-negative") + if self.rdma_counter_delta_bytes < 0 or self.tcp_counter_delta_bytes < 0: + raise ValueError("counter deltas must be non-negative") + + @property + def actual_hit_rate(self) -> float: + return self.cached_tokens / self.context_tokens + + def to_dict(self) -> dict[str, Any]: + result = asdict(self) + result["status"] = self.status.value + result["evidence_level"] = self.evidence_level.value + result["actual_hit_rate"] = self.actual_hit_rate + return result diff --git a/src/code/issue5/orchestration/collect.sh b/src/code/issue5/orchestration/collect.sh new file mode 100755 index 0000000..7e71ab8 --- /dev/null +++ b/src/code/issue5/orchestration/collect.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +REMOTE_SOURCE="${1:?usage: collect.sh user@host:/absolute/project/path/results/}" +require_command rsync +mkdir -p "$PROJECT_ROOT/results" +rsync -avz "$REMOTE_SOURCE" "$PROJECT_ROOT/results/" diff --git a/src/code/issue5/orchestration/common.sh b/src/code/issue5/orchestration/common.sh new file mode 100755 index 0000000..975112c --- /dev/null +++ b/src/code/issue5/orchestration/common.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -euo pipefail + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +RUNTIME_DIR="$PROJECT_ROOT/results/runtime" +LOG_DIR="$PROJECT_ROOT/results/logs" +mkdir -p "$RUNTIME_DIR" "$LOG_DIR" + +require_command() { + command -v "$1" >/dev/null 2>&1 || { + echo "required command is missing: $1" >&2 + return 127 + } +} + +ensure_process_slot() { + local name="$1" pidfile="$RUNTIME_DIR/$1.pid" + [[ ! -e "$pidfile" ]] || { + echo "$name already has a pid file: $pidfile" >&2 + return 4 + } +} + +stop_pidfile() { + local pidfile="$1" expected_root="$2" pid cwd session_id + [[ -f "$pidfile" ]] || return 0 + pid="$(tr -d '[:space:]' < "$pidfile")" + [[ "$pid" =~ ^[0-9]+$ ]] || { + echo "invalid pid file: $pidfile" >&2 + return 2 + } + [[ -d "/proc/$pid" ]] || { + rm -f "$pidfile" + return 0 + } + cwd="$(readlink -f "/proc/$pid/cwd")" + [[ "$cwd" == "$expected_root"* ]] || { + echo "refusing to stop pid $pid outside $expected_root" >&2 + return 3 + } + session_id="$(ps -o sid= -p "$pid" | tr -d '[:space:]')" + [[ "$session_id" == "$pid" ]] || { + echo "refusing to stop pid $pid without a dedicated session" >&2 + return 4 + } + kill -TERM -- "-$pid" + for _ in {1..20}; do + pgrep -s "$pid" >/dev/null || break + sleep 0.5 + done + pgrep -s "$pid" >/dev/null && kill -KILL -- "-$pid" + rm -f "$pidfile" +} + +start_owned_process() { + local name="$1" + shift + local pidfile="$RUNTIME_DIR/$name.pid" logfile="$LOG_DIR/$name.log" + ensure_process_slot "$name" + require_command setsid + ( + cd "$PROJECT_ROOT" + exec setsid "$@" >>"$logfile" 2>&1 + ) & + local pid=$! + printf '%s\n' "$pid" > "$pidfile" + echo "$name started as pid $pid; log=$logfile" +} diff --git a/src/code/issue5/orchestration/deploy.sh b/src/code/issue5/orchestration/deploy.sh new file mode 100755 index 0000000..bf46029 --- /dev/null +++ b/src/code/issue5/orchestration/deploy.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +REMOTE_TARGET="${1:?usage: deploy.sh user@host:/absolute/project/path/}" +require_command rsync +rsync -avz \ + --exclude=.git --exclude=.venv --exclude=__pycache__ \ + --exclude=results/raw --exclude=results/derived --exclude=report/figures --exclude='*.log' \ + "$PROJECT_ROOT/" "$REMOTE_TARGET" diff --git a/src/code/issue5/orchestration/gates/128k_single.sh b/src/code/issue5/orchestration/gates/128k_single.sh new file mode 100755 index 0000000..19560d6 --- /dev/null +++ b/src/code/issue5/orchestration/gates/128k_single.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common_gate.sh" +run_cell 131072 0.3 1 diff --git a/src/code/issue5/orchestration/gates/32k_matrix.sh b/src/code/issue5/orchestration/gates/32k_matrix.sh new file mode 100755 index 0000000..2afffce --- /dev/null +++ b/src/code/issue5/orchestration/gates/32k_matrix.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common_gate.sh" +for hit_rate in 0.0 0.3 0.5 0.7 0.9; do + run_cell 32768 "$hit_rate" 5 +done diff --git a/src/code/issue5/orchestration/gates/8k_smoke.sh b/src/code/issue5/orchestration/gates/8k_smoke.sh new file mode 100755 index 0000000..f61256b --- /dev/null +++ b/src/code/issue5/orchestration/gates/8k_smoke.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common_gate.sh" +run_cell 8192 0.5 1 diff --git a/src/code/issue5/orchestration/gates/common_gate.sh b/src/code/issue5/orchestration/gates/common_gate.sh new file mode 100755 index 0000000..026de65 --- /dev/null +++ b/src/code/issue5/orchestration/gates/common_gate.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +MODEL_NAME="${MODEL_NAME:-issue5-qwen2.5-7b}" +READER_ENDPOINT="${READER_ENDPOINT:-http://127.0.0.1:8020}" +PROTOCOL="${PROTOCOL:-tcp}" +RAW_DIR="${RAW_DIR:-$PROJECT_ROOT/results/raw/requests}" +mkdir -p "$RAW_DIR" + +run_cell() { + local budget="$1" hit_rate="$2" count="$3" offered_qps="${4:-1}" + uv run python -m benchmarks.run_cell \ + --endpoint "$READER_ENDPOINT" --model "$MODEL_NAME" --phase reader --protocol "$PROTOCOL" \ + --sequence-budget "$budget" --hit-rate "$hit_rate" --count "$count" \ + --offered-qps "$offered_qps" --output "$RAW_DIR/${PROTOCOL}-${budget}-${hit_rate}.jsonl" +} diff --git a/src/code/issue5/orchestration/gates/open_loop_load.sh b/src/code/issue5/orchestration/gates/open_loop_load.sh new file mode 100755 index 0000000..5210343 --- /dev/null +++ b/src/code/issue5/orchestration/gates/open_loop_load.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common_gate.sh" +for offered_qpm in 1 2 4 8 16 32 64; do + offered_qps="$(python3 -c "print($offered_qpm / 60)")" + run_cell 32768 0.5 "$offered_qpm" "$offered_qps" +done diff --git a/src/code/issue5/orchestration/gates/rdma_transport.sh b/src/code/issue5/orchestration/gates/rdma_transport.sh new file mode 100755 index 0000000..73332fc --- /dev/null +++ b/src/code/issue5/orchestration/gates/rdma_transport.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -euo pipefail +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + +[[ "${PROTOCOL:-rdma}" == "rdma" ]] || { + echo "rdma_transport gate requires PROTOCOL=rdma" >&2 + exit 2 +} +"$PROJECT_ROOT/orchestration/network_bench.sh" diff --git a/src/code/issue5/orchestration/network_bench.sh b/src/code/issue5/orchestration/network_bench.sh new file mode 100755 index 0000000..890dd6e --- /dev/null +++ b/src/code/issue5/orchestration/network_bench.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +PEER_RDMA_IP="${PEER_RDMA_IP:?set PEER_RDMA_IP}" +GID_INDEX="${GID_INDEX:-3}" +OUTPUT_DIR="${OUTPUT_DIR:-$PROJECT_ROOT/results/raw/network}" +mkdir -p "$OUTPUT_DIR" +require_command ib_write_bw +require_command ib_write_lat + +for qp in 1 2 4 8; do + ib_write_bw "$PEER_RDMA_IP" -d mlx5_0 -x "$GID_INDEX" -q "$qp" --report_gbits \ + >"$OUTPUT_DIR/rdma-write-bw-qp${qp}.txt" 2>"$OUTPUT_DIR/rdma-write-bw-qp${qp}.stderr" +done +for bytes in 64 4096 1048576; do + ib_write_lat "$PEER_RDMA_IP" -d mlx5_0 -x "$GID_INDEX" -s "$bytes" -n 10000 \ + >"$OUTPUT_DIR/rdma-write-lat-${bytes}.txt" 2>"$OUTPUT_DIR/rdma-write-lat-${bytes}.stderr" +done diff --git a/src/code/issue5/orchestration/preflight.sh b/src/code/issue5/orchestration/preflight.sh new file mode 100755 index 0000000..c1b5805 --- /dev/null +++ b/src/code/issue5/orchestration/preflight.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +for command in python3 nvidia-smi ib_write_bw ib_write_lat ibv_devinfo; do + require_command "$command" +done + +unset CUDA_VISIBLE_DEVICES +PYTHONPATH="$PROJECT_ROOT${PYTHONPATH:+:$PYTHONPATH}" python3 - <<'PY' +import json +import platform +import shutil +import subprocess +import sys + +from kvbreak.gpu_registration import inspect_registration_capabilities + +if not ((3, 10) <= sys.version_info[:2] < (3, 13)): + raise SystemExit(f"Python 3.10-3.12 required, found {platform.python_version()}") + +def capture(*command: str) -> str: + return subprocess.run(command, check=True, text=True, stdout=subprocess.PIPE).stdout.strip() + +print(json.dumps({ + "python": platform.python_version(), + "disk_free_bytes": shutil.disk_usage(".").free, + "gpus": capture("nvidia-smi", "--query-gpu=name,driver_version,memory.total", "--format=csv,noheader"), + "rdma_device": capture("ibv_devinfo", "-d", "mlx5_0"), + "gpu_registration": inspect_registration_capabilities().as_dict(), +}, ensure_ascii=False)) +PY + +[[ -w "$PROJECT_ROOT" ]] || { + echo "project directory is not writable: $PROJECT_ROOT" >&2 + exit 5 +} diff --git a/src/code/issue5/orchestration/run_matrix.sh b/src/code/issue5/orchestration/run_matrix.sh new file mode 100755 index 0000000..da78d6f --- /dev/null +++ b/src/code/issue5/orchestration/run_matrix.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +run_gate() { + local name="$1" + echo "==> gate: $name" + "$PROJECT_ROOT/orchestration/gates/${name}.sh" +} + +run_gate "rdma_transport" +run_gate "8k_smoke" +run_gate "32k_matrix" +run_gate "128k_single" +run_gate "open_loop_load" diff --git a/src/code/issue5/orchestration/start_store.sh b/src/code/issue5/orchestration/start_store.sh new file mode 100755 index 0000000..3815015 --- /dev/null +++ b/src/code/issue5/orchestration/start_store.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +CONFIG_ENV="${1:?usage: start_store.sh CONFIG_ENV}" +[[ -f "$CONFIG_ENV" ]] || { + echo "config not found: $CONFIG_ENV" >&2 + exit 2 +} +set -a +source "$CONFIG_ENV" +set +a + +: "${MOONCAKE_PROTOCOL:?}" +: "${MOONCAKE_MASTER:?}" +: "${MOONCAKE_TE_META_DATA_SERVER:?}" +: "${MOONCAKE_LOCAL_HOSTNAME:?}" +: "${MOONCAKE_GLOBAL_SEGMENT_SIZE:?}" +: "${MOONCAKE_STORE_OWNER:?}" +require_command mooncake_master +require_command mooncake_client + +master_host="${MOONCAKE_MASTER%:*}" +master_port="${MOONCAKE_MASTER##*:}" +owner_host="${MOONCAKE_STORE_OWNER%:*}" +owner_port="${MOONCAKE_STORE_OWNER##*:}" +device_args=() +[[ -z "${MOONCAKE_DEVICE:-}" ]] || device_args=(--device_names="$MOONCAKE_DEVICE") + +start_owned_process mooncake-master mooncake_master \ + --port "$master_port" \ + --enable_http_metadata_server=true \ + --http_metadata_server_host="$master_host" \ + --http_metadata_server_port=8080 + +start_owned_process mooncake-owner mooncake_client \ + --host="$owner_host" \ + --port="$owner_port" \ + --global_segment_size="$MOONCAKE_GLOBAL_SEGMENT_SIZE" \ + --master_server_address="$MOONCAKE_MASTER" \ + --metadata_server="$MOONCAKE_TE_META_DATA_SERVER" \ + --protocol="$MOONCAKE_PROTOCOL" \ + "${device_args[@]}" \ + --threads=8 \ + --enable_offload=false diff --git a/src/code/issue5/orchestration/start_vllm.sh b/src/code/issue5/orchestration/start_vllm.sh new file mode 100755 index 0000000..5aeef69 --- /dev/null +++ b/src/code/issue5/orchestration/start_vllm.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +ROLE="${1:?usage: start_vllm.sh writer|reader|recompute tcp|rdma}" +PROTOCOL="${2:-tcp}" +[[ "$ROLE" =~ ^(writer|reader|recompute)$ ]] || exit 2 +[[ "$PROTOCOL" =~ ^(tcp|rdma)$ ]] || exit 2 +ensure_process_slot "vllm-${ROLE}-${PROTOCOL}" +require_command python3 +require_command vllm +: "${MOONCAKE_STORE_HOST:?set MOONCAKE_STORE_HOST to the Store RoCE IP}" +: "${MOONCAKE_REQUESTER_HOST:?set MOONCAKE_REQUESTER_HOST to this requester RoCE IP}" +MODEL_CONFIG="${ISSUE5_MODEL_CONFIG:-$PROJECT_ROOT/configs/model.yaml}" +SAFETENSORS_LOAD_STRATEGY="${ISSUE5_SAFETENSORS_LOAD_STRATEGY:-}" +ENFORCE_EAGER="${ISSUE5_ENFORCE_EAGER:-0}" +[[ -f "$MODEL_CONFIG" ]] || { + echo "model config not found: $MODEL_CONFIG" >&2 + exit 2 +} +if [[ -n "$SAFETENSORS_LOAD_STRATEGY" ]] && + [[ ! "$SAFETENSORS_LOAD_STRATEGY" =~ ^(lazy|eager|prefetch)$ ]]; then + echo "unsupported safetensors load strategy: $SAFETENSORS_LOAD_STRATEGY" >&2 + exit 2 +fi +[[ "$ENFORCE_EAGER" =~ ^(0|1)$ ]] || { + echo "ISSUE5_ENFORCE_EAGER must be 0 or 1" >&2 + exit 2 +} + +eval "$(python3 - "$MODEL_CONFIG" <<'PY' +import json, shlex, sys, yaml +config = yaml.safe_load(open(sys.argv[1], encoding="utf-8")) +required = ["model_id", "revision", "tokenizer_revision", "served_model_name", "tensor_parallel_size", "max_model_len", "dtype", "seed", "rope_scaling"] +missing = [key for key in required if key not in config] +if missing: + raise SystemExit(f"missing model keys: {missing}") +mapping = { + "MODEL_ID": config["model_id"], "MODEL_REVISION": config["revision"], + "TOKENIZER_REVISION": config["tokenizer_revision"], "SERVED_MODEL_NAME": config["served_model_name"], + "TENSOR_PARALLEL_SIZE": config["tensor_parallel_size"], "MAX_MODEL_LEN": config["max_model_len"], + "MODEL_DTYPE": config["dtype"], "MODEL_SEED": config["seed"], + "HF_OVERRIDES": json.dumps( + {"rope_scaling": config["rope_scaling"]}, separators=(",", ":") + ), +} +for key, value in mapping.items(): + print(f"{key}={shlex.quote(str(value))}") +PY +)" + +export PYTHONHASHSEED=0 +export MOONCAKE_PREFERRED_SEGMENT="${MOONCAKE_STORE_HOST}:50052" +export MOONCAKE_REQUESTER_LOCAL_HOSTNAME="$MOONCAKE_REQUESTER_HOST" +export MOONCAKE_CONFIG_PATH="$RUNTIME_DIR/mooncake-store-${PROTOCOL}.resolved.json" +PYTHONPATH="$PROJECT_ROOT${PYTHONPATH:+:$PYTHONPATH}" python3 -m kvbreak.cli render-config \ + --template "$PROJECT_ROOT/configs/mooncake-store-${PROTOCOL}.json" \ + --output "$MOONCAKE_CONFIG_PATH" \ + --store-host "$MOONCAKE_STORE_HOST" \ + --requester-host "$MOONCAKE_REQUESTER_HOST" \ + >"$RUNTIME_DIR/mooncake-store-${PROTOCOL}.resolved.stdout" + +case "$ROLE" in + writer) + port=8010 + gpu_set="${ISSUE5_WRITER_GPUS:-0,1}" + kv_config='{"kv_connector":"MooncakeStoreConnector","kv_role":"kv_producer"}' + ;; + reader) + port=8020 + gpu_set="${ISSUE5_READER_GPUS:-2,3}" + kv_config='{"kv_connector":"MooncakeStoreConnector","kv_role":"kv_consumer"}' + ;; + recompute) + port=8020 + gpu_set="${ISSUE5_RECOMPUTE_GPUS:-2,3}" + kv_config= + ;; +esac + +# Inspect configured physical ordinals before CUDA can remap an inherited visible set. +unset CUDA_VISIBLE_DEVICES +if [[ "$PROTOCOL" = "rdma" ]]; then + : "${ISSUE5_RDMA_GPU_REGISTRATION:?set ISSUE5_RDMA_GPU_REGISTRATION to dmabuf or peermem}" + WITH_NVIDIA_PEERMEM="$( + PYTHONPATH="$PROJECT_ROOT${PYTHONPATH:+:$PYTHONPATH}" python3 -m kvbreak.cli \ + validate-gpu-registration \ + --mode "$ISSUE5_RDMA_GPU_REGISTRATION" \ + --gpu-indices "$gpu_set" + )" + export WITH_NVIDIA_PEERMEM +fi +export CUDA_VISIBLE_DEVICES="$gpu_set" +PYTHONPATH="$PROJECT_ROOT${PYTHONPATH:+:$PYTHONPATH}" python3 -m kvbreak.cli \ + snapshot-environment \ + --output "$RUNTIME_DIR/vllm-${ROLE}-${PROTOCOL}.environment.json" \ + >"$RUNTIME_DIR/vllm-${ROLE}-${PROTOCOL}.environment.stdout" + +args=( + vllm serve "$MODEL_ID" + --host 0.0.0.0 --port "$port" + --served-model-name "$SERVED_MODEL_NAME" + --revision "$MODEL_REVISION" + --tokenizer-revision "$TOKENIZER_REVISION" + --tensor-parallel-size "$TENSOR_PARALLEL_SIZE" + --max-model-len "$MAX_MODEL_LEN" + --dtype "$MODEL_DTYPE" + --seed "$MODEL_SEED" + --hf-overrides "$HF_OVERRIDES" +) +[[ -z "$SAFETENSORS_LOAD_STRATEGY" ]] || args+=( + --safetensors-load-strategy "$SAFETENSORS_LOAD_STRATEGY" +) +[[ "$ENFORCE_EAGER" = 0 ]] || args+=(--enforce-eager) +[[ -z "$kv_config" ]] || args+=(--kv-transfer-config "$kv_config") +printf '%q ' "${args[@]}" > "$RUNTIME_DIR/vllm-${ROLE}-${PROTOCOL}.command" +printf '\n' >> "$RUNTIME_DIR/vllm-${ROLE}-${PROTOCOL}.command" +start_owned_process "vllm-${ROLE}-${PROTOCOL}" "${args[@]}" diff --git a/src/code/issue5/orchestration/stop_stack.sh b/src/code/issue5/orchestration/stop_stack.sh new file mode 100755 index 0000000..d218bbe --- /dev/null +++ b/src/code/issue5/orchestration/stop_stack.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" + +shopt -s nullglob +for pidfile in "$RUNTIME_DIR"/*.pid; do + stop_pidfile "$pidfile" "$PROJECT_ROOT" +done diff --git a/src/code/issue5/pyproject.toml b/src/code/issue5/pyproject.toml new file mode 100644 index 0000000..af1297e --- /dev/null +++ b/src/code/issue5/pyproject.toml @@ -0,0 +1,34 @@ +[build-system] +requires = ["setuptools>=75", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "hpn-issue5-kvbreak" +version = "0.1.0" +description = "Reproducible KV-cache break-even bandwidth and TCP/RDMA analysis" +requires-python = ">=3.10,<3.13" +dependencies = [ + "httpx>=0.27,<1", + "matplotlib>=3.8,<4", + "numpy>=1.26,<3", + "PyYAML>=6,<7", +] + +[project.optional-dependencies] +dev = ["pytest>=8,<9", "pytest-asyncio>=0.24,<1", "ruff>=0.8,<1"] + +[project.scripts] +kvbreak = "kvbreak.cli:main" + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = "-ra --strict-markers" +asyncio_mode = "auto" + +[tool.ruff] +line-length = 100 +target-version = "py310" + +[tool.setuptools.packages.find] +where = ["."] +include = ["kvbreak*", "benchmarks*"] diff --git a/src/code/issue5/report/RESULTS.md b/src/code/issue5/report/RESULTS.md new file mode 100644 index 0000000..164cba5 --- /dev/null +++ b/src/code/issue5/report/RESULTS.md @@ -0,0 +1,289 @@ +# TCP/RDMA KV Cache 实验报告 + +## 结论与证据边界 + +2026-07-31 完成了双机 A40/RoCE 环境检查、裸 RDMA/TCP 链路 Gate 和 +Mooncake Store TCP 最小兼容性闭环;2026-08-01 在明确授权后加载与 +node1 内核/驱动匹配的 `nvidia_peermem`,又完成了一次单 GPU、单请求的 +Mooncake GPUDirect RDMA 兼容性闭环。当前可确认: + +1. `gpu-node1 → gpu-node3` 的裸 RDMA write 链路正常,64 KiB、8 QP 的平均带宽为 + 185.11 Gbit/s;这只证明网卡链路,不证明 Mooncake 的 GPU 数据路径。 +2. Pythia 14M、2048-token 兼容性 smoke 的 TCP Store Writer/Reader 闭环通过: + 3/3 Reader 请求成功,189/189 GET keys 成功,GET 字节与理论值同为 + 9,289,728 bytes,3024/3024 cached tokens 被外部前缀缓存命中,输出摘要 3/3 + 与 recompute 对照一致。 +3. 7 月 31 日的 Mooncake RDMA 诊断因 peer-memory 未加载而失败;该失败和 + DMA-BUF 对照试验锁定了根因,但不再代表加载模块后的当前状态。 +4. 加载 `nvidia_peermem` 后,RDMA Writer 的 63/63 PUT keys 成功,Reader 的 + 63/63 GET keys 成功;理论与实测 GET 字节均为 3,096,576,1008/1008 + cached tokens 命中,Reader 输出摘要与 fresh recompute 一致,机器判定 + `proven=true`。 +5. 现场证据还同时满足了 GPUDirect 兼容性判据:显式 peermem 注册、 + CUDA-backed KV arena 成功注册、`nvidia_peermem` 运行时 use count 为 6、 + Mooncake endpoint memcpy 禁用、Store host pinned staging 禁用,且 RDMA 计数器按 + payload 方向增长 3,278,016 / 3,274,992 bytes。 +6. 上述模型仅用于兼容性诊断;TCP 样本量为 3,RDMA 样本量为 1。 + TCP Reader TTFT 中位数为 104.212 ms,高于 warmed recompute 的 26.736 ms; + RDMA 的单次 TTFT 也不构成统计或加速结论。 +7. 锁定的 Qwen 7B 8K/32K/128K 与 open-loop 矩阵没有完成,仍为 `UNKNOWN`。 + +完整原始证据分别位于 `results/raw/remote-20260731/`(TCP 闭环与首次 +RDMA 失败)、`results/raw/remote-20260801/`(注册根因对照)和 +`results/raw/remote-20260801-peermem-smoke/`(授权后的 GPUDirect RDMA 闭环)。 +关键机器判定与文件完整性分别由 `remote-hit-verdict.json` 和各目录的 +`manifest.json` 校验。 + +## 状态总览 + +| 层级 | 状态 | 证据级别 | 能否作为性能结论 | +| --- | --- | --- | --- | +| 临界带宽公式、边界与统计实现 | 本地测试通过 | `CALCULATED` / 方法实现 | 公式结论可以 | +| A40 双机 preflight | 两端原始输出已归档 | `MEASURED` | 只能描述环境 | +| 裸 RDMA/TCP 链路 | Gate 通过 | `MEASURED` | 只能描述链路 | +| TCP Mooncake Store 2048-token smoke | 功能闭环通过 | `MEASURED_COMPATIBILITY` | 只能说明兼容性 | +| RDMA Mooncake GPU 数据路径 | peermem 单请求闭环通过 | `GPUDIRECT_RDMA_COMPATIBILITY` | 只能说明兼容性 | +| Qwen 7B 8K/32K/128K、QPM、成本 | 未运行 | `UNKNOWN` | 否 | + +## 双机环境 + +| 项目 | Requester / `gpu-node1` | Store / `gpu-node3` | +| --- | --- | --- | +| RoCE 地址 | `10.10.10.3` | `10.10.10.7` | +| GPU | 3 × NVIDIA A40 | 8 × NVIDIA A40;本实验 Store 只用 CPU/内存 | +| NVIDIA Driver | 580.95.05 | 590.48.01 | +| RDMA | `mlx5_0`,RoCE v2,GID index 3 | `mlx5_0`,RoCE v2,GID index 3 | +| Python | 3.12.3 | 3.12.3 | +| vLLM | 0.23.0 | 不适用 | +| Mooncake Transfer Engine | 0.3.12.post1 | 0.3.12.post1 | +| PyTorch | 2.11.0+cu130 | 不适用 | +| NVIDIA kernel module | Proprietary,license `NVIDIA` | Open,license `Dual MIT/GPL` | +| CUDA attr 116 / 124 | 全部 GPU 为 `1 / 0` | 全部 GPU 为 `1 / 1` | +| peer-memory | 授权后已加载 580.95.05;smoke 时 use count=6,收尾时为 0 | 未加载;Store 不使用 GPU | + +模型、tokenizer 和 resolved YAML 的 SHA-256 记录在 +`results/raw/remote-20260731/environment.json`。两端服务在证据收集后均通过项目 PID +文件和独立 session 清理;Requester 的 8010/8020 与 Store 的 +50051/50052/8080/9003 端口均确认释放,GPU 0/1 回到 0 MiB。GPU 2 上的 +其他用户进程从始至终未被触碰。`nvidia_peermem` 按授权加载后保持已加载, +未在共享主机上擅自卸载。 + +## 原始链路 Gate + +### RDMA write bandwidth + +64 KiB payload,`mlx5_0`,GID index 3: + +| QP | 平均带宽(Gbit/s) | +| ---: | ---: | +| 1 | 184.98 | +| 2 | 185.07 | +| 4 | 185.09 | +| 8 | 185.11 | + +### RDMA write latency + +| Payload | 平均延迟(µs) | p99(µs) | +| ---: | ---: | ---: | +| 64 B | 2.45 | 2.51 | +| 4 KiB | 3.45 | 3.65 | +| 1 MiB | 49.08 | 49.34 | + +### TCP 应用探针 + +| 并发连接 | 吞吐(Gbit/s) | +| ---: | ---: | +| 1 | 5.3756 | +| 2 | 10.4619 | +| 4 | 20.2564 | +| 8 | 28.8071 | + +| Payload | 应用 RTT 中位数(µs) | p95(µs) | +| ---: | ---: | ---: | +| 64 B | 112.8865 | 122.9143 | +| 4 KiB | 190.3345 | 218.4106 | +| 1 MiB | 16292.6660 | 17327.8398 | + +TCP 探针包含 Python framing、序列号与 SHA 校验,是应用往返时间;RDMA perftest 是 +write latency。二者语义不同,不能把这两组延迟直接相除得出协议加速比。 + +## TCP Store 兼容性 smoke + +### 负载与模型 + +| 项目 | 值 | +| --- | ---: | +| 模型 | 本地 Pythia 14M(GPT-NeoX,兼容性模型) | +| TP / dtype / seed | 1 / float16 / 20260731 | +| sequence budget | 2048 tokens | +| prompt / output | 2047 / 1 tokens | +| cached tokens | 1008 / request | +| 实际命中率 | 49.2428% | +| 理论 KV payload | 3,096,576 bytes / request | +| 样本数 | 3 requests / path | + +### 请求结果 + +| 路径 | 成功/总数 | TTFT 原始值(ms) | TTFT 中位数(ms) | 结论 | +| --- | ---: | --- | ---: | --- | +| recompute | 3/3 | 481.855360, 23.762906, 26.735648 | 26.735648 | 首个样本含明显 warmup | +| TCP Writer | 3/3 | 62.356075, 27.841733, 29.741729 | 29.741729 | 189 keys 全部写入 | +| TCP Reader | 3/3 | 348.581553, 104.211576, 102.857144 | 104.211576 | 189 keys 全部远端读取 | + +样本量过小,不报告 p95/QPM,也不做显著性或成本结论。Reader 比 warmed recompute 慢, +符合 tiny model 的 prefill 计算量太小、远端读取固定开销占主导的现象;这只是本次测量的 +观察,不外推到 7B/长上下文。 + +### 远端命中闭环 + +| 判据 | 期望 | 观测 | 状态 | +| --- | ---: | ---: | --- | +| Reader 请求成功 | 3 | 3 | 通过 | +| 输出 SHA-256 与 recompute 匹配 | 3 | 3 | 通过 | +| Store GET keys | 189 | 189 success / 0 failed | 通过 | +| Store GET bytes | 9,289,728 | 9,289,728 | 通过 | +| external prefix hit tokens | 3,024 | 3,024 | 通过 | +| Store 内存状态 | 189 keys | 8.86 MiB / 64 GiB | 通过 | + +每个 Reader 请求的 tier log 都显示 `batch_keys=63`、`memory_keys=63`、 +`disk_keys=0`、`failed_keys=0`、`bytes=3,096,576`。验证器不是只看请求 HTTP 成功, +而是按 `request_id` 连接 recompute/Reader 输出,再核对 fresh Reader 进程的 Prometheus +累计量;判定结果为 `proven=true`。 + +## 历史 RDMA Store 失败 Gate 与根因 + +裸 RDMA 通过后,Mooncake Store 的 RDMA Writer 在注册 vLLM GPU KV arena 时失败: + +```text +Failed to register memory ...: Bad address [14] +register_buffer failed ...: -600 +Failed to submit all transfers, error code is AddressNotRegistered +``` + +三请求诊断虽然仍能通过本地推理返回输出,但 KV transfer 指标为: + +- `save_put_total_keys=189` +- `save_put_total_bytes=9,289,728` +- `save_put_failed_keys=189` + +这说明“请求成功”不能证明缓存写入成功。另一次设置 `MC_STORE_MEMCPY=1` 的单请求 +探针仍有 63/63 keys 失败;该变量不是 GPU→Host staging 回退证明。 + +Mooncake v0.3.12 的发布源码将 `WITH_NVIDIA_PEERMEM` 的运行时默认值设为 `true`。 +GPU 指针在该模式下进入 legacy host-registration 分支,最终使用 `ibv_reg_mr`;只有显式 +设为 `false` 才使用 CUDA DMA-BUF handle 与 `ibv_reg_dmabuf_mr`。因此原始 run 在未加载 +`nvidia_peermem`/`nv_peer_mem` 时继承 legacy 路径,`ibv_reg_mr` 返回 EFAULT,解释了 +`Bad address [14]` 与随后的 `AddressNotRegistered`。 + +为排除“只缺一个环境变量”,2026-08-01 使用同一模型、GPU 0、RNIC 和 RDMA 配置, +只增加 `WITH_NVIDIA_PEERMEM=0`。旧的 `Bad address` 消失,但 Transfer Engine 在初始化 +阶段明确停止: + +```text +DMA BUF supported required for GPU RDMA without nvidia-peermem on GPU device 0 mapped to RNIC mlx5_0 +Failed to initialize transfer engine +``` + +直接调用 CUDA Driver API 的结果与日志一致:node1 三张 A40 的 +`GPU_DIRECT_RDMA_SUPPORTED`(attribute 116)均为 1,而 `DMA_BUF_SUPPORTED` +(attribute 124)均为 0;node3 八张 A40 的两个属性均为 1。node1 使用 proprietary +NVIDIA kernel module,且匹配 kernel/driver 的 `nvidia-peermem.ko.zst` 虽存在于磁盘, +但没有加载。于是诊断当时 Requester 上两条路径的阻断条件得到了独立复现: + +| 注册路径 | Mooncake 开关 | Requester 观测 | 结论 | +| --- | --- | --- | --- | +| legacy peer-memory | `WITH_NVIDIA_PEERMEM=1` | module 未加载;`ibv_reg_mr` EFAULT | FAIL | +| DMA-BUF | `WITH_NVIDIA_PEERMEM=0` | CUDA attribute 124=0;初始化主动拒绝 | FAIL | + +项目现在要求 `ISSUE5_RDMA_GPU_REGISTRATION=dmabuf|peermem`,启动前检查所选 GPU +属性与模块状态,再显式映射为 Mooncake 开关。该修复不会让不兼容主机“假通过”,而是 +把分钟级、189-key 的运行时失败提前成无 GPU 服务副作用的确定性 preflight 失败。 + +因此在管理员授权加载模块之前,历史状态严格为: + +```text +bare RDMA link = MEASURED/PASS +Mooncake RDMA GPU path = UNPROVEN_RDMA/FAIL +GPUDirect RDMA = NOT PROVEN +``` + +## peermem GPUDirect RDMA 兼容性 smoke + +2026-08-01 在用户明确授权后,node1 先校验了模块文件、版本和 +vermagic,再执行 `sudo modprobe nvidia-peermem`。实验只使用空闲 GPU 0; +GPU 2 上保持着其他用户的进程。Writer、Reader 与 recompute 串行运行, +负载与 TCP 兼容性测试的 item0 完全一致。 + +| 判据 | 期望 | 观测 | 状态 | +| --- | ---: | ---: | --- | +| Writer PUT keys | 63 | 63 success / 0 failed | 通过 | +| Reader GET keys | 63 | 63 success / 0 failed | 通过 | +| Store GET bytes | 3,096,576 | 3,096,576 | 通过 | +| external prefix hit tokens | 1,008 | 1,008 | 通过 | +| Reader/recompute 输出 SHA-256 | 相同 | 1/1 相同 | 通过 | +| Writer RDMA 发送增量 | 与 payload 同量级 | 3,278,016 bytes | 通过 | +| Reader RDMA 接收增量 | 与 payload 同量级 | 3,274,992 bytes | 通过 | + +GPUDirect 判定不仅依赖 `protocol=rdma`: + +- 启动前预检显式选择 `ISSUE5_RDMA_GPU_REGISTRATION=peermem`,环境快照中 + `WITH_NVIDIA_PEERMEM=1`。 +- Writer/Reader 都在 `mlx5_0`、GID index 3 上启动 RDMA,成功注册 + 8 GiB CUDA-backed 本地 KV 内存和 vLLM KV-cache segments;实验期间 + `nvidia_peermem` use count 为 6。 +- Requester 的 Mooncake endpoint memcpy 被禁用,Store 的 pinned host staging 也被禁用。 +- Reader 的 Store TCP 连接只通往 metadata/master 端口 8080/50051,累计字节远小于 + 3.1 MB payload,且没有通往 data-plane owner 50052 的 TCP 连接。 +- payload 方向的 RDMA 计数器增量分别比理论 KV 字节高 5.86% 和 5.76%, + 符合小 payload 的协议开销,不存在 TCP payload fallback 特征。 + +机器闭环判定为 `proven=true`,因此这一次最小运行的证据级别为 +`GPUDIRECT_RDMA_COMPATIBILITY`。但 Writer/Reader/recompute 都只有一个请求, +TTFT 分别为 59.863 / 112.552 / 70.106 ms,不报告 p50/p95、QPM、SLO 或 +RDMA-over-TCP 加速比。这一兼容性结果也不能外推到 Qwen 7B 或长上下文。 + +## 正式结果矩阵 + +| 协议 | 序列预算 | 目标/实际命中率 | KV 字节 | 有效带宽 | TTFT p50/p95 | 错误率 | 最大并发 | 合规 QPM | 证据级别 | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | +| recompute | 8K | 0/0 | 0 | N/A | 未运行 | 未运行 | 未运行 | 未运行 | `UNKNOWN` | +| TCP | 8K | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | `UNKNOWN` | +| RDMA | 8K | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | `UNKNOWN` | +| recompute/TCP/RDMA | 32K | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | `UNKNOWN` | +| recompute/TCP/RDMA | 128K | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | 未运行 | `UNKNOWN` | + +锁定的 Qwen2.5-7B 权重未能在运行窗口内取得;现有只读 Llama 8B 副本位于共享冷盘, +加载在第一个 shard 长时间停滞。为避免占用共享 GPU 和误报结果,本轮在最小兼容性 +smoke 后停止,没有把替代模型升级成正式结果。 + +## 公平性检查 + +### 兼容性 smoke + +- [x] recompute/Writer/Reader 使用相同模型、tokenizer SHA-256、dtype、TP、seed。 +- [x] `context_tokens + max_output_tokens = sequence_budget_tokens`。 +- [x] Reader 使用 fresh vLLM 进程,Prometheus GET 计数从零开始。 +- [x] TCP Writer/Reader 输出与 recompute 逐请求摘要一致。 +- [x] 失败键保留;历史 RDMA 请求的本地推理成功没有覆盖 KV transfer 失败。 +- [x] 双机 raw、环境、模型 hash 和 manifest 纳入证据包。 +- [x] peermem smoke 的 RDMA counter 与 Mooncake payload 在方向和量级上对应。 +- [x] fresh RDMA Reader 的输出、GET 字节、external hit tokens 和失败键已机器交叉验证。 + +### 正式 Qwen 7B 矩阵 + +- [ ] 三路径模型与 tokenizer 完整 revision 相同。 +- [ ] TP、dtype、RoPE、max model length、seed 相同。 +- [ ] Reader 每个 cell 重启,正式样本不复用本地热 cache。 +- [ ] TCP/RDMA 仅改变 protocol/device 字段。 +- [ ] 失败、超时和 OOM 保留在分母。 +- [ ] QPM 是 SLO 与错误率约束下的实际完成量,不是 offered load。 +- [ ] RDMA counter 和 TCP fallback 证据已保存。 + +## 后续放行条件 + +1. 已完成授权后的 peermem 单 GPU 最小 Writer/Reader Gate;后续若要把 + `nvidia_peermem` 做成宿主机持久配置,或卸载它,应由共享主机管理员单独决定。 +2. 将锁定 revision 的 Qwen2.5-7B 权重预热到可持续读取的本地盘,再按 + `8K smoke → 32K matrix → 128K single → open-loop` 顺序运行;任何 Gate 失败即停止。 +3. 正式矩阵仍需每个 cell 重新捕获 RDMA/TCP 计数器、完整失败分母、 + 延迟分布、SLO 合规 QPM 和成本;本次单请求证据包只允许用作功能放行。 diff --git a/src/code/issue5/requirements-remote.in b/src/code/issue5/requirements-remote.in new file mode 100644 index 0000000..606960f --- /dev/null +++ b/src/code/issue5/requirements-remote.in @@ -0,0 +1,2 @@ +vllm>=0.23,<0.24 +mooncake-transfer-engine>=0.3.12,<0.4 diff --git a/src/code/issue5/results/raw/remote-20260731/README.md b/src/code/issue5/results/raw/remote-20260731/README.md new file mode 100644 index 0000000..8300d0e --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/README.md @@ -0,0 +1,24 @@ +# Remote evidence bundle: 2026-07-31 + +This bundle preserves the two-host A40/RoCE diagnostic run used by +`report/RESULTS.md`. + +- `node1/`: requester-side preflight, RDMA/TCP probes, request JSONL, vLLM logs, + Prometheus snapshot, and the curated GPU-memory-registration failure excerpt. +- `node3/`: Store-side preflight, probe-server outputs, and Mooncake + master/owner snapshots. +- `tcp-remote-hit-verdict.json`: machine-generated cross-check of recompute and + TCP Reader outputs against vLLM/Mooncake metrics. +- `environment.json`: package, topology, model, and SHA-256 provenance. +- `manifest.json`: SHA-256 inventory generated after the source adaptation + commit; verify it with `kvbreak verify-manifests`. + +Evidence boundary: the bare RDMA link passed, and the TCP Mooncake Store +compatibility path completed. The Mooncake RDMA GPU data path did not complete +because GPU memory registration failed. This bundle is not a Qwen 7B 8K/32K/ +128K performance result. + +Known raw-artifact caveat: `node3/network/server-bw-q1.exit` contains a malformed +four-byte sidecar and is retained verbatim for auditability. It is not used as +pass evidence; the completed client/server perftest stdout, including the final +5000-iteration measurement row, is the QP=1 evidence. diff --git a/src/code/issue5/results/raw/remote-20260731/environment.json b/src/code/issue5/results/raw/remote-20260731/environment.json new file mode 100644 index 0000000..8ac74c6 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/environment.json @@ -0,0 +1,53 @@ +{ + "collected_at_utc": "2026-07-31T17:13:35Z", + "base_commit": "efff26b384d45a06d76f3d3a034ddf58655a6e88", + "verification_source_commit": "73e5da1659a7af7bf6d596d123a56b2e49c5c9a0", + "requester": { + "hostname": "gpu-node1", + "roce_address": "10.10.10.3", + "python": "3.12.3", + "vllm": "0.23.0", + "mooncake_transfer_engine": "0.3.12.post1", + "torch": "2.11.0+cu130", + "gpu": "NVIDIA A40", + "driver": "580.95.05", + "rdma_device": "mlx5_0", + "gid_index": 3 + }, + "store": { + "hostname": "gpu-node3", + "roce_address": "10.10.10.7", + "python": "3.12.3", + "mooncake_transfer_engine": "0.3.12.post1", + "gpu": "NVIDIA A40", + "driver": "590.48.01", + "rdma_device": "mlx5_0", + "gid_index": 3 + }, + "compatibility_smoke_model": { + "model_id": "/mnt/sda1/yxz/pythia_test/pythia-14m_main", + "served_model_name": "issue5-pythia-14m-smoke", + "tensor_parallel_size": 1, + "max_model_len": 2048, + "dtype": "float16", + "seed": 20260731, + "files": { + "config.json": { + "sha256": "5536386c1709fd29d9617fca802bb8f592071ac279f772b5c63a6be3db3488e2" + }, + "model.safetensors": { + "bytes": 53311772, + "sha256": "821667edaab2cb38aac634fd1bbda547ecf451f4ea514f47b5a0080be24154fb" + }, + "tokenizer.json": { + "bytes": 2113738, + "sha256": "3cf430678137c8491ca82fb7092ee49e44ad38857fffe1e4a4a5ed860139a5b8" + }, + "model-pythia14m-smoke.resolved.yaml": { + "bytes": 389, + "sha256": "729993ac58c6ab1339925d0df27b7fe4a667389f173bc86d46ec801ca1ba1ba5" + } + } + }, + "scope": "2048-token compatibility smoke only; not the locked Qwen 7B performance matrix" +} diff --git a/src/code/issue5/results/raw/remote-20260731/manifest.json b/src/code/issue5/results/raw/remote-20260731/manifest.json new file mode 100644 index 0000000..050d5f6 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/manifest.json @@ -0,0 +1,88 @@ +{ + "metadata": { + "commit": "73e5da1659a7af7bf6d596d123a56b2e49c5c9a0", + "node": "gpu-node1+gpu-node3" + }, + "files": { + "README.md": "89cdf76e264bce981db78f513befce17f37dcaddac443f04b8772e604bad5d8d", + "environment.json": "567cfea6b2f219d4d1553d675d885a38cc01634b1a5ad8115e6106610115d121", + "node1/mooncake/rdma-gpu-registration-failure-excerpt.log": "a1f7c3b9cd9cbb06420f103e3766ef7093eaf4c16c2d73bdd128fdb0838fa20d", + "node1/mooncake/requester-after-writer-rdma.txt": "98da88790ddae2521018c7d5cbe7dadf62de8476c7ae5ff1b6170ac454ffb279", + "node1/mooncake/requester-before-writer-rdma.txt": "d04c27c04e75a64803703fc040d642d3c9475e9dc1fa009f61f3a014a72ad2be", + "node1/mooncake/vllm-reader-tcp-prometheus.txt": "8c27806fdfa725c4fa8630a456518e0c14135f4c3b42fc3820f8633002924676", + "node1/mooncake/vllm-reader-tcp-smoke.log": "ddc664c1683153508e636c3d83ddbc01bd80000e3b2cd57211ab49088d8a05f4", + "node1/mooncake/vllm-writer-tcp-smoke.log": "3059c872a057acea7e1a3267d38e1caecb32dabb446e815bbda5df05c02f921c", + "node1/network/client-bw-q1.stderr": "02b2f77b68fd33eed0b953de7d8d0e4c8e2075a58ab26d65881dc863186644c9", + "node1/network/client-bw-q1.stdout": "6192e32d388dbb05eb6bec50eace8106e4d1506a386f5178852f17ad7f3279ae", + "node1/network/client-bw-q2.stderr": "1a54fc9344e49763f2a860e5956206023fa6634a4910142d0e480e3bd9043c01", + "node1/network/client-bw-q2.stdout": "17c017d9e93f8011eafc32e4e7d48884cd4a351d2872cb05c86450904e4084a9", + "node1/network/client-bw-q4.stderr": "2f972d9b336c430ab240bf72f68d7ea765291b8b7e21e2461b5fc8d5bbf0e529", + "node1/network/client-bw-q4.stdout": "26c7e24752d61584c4a426f4e20389c44e79c8f383a800820d97fabbf371408b", + "node1/network/client-bw-q8.stderr": "f378e4e67919d09e684b4e6bfd9e1d424de8446a6ec1669c9c7781183dcad11c", + "node1/network/client-bw-q8.stdout": "f18e8b6a6cf35c472791e426bb83f5e1e0faf48322b4e06270283d760ce1539b", + "node1/network/client-lat-1048576.stderr": "03888de46c1ec37e1693cdbc924dbacb7382b493ac8676685256e691c7c13066", + "node1/network/client-lat-1048576.stdout": "f5aab3051623229ef874ee162395a8b3147e823c39c0a9386e04249ee38992bf", + "node1/network/client-lat-4096.stderr": "10174785fc804fc81b49939e8b802f12ea8c35081326cf92a739376d84725372", + "node1/network/client-lat-4096.stdout": "a5143ef56152ceb3545e46b14339f69c4046ca7c1169efe3ed1d6e3a2714bdeb", + "node1/network/client-lat-64.stderr": "e6042ee85f5ca4480c9a47b6ee50b9fff2e24236dc881dacaa97b07ebb08dc9c", + "node1/network/client-lat-64.stdout": "e187d6a77d0d70a77f1345a20d9e2970b62011ab6b9331a1b20c3b529d72af9a", + "node1/network/tcp-client-bw-c1.json": "af34ac877d7a561ff578289e01de154ae9e6ff929f66aa80b3390fb6d079e7d2", + "node1/network/tcp-client-bw-c2.json": "60e0b7f244089d202c623099a42b5ebe9b332e1ece8c0242e38abb7b69f63a06", + "node1/network/tcp-client-bw-c4.json": "8a72d31e904aa9aa8d0e345a76fae14936e5189219fa00da8f8c279e652c3fd9", + "node1/network/tcp-client-bw-c8.json": "e5f581cadc95e06b8a1ad5681f587a8694e08aa87e9a98208feee07d63125dfb", + "node1/network/tcp-client-lat-1048576.json": "7ae0238d8c51bbb3df6a153f9c6fce39a42b7726fa9618d2a1b683fd328ec141", + "node1/network/tcp-client-lat-4096.json": "bc718c0b4ad666d8d1a2345fd02fb4bfb1e81eeefa9e09bf2e3bc3367496375c", + "node1/network/tcp-client-lat-64.json": "4a7f0e1076f785984af5e7eb051ed1fd174cead8253724464ca6eaf46781428f", + "node1/preflight/gpu-node1.jsonl": "497b90fc8c8f7a18a6b12995688dfc4cbcd90093dec310a7c5eca489b1d15b6d", + "node1/requests/pythia14m-reader-tcp-smoke.jsonl": "88e62693d7e76b966ddd127897e9af66b098de4ad6fae0b5b4a2318e5c958f82", + "node1/requests/pythia14m-recompute-rdma-smoke.jsonl": "770e3d84068eb215ff3f7d3f50bf6fb2fe76773647299cb1b93d5d393a9fc095", + "node1/requests/pythia14m-writer-rdma-smoke.jsonl": "26e2b8a9392bafa9cba8857ce4706b07d5ad48c5b0e5af481c8a06138a83ab41", + "node1/requests/pythia14m-writer-rdma-staged-probe.jsonl": "4b8c926f997f349aed59d6759d70830c979e395a11c1f916472fb2f569432999", + "node1/requests/pythia14m-writer-tcp-smoke.jsonl": "c507b5f6840e4bb275bf4927e12dbcacefd19aaa60e59993e27eee99bdc56d6c", + "node3/mooncake/master-after-reader-tcp.log": "21cd1291886576fd37b665c329aa0846b6309317bcff61bd7cdb584644bcd5f9", + "node3/mooncake/master-after-writer-tcp.log": "05a245652335a680b2dbeb576b0b634528dc847c7c504ef31673fe7d9caefcc7", + "node3/mooncake/master-before-writer-rdma.log": "aa807f6c7e0b504e3c098c40ed05bb6cec8fb0d0a9559cadb77edecd5e13a76b", + "node3/mooncake/owner-after-reader-tcp.log": "bdf817e2bf2829b01f9b38d8038134107a7a7bbb3bcb189e53912e7d2796f6ea", + "node3/mooncake/owner-after-writer-tcp.log": "c1f8183d7950e49648678ba125238a9349efd4709bc6d63d18acfe713d7d788c", + "node3/mooncake/owner-before-writer-rdma.log": "78266876d3f28ad6215e3fe623fb1b6b2d0d197c9bae2b9651f2ea0a7b47b412", + "node3/mooncake/store-before-writer-rdma.txt": "7348c513958facf0c4f0f5cd8f4847692fc6f6fc8576794d6af3ec4722cad915", + "node3/network/server-bw-q1.exit": "a88f28d0670369ef8e3f771ac3df3b011fd914053ead04c5cec8e30cd1faec45", + "node3/network/server-bw-q1.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/server-bw-q1.stdout": "442a1df3fabe43eac7c8c30d6912a0cd590bf074c501caffd207528967abf06a", + "node3/network/server-bw-q2.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/server-bw-q2.stdout": "5a4774f6b458bd796b626339dcfb45924cbb7c3dc9c93769405ec035d5169bf3", + "node3/network/server-bw-q4.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/server-bw-q4.stdout": "363a707ad43f7eab776470fd1d04a52356cb612b50a580c38ee0cfb5f75fffb1", + "node3/network/server-bw-q8.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/server-bw-q8.stdout": "7c68ebc4c5ad8972129e4e4e3e28fb6f4f6d9c85eb18928839c3b96ac59ea01f", + "node3/network/server-lat-1048576.stderr": "07067d3659daca6327a262635d02cfd440b0bc32a922ca869c5d269964e83317", + "node3/network/server-lat-1048576.stdout": "a99147c022025280bf9ca773022d812fae05210314ac3d784f67508f98427d9c", + "node3/network/server-lat-4096.stderr": "e4b65617fd11884521ae47f01d382fb6c926117e63d85cfce6b0740c753e1cfa", + "node3/network/server-lat-4096.stdout": "bd4dd4a0ce897211364c8e898204ddb3bf002c1fecc5c7d6377de4f3bbe0619f", + "node3/network/server-lat-64.stderr": "e4b65617fd11884521ae47f01d382fb6c926117e63d85cfce6b0740c753e1cfa", + "node3/network/server-lat-64.stdout": "abad6d67d9646da66b6721b0eaf1de8acfe5b521ad0eac2d35d64feb082a9832", + "node3/network/tcp-server-bw-c1.json": "59dc5156cf226f90db14bbc3ff45a1ec91f482c81ce4ced8e24c74f57102309f", + "node3/network/tcp-server-bw-c1.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/tcp-server-bw-c1.stdout": "59dc5156cf226f90db14bbc3ff45a1ec91f482c81ce4ced8e24c74f57102309f", + "node3/network/tcp-server-bw-c2.json": "771524af0109cfd89ccc9812d1f32a568413a776ff0aa10290fd23f7b4ce6289", + "node3/network/tcp-server-bw-c2.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/tcp-server-bw-c2.stdout": "771524af0109cfd89ccc9812d1f32a568413a776ff0aa10290fd23f7b4ce6289", + "node3/network/tcp-server-bw-c4.json": "6ba6618b7bcecd183369c742b31c33df8339a9e3131beda6d73455c960af820a", + "node3/network/tcp-server-bw-c4.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/tcp-server-bw-c4.stdout": "6ba6618b7bcecd183369c742b31c33df8339a9e3131beda6d73455c960af820a", + "node3/network/tcp-server-bw-c8.json": "2b2673982998649f076b6f1b4141795a94ef8c69c1f1f814888999ea50c36005", + "node3/network/tcp-server-bw-c8.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/tcp-server-bw-c8.stdout": "2b2673982998649f076b6f1b4141795a94ef8c69c1f1f814888999ea50c36005", + "node3/network/tcp-server-lat-1048576.json": "79a0b1e64ffbdf1c76846e50c679b970ad84f1ba2dc05a89d1f05c2e0aa6ac1a", + "node3/network/tcp-server-lat-1048576.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/tcp-server-lat-1048576.stdout": "79a0b1e64ffbdf1c76846e50c679b970ad84f1ba2dc05a89d1f05c2e0aa6ac1a", + "node3/network/tcp-server-lat-4096.json": "b13e53f28004c7822f60cd2ccbfd9245688125162871cebc2743ae03a500cb1d", + "node3/network/tcp-server-lat-4096.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/tcp-server-lat-4096.stdout": "b13e53f28004c7822f60cd2ccbfd9245688125162871cebc2743ae03a500cb1d", + "node3/network/tcp-server-lat-64.json": "dbeec93c621f31fb49fa8564012c3a550681a4c98eb24c39905ac3ba42fd9db3", + "node3/network/tcp-server-lat-64.stderr": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "node3/network/tcp-server-lat-64.stdout": "dbeec93c621f31fb49fa8564012c3a550681a4c98eb24c39905ac3ba42fd9db3", + "node3/preflight/gpu-node3.jsonl": "a54fa3dafc12c90cc59e6204a5c16c43d6d25e750c95d6a83e028227694473b0", + "tcp-remote-hit-verdict.json": "0cffd0f278c3fa3b9e6ad796e56900861bb76c1896e442755f2d0d2d0f5eec39" + } +} diff --git a/src/code/issue5/results/raw/remote-20260731/node1/mooncake/rdma-gpu-registration-failure-excerpt.log b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/rdma-gpu-registration-failure-excerpt.log new file mode 100644 index 0000000..cc0db34 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/rdma-gpu-registration-failure-excerpt.log @@ -0,0 +1,19 @@ +# source: results/logs/vllm-writer-rdma.failed-gpudirect-20260731T1652Z.log +E0731 16:51:14.899969 1453989 rdma_context.cpp:588] Failed to register memory 0x7d0a04000000: Bad address [14] +(EngineCore pid=1440361) ERROR 07-31 16:51:14 [worker.py:1154] register_buffer failed for addr 0x7d0a04000000 len 7240867840: -600 +E0731 16:52:05.806559 1454087 transfer_task.cpp:1176] Failed to submit all transfers, error code is AddressNotRegistered +(APIServer pid=1436766) INFO 07-31 16:52:15 [metrics.py:103] KV Transfer metrics: lookup_exists_count=3, lookup_exists_avg_ms=178.401, lookup_exists_p90_ms=533.857, lookup_exists_total_keys=189, lookup_exists_total_bytes=0, lookup_exists_failed_keys=0, lookup_exists_error_count=0, save_exists_count=3, save_exists_avg_ms=0.632, save_exists_p90_ms=0.656, save_exists_total_keys=189, save_exists_total_bytes=0, save_exists_failed_keys=0, save_exists_error_count=0, save_put_count=3, save_put_avg_ms=197.758, save_put_p90_ms=585.205, save_put_total_keys=189, save_put_total_bytes=9289728, save_put_failed_keys=189, save_put_error_count=0 + +# source: results/logs/vllm-writer-rdma.failed-staged-no-gpudirect-20260731T1700Z.log +# MC_STORE_MEMCPY=1 was set for this single-request diagnostic probe. +E0731 17:00:15.567684 1638450 rdma_context.cpp:588] Failed to register memory 0x7dc97a000000: Bad address [14] +(EngineCore pid=1611196) ERROR 07-31 17:00:15 [worker.py:1154] register_buffer failed for addr 0x7dc97a000000 len 7259742208: -600 +E0731 17:00:34.806782 1638546 transfer_task.cpp:1176] Failed to submit all transfers, error code is AddressNotRegistered +(APIServer pid=1607575) INFO 07-31 17:00:37 [metrics.py:103] KV Transfer metrics: lookup_exists_count=1, lookup_exists_avg_ms=0.608, lookup_exists_p90_ms=0.608, lookup_exists_total_keys=63, lookup_exists_total_bytes=0, lookup_exists_failed_keys=0, lookup_exists_error_count=0, save_exists_count=1, save_exists_avg_ms=0.546, save_exists_p90_ms=0.546, save_exists_total_keys=63, save_exists_total_bytes=0, save_exists_failed_keys=0, save_exists_error_count=0, save_put_count=1, save_put_avg_ms=4.845, save_put_p90_ms=4.845, save_put_total_keys=63, save_put_total_bytes=3096576, save_put_failed_keys=63, save_put_error_count=0 + +# host inspection after the probes +nvidia_peermem_loaded=false +nv_peer_mem_loaded=false +# Mooncake 0.3.12 actually defaults WITH_NVIDIA_PEERMEM to true. This run therefore +# selected the legacy ibv_reg_mr path while no peer-memory module was loaded. +# The controlled WITH_NVIDIA_PEERMEM=0 follow-up is in remote-20260801. diff --git a/src/code/issue5/results/raw/remote-20260731/node1/mooncake/requester-after-writer-rdma.txt b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/requester-after-writer-rdma.txt new file mode 100644 index 0000000..14e4bad --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/requester-after-writer-rdma.txt @@ -0,0 +1,5 @@ +2026-07-31T16:52:20+00:00 +port_xmit_data=140945339120 +port_rcv_data=350506453268 +port_xmit_packets=541036610 +port_rcv_packets=1301050564 diff --git a/src/code/issue5/results/raw/remote-20260731/node1/mooncake/requester-before-writer-rdma.txt b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/requester-before-writer-rdma.txt new file mode 100644 index 0000000..7aabb10 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/requester-before-writer-rdma.txt @@ -0,0 +1,5 @@ +2026-07-31T16:50:01+00:00 +port_xmit_data=140945339120 +port_rcv_data=350506453268 +port_xmit_packets=541036610 +port_rcv_packets=1301050564 diff --git a/src/code/issue5/results/raw/remote-20260731/node1/mooncake/vllm-reader-tcp-prometheus.txt b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/vllm-reader-tcp-prometheus.txt new file mode 100644 index 0000000..12c3c2c --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/vllm-reader-tcp-prometheus.txt @@ -0,0 +1,651 @@ +# HELP python_gc_objects_collected_total Objects collected during gc +# TYPE python_gc_objects_collected_total counter +python_gc_objects_collected_total{generation="0"} 12005.0 +python_gc_objects_collected_total{generation="1"} 1923.0 +python_gc_objects_collected_total{generation="2"} 1035.0 +# HELP python_gc_objects_uncollectable_total Uncollectable objects found during GC +# TYPE python_gc_objects_uncollectable_total counter +python_gc_objects_uncollectable_total{generation="0"} 0.0 +python_gc_objects_uncollectable_total{generation="1"} 0.0 +python_gc_objects_uncollectable_total{generation="2"} 0.0 +# HELP python_gc_collections_total Number of times this generation was collected +# TYPE python_gc_collections_total counter +python_gc_collections_total{generation="0"} 1594.0 +python_gc_collections_total{generation="1"} 145.0 +python_gc_collections_total{generation="2"} 9.0 +# HELP python_info Python platform information +# TYPE python_info gauge +python_info{implementation="CPython",major="3",minor="12",patchlevel="3",version="3.12.3"} 1.0 +# HELP process_virtual_memory_bytes Virtual memory size in bytes. +# TYPE process_virtual_memory_bytes gauge +process_virtual_memory_bytes 2.3212146688e+10 +# HELP process_resident_memory_bytes Resident memory size in bytes. +# TYPE process_resident_memory_bytes gauge +process_resident_memory_bytes 1.068744704e+09 +# HELP process_start_time_seconds Start time of the process since unix epoch in seconds. +# TYPE process_start_time_seconds gauge +process_start_time_seconds 1.78551745279e+09 +# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. +# TYPE process_cpu_seconds_total counter +process_cpu_seconds_total 26.73 +# HELP process_open_fds Number of open file descriptors. +# TYPE process_open_fds gauge +process_open_fds 51.0 +# HELP process_max_fds Maximum number of open file descriptors. +# TYPE process_max_fds gauge +process_max_fds 65535.0 +# HELP vllm:mooncake_store_operation_time_seconds Histogram of Mooncake store communication time. +# TYPE vllm:mooncake_store_operation_time_seconds histogram +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.001",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 2.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.005",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="3.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="4.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 0.002657468430697918 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.001",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.005",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="3.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="4.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +vllm:mooncake_store_operation_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.1892300397157669 +# HELP vllm:mooncake_store_operation_time_seconds_created Histogram of Mooncake store communication time. +# TYPE vllm:mooncake_store_operation_time_seconds_created gauge +vllm:mooncake_store_operation_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.7855174919197812e+09 +vllm:mooncake_store_operation_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.785517491989706e+09 +# HELP vllm:mooncake_store_operation_total Number of Mooncake store communication operations. +# TYPE vllm:mooncake_store_operation_total counter +vllm:mooncake_store_operation_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 3.0 +vllm:mooncake_store_operation_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.0 +# HELP vllm:mooncake_store_operation_created Number of Mooncake store communication operations. +# TYPE vllm:mooncake_store_operation_created gauge +vllm:mooncake_store_operation_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.785517491919882e+09 +vllm:mooncake_store_operation_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855174919898772e+09 +# HELP vllm:mooncake_store_operation_keys_total Number of Mooncake store keys touched by operations. +# TYPE vllm:mooncake_store_operation_keys_total counter +vllm:mooncake_store_operation_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 381.0 +vllm:mooncake_store_operation_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 189.0 +# HELP vllm:mooncake_store_operation_keys_created Number of Mooncake store keys touched by operations. +# TYPE vllm:mooncake_store_operation_keys_created gauge +vllm:mooncake_store_operation_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.7855174919199018e+09 +vllm:mooncake_store_operation_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855174919899065e+09 +# HELP vllm:mooncake_store_operation_bytes_total Number of bytes transferred by Mooncake store operations. +# TYPE vllm:mooncake_store_operation_bytes_total counter +vllm:mooncake_store_operation_bytes_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 0.0 +vllm:mooncake_store_operation_bytes_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 9.289728e+06 +# HELP vllm:mooncake_store_operation_bytes_created Number of bytes transferred by Mooncake store operations. +# TYPE vllm:mooncake_store_operation_bytes_created gauge +vllm:mooncake_store_operation_bytes_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.7855174919199178e+09 +vllm:mooncake_store_operation_bytes_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855174919899282e+09 +# HELP vllm:mooncake_store_operation_failed_keys_total Number of Mooncake store keys that failed in operations. +# TYPE vllm:mooncake_store_operation_failed_keys_total counter +vllm:mooncake_store_operation_failed_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 0.0 +vllm:mooncake_store_operation_failed_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +# HELP vllm:mooncake_store_operation_failed_keys_created Number of Mooncake store keys that failed in operations. +# TYPE vllm:mooncake_store_operation_failed_keys_created gauge +vllm:mooncake_store_operation_failed_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.7855174919199321e+09 +vllm:mooncake_store_operation_failed_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855174919899492e+09 +# HELP vllm:estimated_flops_per_gpu_total Estimated number of floating point operations per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_flops_per_gpu_total counter +vllm:estimated_flops_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_flops_per_gpu_created Estimated number of floating point operations per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_flops_per_gpu_created gauge +vllm:estimated_flops_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760129185e+09 +# HELP vllm:estimated_read_bytes_per_gpu_total Estimated number of bytes read from memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_read_bytes_per_gpu_total counter +vllm:estimated_read_bytes_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_read_bytes_per_gpu_created Estimated number of bytes read from memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_read_bytes_per_gpu_created gauge +vllm:estimated_read_bytes_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785517476013011e+09 +# HELP vllm:estimated_write_bytes_per_gpu_total Estimated number of bytes written to memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_write_bytes_per_gpu_total counter +vllm:estimated_write_bytes_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_write_bytes_per_gpu_created Estimated number of bytes written to memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_write_bytes_per_gpu_created gauge +vllm:estimated_write_bytes_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760130866e+09 +# HELP vllm:num_requests_running Number of requests in model execution batches. +# TYPE vllm:num_requests_running gauge +vllm:num_requests_running{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_requests_waiting Number of requests waiting to be processed. +# TYPE vllm:num_requests_waiting gauge +vllm:num_requests_waiting{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_requests_waiting_by_reason Number of waiting requests by reason. Reason labels: 'capacity' = waiting for scheduling capacity; 'deferred' = deferred by transient constraints (LoRA budget, KV transfer, blocked status). Sum of all reasons equals vllm:num_requests_waiting. +# TYPE vllm:num_requests_waiting_by_reason gauge +vllm:num_requests_waiting_by_reason{engine="0",model_name="issue5-pythia-14m-smoke",reason="capacity"} 0.0 +vllm:num_requests_waiting_by_reason{engine="0",model_name="issue5-pythia-14m-smoke",reason="deferred"} 0.0 +# HELP vllm:engine_sleep_state Engine sleep state; awake = 0 means engine is sleeping; awake = 1 means engine is awake; weights_offloaded = 1 means sleep level 1; discard_all = 1 means sleep level 2. +# TYPE vllm:engine_sleep_state gauge +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="awake"} 1.0 +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="weights_offloaded"} 0.0 +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="discard_all"} 0.0 +# HELP vllm:kv_cache_usage_perc KV-cache usage. 1 means 100 percent usage. +# TYPE vllm:kv_cache_usage_perc gauge +vllm:kv_cache_usage_perc{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prefix_cache_queries_total Prefix cache queries, in terms of number of queried tokens. +# TYPE vllm:prefix_cache_queries_total counter +vllm:prefix_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 6141.0 +# HELP vllm:prefix_cache_queries_created Prefix cache queries, in terms of number of queried tokens. +# TYPE vllm:prefix_cache_queries_created gauge +vllm:prefix_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785517476013826e+09 +# HELP vllm:prefix_cache_hits_total Prefix cache hits, in terms of number of cached tokens. +# TYPE vllm:prefix_cache_hits_total counter +vllm:prefix_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prefix_cache_hits_created Prefix cache hits, in terms of number of cached tokens. +# TYPE vllm:prefix_cache_hits_created gauge +vllm:prefix_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760138826e+09 +# HELP vllm:external_prefix_cache_queries_total External prefix cache queries from KV connector cross-instance cache sharing, in terms of number of queried tokens. +# TYPE vllm:external_prefix_cache_queries_total counter +vllm:external_prefix_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 6141.0 +# HELP vllm:external_prefix_cache_queries_created External prefix cache queries from KV connector cross-instance cache sharing, in terms of number of queried tokens. +# TYPE vllm:external_prefix_cache_queries_created gauge +vllm:external_prefix_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760139458e+09 +# HELP vllm:external_prefix_cache_hits_total External prefix cache hits from KV connector cross-instance cache sharing, in terms of number of cached tokens. +# TYPE vllm:external_prefix_cache_hits_total counter +vllm:external_prefix_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 3024.0 +# HELP vllm:external_prefix_cache_hits_created External prefix cache hits from KV connector cross-instance cache sharing, in terms of number of cached tokens. +# TYPE vllm:external_prefix_cache_hits_created gauge +vllm:external_prefix_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760139954e+09 +# HELP vllm:mm_cache_queries_total Multi-modal cache queries, in terms of number of queried items. +# TYPE vllm:mm_cache_queries_total counter +vllm:mm_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:mm_cache_queries_created Multi-modal cache queries, in terms of number of queried items. +# TYPE vllm:mm_cache_queries_created gauge +vllm:mm_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760140448e+09 +# HELP vllm:mm_cache_hits_total Multi-modal cache hits, in terms of number of cached items. +# TYPE vllm:mm_cache_hits_total counter +vllm:mm_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:mm_cache_hits_created Multi-modal cache hits, in terms of number of cached items. +# TYPE vllm:mm_cache_hits_created gauge +vllm:mm_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760141087e+09 +# HELP vllm:num_preemptions_total Cumulative number of preemption from the engine. +# TYPE vllm:num_preemptions_total counter +vllm:num_preemptions_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_preemptions_created Cumulative number of preemption from the engine. +# TYPE vllm:num_preemptions_created gauge +vllm:num_preemptions_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760141609e+09 +# HELP vllm:prompt_tokens_total Number of prefill tokens processed. +# TYPE vllm:prompt_tokens_total counter +vllm:prompt_tokens_total{engine="0",model_name="issue5-pythia-14m-smoke"} 6141.0 +# HELP vllm:prompt_tokens_created Number of prefill tokens processed. +# TYPE vllm:prompt_tokens_created gauge +vllm:prompt_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760142095e+09 +# HELP vllm:prompt_tokens_by_source_total Number of prompt tokens by source. +# TYPE vllm:prompt_tokens_by_source_total counter +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="local_compute"} 3117.0 +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="local_cache_hit"} 0.0 +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="external_kv_transfer"} 3024.0 +# HELP vllm:prompt_tokens_by_source_created Number of prompt tokens by source. +# TYPE vllm:prompt_tokens_by_source_created gauge +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="local_compute"} 1.7855174760142791e+09 +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="local_cache_hit"} 1.7855174760143056e+09 +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="external_kv_transfer"} 1.7855174760143268e+09 +# HELP vllm:prompt_tokens_cached_total Number of cached prompt tokens (local + external). +# TYPE vllm:prompt_tokens_cached_total counter +vllm:prompt_tokens_cached_total{engine="0",model_name="issue5-pythia-14m-smoke"} 3024.0 +# HELP vllm:prompt_tokens_cached_created Number of cached prompt tokens (local + external). +# TYPE vllm:prompt_tokens_cached_created gauge +vllm:prompt_tokens_cached_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760143945e+09 +# HELP vllm:generation_tokens_total Number of generation tokens processed. +# TYPE vllm:generation_tokens_total counter +vllm:generation_tokens_total{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +# HELP vllm:generation_tokens_created Number of generation tokens processed. +# TYPE vllm:generation_tokens_created gauge +vllm:generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760144658e+09 +# HELP vllm:request_success_total Count of successfully processed requests. +# TYPE vllm:request_success_total counter +vllm:request_success_total{engine="0",finished_reason="stop",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="length",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_success_total{engine="0",finished_reason="abort",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="error",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="repetition",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_success_created Count of successfully processed requests. +# TYPE vllm:request_success_created gauge +vllm:request_success_created{engine="0",finished_reason="stop",model_name="issue5-pythia-14m-smoke"} 1.7855174760145578e+09 +vllm:request_success_created{engine="0",finished_reason="length",model_name="issue5-pythia-14m-smoke"} 1.7855174760145924e+09 +vllm:request_success_created{engine="0",finished_reason="abort",model_name="issue5-pythia-14m-smoke"} 1.785517476014621e+09 +vllm:request_success_created{engine="0",finished_reason="error",model_name="issue5-pythia-14m-smoke"} 1.7855174760146477e+09 +vllm:request_success_created{engine="0",finished_reason="repetition",model_name="issue5-pythia-14m-smoke"} 1.7855174760146618e+09 +# HELP vllm:request_prompt_tokens Number of prefill tokens processed. +# TYPE vllm:request_prompt_tokens histogram +vllm:request_prompt_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prompt_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prompt_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 6141.0 +# HELP vllm:request_prompt_tokens_created Number of prefill tokens processed. +# TYPE vllm:request_prompt_tokens_created gauge +vllm:request_prompt_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760147564e+09 +# HELP vllm:request_generation_tokens Number of generation tokens processed. +# TYPE vllm:request_generation_tokens histogram +vllm:request_generation_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_generation_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +# HELP vllm:request_generation_tokens_created Number of generation tokens processed. +# TYPE vllm:request_generation_tokens_created gauge +vllm:request_generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760148838e+09 +# HELP vllm:iteration_tokens_total Histogram of number of tokens per engine_step. +# TYPE vllm:iteration_tokens_total histogram +vllm:iteration_tokens_total_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="8.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="16.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="32.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="64.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="128.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="256.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="512.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="1024.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="2048.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:iteration_tokens_total_bucket{engine="0",le="4096.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:iteration_tokens_total_bucket{engine="0",le="8192.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:iteration_tokens_total_bucket{engine="0",le="16384.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:iteration_tokens_total_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:iteration_tokens_total_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:iteration_tokens_total_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 3120.0 +# HELP vllm:iteration_tokens_total_created Histogram of number of tokens per engine_step. +# TYPE vllm:iteration_tokens_total_created gauge +vllm:iteration_tokens_total_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760149763e+09 +# HELP vllm:request_max_num_generation_tokens Histogram of maximum number of requested generation tokens. +# TYPE vllm:request_max_num_generation_tokens histogram +vllm:request_max_num_generation_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_max_num_generation_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +# HELP vllm:request_max_num_generation_tokens_created Histogram of maximum number of requested generation tokens. +# TYPE vllm:request_max_num_generation_tokens_created gauge +vllm:request_max_num_generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760150778e+09 +# HELP vllm:request_params_n Histogram of the n request parameter. +# TYPE vllm:request_params_n histogram +vllm:request_params_n_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_n_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_n_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_n_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_n_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_n_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_n_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_n_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +# HELP vllm:request_params_n_created Histogram of the n request parameter. +# TYPE vllm:request_params_n_created gauge +vllm:request_params_n_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760151577e+09 +# HELP vllm:request_params_max_tokens Histogram of the max_tokens request parameter. +# TYPE vllm:request_params_max_tokens histogram +vllm:request_params_max_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_params_max_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +# HELP vllm:request_params_max_tokens_created Histogram of the max_tokens request parameter. +# TYPE vllm:request_params_max_tokens_created gauge +vllm:request_params_max_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760152378e+09 +# HELP vllm:time_to_first_token_seconds Histogram of time to first token in seconds. +# TYPE vllm:time_to_first_token_seconds histogram +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.001",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.005",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.02",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.04",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.06",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.08",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 2.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.25",model_name="issue5-pythia-14m-smoke"} 2.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="160.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="640.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="2560.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:time_to_first_token_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.5140528678894043 +# HELP vllm:time_to_first_token_seconds_created Histogram of time to first token in seconds. +# TYPE vllm:time_to_first_token_seconds_created gauge +vllm:time_to_first_token_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760155165e+09 +# HELP vllm:inter_token_latency_seconds Histogram of inter-token latency in seconds. +# TYPE vllm:inter_token_latency_seconds histogram +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.025",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.075",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.15",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:inter_token_latency_seconds_created Histogram of inter-token latency in seconds. +# TYPE vllm:inter_token_latency_seconds_created gauge +vllm:inter_token_latency_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785517476015648e+09 +# HELP vllm:request_time_per_output_token_seconds Histogram of time_per_output_token_seconds per request. +# TYPE vllm:request_time_per_output_token_seconds histogram +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.025",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.075",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.15",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_time_per_output_token_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_time_per_output_token_seconds_created Histogram of time_per_output_token_seconds per request. +# TYPE vllm:request_time_per_output_token_seconds_created gauge +vllm:request_time_per_output_token_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760157588e+09 +# HELP vllm:e2e_request_latency_seconds Histogram of e2e request latency in seconds. +# TYPE vllm:e2e_request_latency_seconds histogram +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 2.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:e2e_request_latency_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.5140528678894043 +# HELP vllm:e2e_request_latency_seconds_created Histogram of e2e request latency in seconds. +# TYPE vllm:e2e_request_latency_seconds_created gauge +vllm:e2e_request_latency_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785517476015882e+09 +# HELP vllm:request_queue_time_seconds Histogram of time spent in WAITING phase for request. +# TYPE vllm:request_queue_time_seconds histogram +vllm:request_queue_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_queue_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.22102930210530758 +# HELP vllm:request_queue_time_seconds_created Histogram of time spent in WAITING phase for request. +# TYPE vllm:request_queue_time_seconds_created gauge +vllm:request_queue_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760159981e+09 +# HELP vllm:request_inference_time_seconds Histogram of time spent in RUNNING phase for request. +# TYPE vllm:request_inference_time_seconds histogram +vllm:request_inference_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_inference_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.22798604890704155 +# HELP vllm:request_inference_time_seconds_created Histogram of time spent in RUNNING phase for request. +# TYPE vllm:request_inference_time_seconds_created gauge +vllm:request_inference_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760161018e+09 +# HELP vllm:request_prefill_time_seconds Histogram of time spent in PREFILL phase for request. +# TYPE vllm:request_prefill_time_seconds histogram +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.22798604890704155 +# HELP vllm:request_prefill_time_seconds_created Histogram of time spent in PREFILL phase for request. +# TYPE vllm:request_prefill_time_seconds_created gauge +vllm:request_prefill_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785517476016215e+09 +# HELP vllm:request_decode_time_seconds Histogram of time spent in DECODE phase for request. +# TYPE vllm:request_decode_time_seconds histogram +vllm:request_decode_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_decode_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_decode_time_seconds_created Histogram of time spent in DECODE phase for request. +# TYPE vllm:request_decode_time_seconds_created gauge +vllm:request_decode_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760163193e+09 +# HELP vllm:request_prefill_kv_computed_tokens Histogram of new KV tokens computed during prefill (excluding cached tokens). +# TYPE vllm:request_prefill_kv_computed_tokens histogram +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_kv_computed_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 3.0 +vllm:request_prefill_kv_computed_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 3117.0 +# HELP vllm:request_prefill_kv_computed_tokens_created Histogram of new KV tokens computed during prefill (excluding cached tokens). +# TYPE vllm:request_prefill_kv_computed_tokens_created gauge +vllm:request_prefill_kv_computed_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855174760164502e+09 +# HELP vllm:cache_config_info Information of the LLMEngine CacheConfig +# TYPE vllm:cache_config_info gauge +vllm:cache_config_info{_block_size_resolved="True",block_size="16",cache_dtype="auto",calculate_kv_scales="False",enable_prefix_caching="True",engine="0",gpu_memory_utilization="0.92",hash_block_size="None",is_attention_free="False",kv_cache_dtype_skip_layers="[]",kv_cache_memory_bytes="None",kv_offloading_backend="native",kv_offloading_size="None",kv_sharing_fast_prefill="False",mamba_block_size="None",mamba_cache_dtype="auto",mamba_cache_mode="none",mamba_page_size_padded="None",mamba_ssm_cache_dtype="auto",num_cpu_blocks="None",num_gpu_blocks="886199",num_gpu_blocks_override="None",prefix_caching_hash_algo="sha256",sliding_window="None",user_specified_block_size="False",user_specified_mamba_block_size="False"} 1.0 +# HELP http_requests_total Total number of requests by method, status and handler. +# TYPE http_requests_total counter +http_requests_total{handler="/v1/completions",method="POST",status="2xx"} 3.0 +# HELP http_requests_created Total number of requests by method, status and handler. +# TYPE http_requests_created gauge +http_requests_created{handler="/v1/completions",method="POST",status="2xx"} 1.785517492192493e+09 +# HELP http_request_size_bytes Content length of incoming requests by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_request_size_bytes summary +http_request_size_bytes_count{handler="/v1/completions"} 3.0 +http_request_size_bytes_sum{handler="/v1/completions"} 36017.0 +# HELP http_request_size_bytes_created Content length of incoming requests by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_request_size_bytes_created gauge +http_request_size_bytes_created{handler="/v1/completions"} 1.7855174921925786e+09 +# HELP http_response_size_bytes Content length of outgoing responses by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_response_size_bytes summary +http_response_size_bytes_count{handler="/v1/completions"} 3.0 +http_response_size_bytes_sum{handler="/v1/completions"} 0.0 +# HELP http_response_size_bytes_created Content length of outgoing responses by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_response_size_bytes_created gauge +http_response_size_bytes_created{handler="/v1/completions"} 1.7855174921926756e+09 +# HELP http_request_duration_highr_seconds Latency with many buckets but no API specific labels. Made for more accurate percentile calculations. +# TYPE http_request_duration_highr_seconds histogram +http_request_duration_highr_seconds_bucket{le="0.01"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.025"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.05"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.075"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.1"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.25"} 2.0 +http_request_duration_highr_seconds_bucket{le="0.5"} 3.0 +http_request_duration_highr_seconds_bucket{le="0.75"} 3.0 +http_request_duration_highr_seconds_bucket{le="1.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="1.5"} 3.0 +http_request_duration_highr_seconds_bucket{le="2.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="2.5"} 3.0 +http_request_duration_highr_seconds_bucket{le="3.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="3.5"} 3.0 +http_request_duration_highr_seconds_bucket{le="4.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="4.5"} 3.0 +http_request_duration_highr_seconds_bucket{le="5.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="7.5"} 3.0 +http_request_duration_highr_seconds_bucket{le="10.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="30.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="60.0"} 3.0 +http_request_duration_highr_seconds_bucket{le="+Inf"} 3.0 +http_request_duration_highr_seconds_count 3.0 +http_request_duration_highr_seconds_sum 0.5441536149010062 +# HELP http_request_duration_highr_seconds_created Latency with many buckets but no API specific labels. Made for more accurate percentile calculations. +# TYPE http_request_duration_highr_seconds_created gauge +http_request_duration_highr_seconds_created 1.7855174761891215e+09 +# HELP http_request_duration_seconds Latency with only few buckets by handler. Made to be only used if aggregation by handler is important. +# TYPE http_request_duration_seconds histogram +http_request_duration_seconds_bucket{handler="/v1/completions",le="0.1",method="POST"} 0.0 +http_request_duration_seconds_bucket{handler="/v1/completions",le="0.5",method="POST"} 3.0 +http_request_duration_seconds_bucket{handler="/v1/completions",le="1.0",method="POST"} 3.0 +http_request_duration_seconds_bucket{handler="/v1/completions",le="+Inf",method="POST"} 3.0 +http_request_duration_seconds_count{handler="/v1/completions",method="POST"} 3.0 +http_request_duration_seconds_sum{handler="/v1/completions",method="POST"} 0.5441536149010062 +# HELP http_request_duration_seconds_created Latency with only few buckets by handler. Made to be only used if aggregation by handler is important. +# TYPE http_request_duration_seconds_created gauge +http_request_duration_seconds_created{handler="/v1/completions",method="POST"} 1.785517492192774e+09 diff --git a/src/code/issue5/results/raw/remote-20260731/node1/mooncake/vllm-reader-tcp-smoke.log b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/vllm-reader-tcp-smoke.log new file mode 100644 index 0000000..20c1a12 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260731/node1/mooncake/vllm-reader-tcp-smoke.log @@ -0,0 +1,558 @@ +(APIServer pid=1719130) INFO 07-31 17:04:21 [api_utils.py:339] +(APIServer pid=1719130) INFO 07-31 17:04:21 [api_utils.py:339] █ █ █▄ ▄█ +(APIServer pid=1719130) INFO 07-31 17:04:21 [api_utils.py:339] ▄▄ ▄█ █ █ █ ▀▄▀ █ version 0.23.0 +(APIServer pid=1719130) INFO 07-31 17:04:21 [api_utils.py:339] █▄█▀ █ █ █ █ model /mnt/sda1/yxz/pythia_test/pythia-14m_main +(APIServer pid=1719130) INFO 07-31 17:04:21 [api_utils.py:339] ▀▀ ▀▀▀▀▀ ▀▀▀▀▀ ▀ ▀ +(APIServer pid=1719130) INFO 07-31 17:04:21 [api_utils.py:339] +(APIServer pid=1719130) INFO 07-31 17:04:22 [api_utils.py:273] non-default args: {'model_tag': '/mnt/sda1/yxz/pythia_test/pythia-14m_main', 'host': '0.0.0.0', 'port': 8020, 'model': '/mnt/sda1/yxz/pythia_test/pythia-14m_main', 'dtype': 'float16', 'seed': 20260731, 'revision': 'local-config-sha256-5536386c1709fd29d9617fca802bb8f592071ac279f772b5c63a6be3db3488e2', 'tokenizer_revision': 'local-tokenizer-sha256-3cf430678137c8491ca82fb7092ee49e44ad38857fffe1e4a4a5ed860139a5b8', 'max_model_len': 2048, 'enforce_eager': True, 'served_model_name': ['issue5-pythia-14m-smoke'], 'hf_overrides': {'rope_scaling': {}}, 'kv_transfer_config': KVTransferConfig(kv_connector='MooncakeStoreConnector', engine_id='a1196e6c-c3d6-4bf4-a851-076a2b4a1c33', kv_buffer_device='cuda', kv_buffer_size=1000000000.0, kv_role='kv_consumer', kv_rank=None, kv_parallel_size=1, kv_ip='127.0.0.1', kv_port=14579, kv_connector_extra_config={}, kv_connector_module_path=None, enable_permute_local_kv=False, kv_load_failure_policy='fail')} +(APIServer pid=1719130) INFO 07-31 17:04:22 [model.py:611] Resolved architecture: GPTNeoXForCausalLM +(APIServer pid=1719130) INFO 07-31 17:04:22 [model.py:1745] Using max model len 2048 +(APIServer pid=1719130) INFO 07-31 17:04:22 [vllm.py:999] Asynchronous scheduling is enabled. +(APIServer pid=1719130) WARNING 07-31 17:04:22 [vllm.py:1055] Enforce eager set, disabling torch.compile and CUDAGraphs. This is equivalent to setting -cc.mode=none -cc.cudagraph_mode=none +(APIServer pid=1719130) WARNING 07-31 17:04:22 [vllm.py:1097] Inductor compilation was disabled by user settings, optimizations settings that are only active during inductor compilation will be ignored. +(APIServer pid=1719130) INFO 07-31 17:04:22 [kernel.py:270] Final IR op priority after setting platform defaults: IrOpPriorityConfig(rms_norm=['vllm_c', 'native'], fused_add_rms_norm=['vllm_c', 'native']) +(APIServer pid=1719130) INFO 07-31 17:04:22 [vllm.py:1273] Cudagraph is disabled under eager mode +(APIServer pid=1719130) INFO 07-31 17:04:22 [compilation.py:321] Enabled custom fusions: norm_quant, act_quant +(EngineCore pid=1722764) INFO 07-31 17:04:30 [core.py:113] Initializing a V1 LLM engine (v0.23.0) with config: model='/mnt/sda1/yxz/pythia_test/pythia-14m_main', speculative_config=None, tokenizer='/mnt/sda1/yxz/pythia_test/pythia-14m_main', skip_tokenizer_init=False, tokenizer_mode=auto, revision=local-config-sha256-5536386c1709fd29d9617fca802bb8f592071ac279f772b5c63a6be3db3488e2, tokenizer_revision=local-tokenizer-sha256-3cf430678137c8491ca82fb7092ee49e44ad38857fffe1e4a4a5ed860139a5b8, trust_remote_code=False, dtype=torch.float16, max_seq_len=2048, download_dir=None, load_format=auto, tensor_parallel_size=1, pipeline_parallel_size=1, data_parallel_size=1, decode_context_parallel_size=1, dcp_comm_backend=ag_rs, disable_custom_all_reduce=False, quantization=None, quantization_config=None, enforce_eager=True, enable_return_routed_experts=False, kv_cache_dtype=auto, device_config=cuda, structured_outputs_config=StructuredOutputsConfig(backend='auto', disable_any_whitespace=False, disable_additional_properties=False, reasoning_parser='', reasoning_parser_plugin='', enable_in_reasoning=False), observability_config=ObservabilityConfig(show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None, kv_cache_metrics=False, kv_cache_metrics_sample=0.01, cudagraph_metrics=False, enable_layerwise_nvtx_tracing=False, enable_mfu_metrics=False, enable_mm_processor_stats=False, enable_logging_iteration_details=False), seed=20260731, served_model_name=issue5-pythia-14m-smoke, enable_prefix_caching=True, enable_chunked_prefill=True, pooler_config=None, compilation_config={'mode': , 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['all'], 'ir_enable_torch_wrap': False, 'splitting_ops': [], 'compile_mm_encoder': False, 'cudagraph_mm_encoder': False, 'encoder_cudagraph_token_budgets': [], 'encoder_cudagraph_max_vision_items_per_batch': 0, 'encoder_cudagraph_max_frames_per_batch': None, 'compile_sizes': [], 'compile_ranges_endpoints': [2048], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'size_asserts': False, 'alignment_asserts': False, 'scalar_asserts': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': , 'cudagraph_num_of_warmups': 0, 'cudagraph_capture_sizes': [], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': True, 'fuse_act_quant': True, 'fuse_attn_quant': False, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False, 'fuse_rope_kvcache_cat_mla': False, 'fuse_act_padding': False}, 'max_cudagraph_capture_size': 0, 'dynamic_shapes_config': {'type': , 'evaluate_guards': False, 'assume_32_bit_indexing': False}, 'local_cache_dir': None, 'fast_moe_cold_start': False, 'static_all_moe_layers': []}, kernel_config=KernelConfig(ir_op_priority=IrOpPriorityConfig(rms_norm=['vllm_c', 'native'], fused_add_rms_norm=['vllm_c', 'native']), enable_flashinfer_autotune=True, moe_backend='auto', linear_backend='auto') +(EngineCore pid=1722764) INFO 07-31 17:04:31 [parallel_state.py:1568] world_size=1 rank=0 local_rank=0 distributed_init_method=tcp://192.168.77.3:39783 backend=nccl +(EngineCore pid=1722764) INFO 07-31 17:04:31 [parallel_state.py:1903] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank N/A, EPLB rank N/A +(EngineCore pid=1722764) INFO 07-31 17:04:32 [topk_topp_sampler.py:55] Using FlashInfer for top-p & top-k sampling. +(EngineCore pid=1722764) INFO 07-31 17:04:32 [gpu_model_runner.py:5092] Starting to load model /mnt/sda1/yxz/pythia_test/pythia-14m_main... +(EngineCore pid=1722764) INFO 07-31 17:04:32 [cuda.py:378] Using FLASH_ATTN attention backend out of potential backends: ['FLASH_ATTN', 'TRITON_ATTN', 'FLEX_ATTENTION']. +(EngineCore pid=1722764) INFO 07-31 17:04:32 [flash_attn.py:636] Using FlashAttention version 2 +(EngineCore pid=1722764) INFO 07-31 17:04:32 [weight_utils.py:922] Filesystem type for checkpoints: EXT4. Checkpoint size: 0.05 GiB. Available RAM: 387.75 GiB. +(EngineCore pid=1722764) INFO 07-31 17:04:32 [weight_utils.py:945] Auto-prefetch is disabled because the filesystem (EXT4) is not a recognized network FS (NFS/Lustre). If you want to force prefetching, start vLLM with --safetensors-load-strategy=prefetch. +(EngineCore pid=1722764) Loading safetensors checkpoint shards: 0% Completed | 0/1 [00:00, 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['all'], 'ir_enable_torch_wrap': False, 'splitting_ops': [], 'compile_mm_encoder': False, 'cudagraph_mm_encoder': False, 'encoder_cudagraph_token_budgets': [], 'encoder_cudagraph_max_vision_items_per_batch': 0, 'encoder_cudagraph_max_frames_per_batch': None, 'compile_sizes': [], 'compile_ranges_endpoints': [2048], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'size_asserts': False, 'alignment_asserts': False, 'scalar_asserts': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': , 'cudagraph_num_of_warmups': 0, 'cudagraph_capture_sizes': [], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': True, 'fuse_act_quant': True, 'fuse_attn_quant': False, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False, 'fuse_rope_kvcache_cat_mla': False, 'fuse_act_padding': False}, 'max_cudagraph_capture_size': 0, 'dynamic_shapes_config': {'type': , 'evaluate_guards': False, 'assume_32_bit_indexing': False}, 'local_cache_dir': None, 'fast_moe_cold_start': False, 'static_all_moe_layers': []}, kernel_config=KernelConfig(ir_op_priority=IrOpPriorityConfig(rms_norm=['vllm_c', 'native'], fused_add_rms_norm=['vllm_c', 'native']), enable_flashinfer_autotune=True, moe_backend='auto', linear_backend='auto') +(EngineCore pid=1690536) INFO 07-31 17:02:57 [parallel_state.py:1568] world_size=1 rank=0 local_rank=0 distributed_init_method=tcp://192.168.77.3:40629 backend=nccl +(EngineCore pid=1690536) INFO 07-31 17:02:57 [parallel_state.py:1903] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank N/A, EPLB rank N/A +(EngineCore pid=1690536) INFO 07-31 17:02:58 [topk_topp_sampler.py:55] Using FlashInfer for top-p & top-k sampling. +(EngineCore pid=1690536) INFO 07-31 17:02:58 [gpu_model_runner.py:5092] Starting to load model /mnt/sda1/yxz/pythia_test/pythia-14m_main... +(EngineCore pid=1690536) INFO 07-31 17:02:58 [cuda.py:378] Using FLASH_ATTN attention backend out of potential backends: ['FLASH_ATTN', 'TRITON_ATTN', 'FLEX_ATTENTION']. +(EngineCore pid=1690536) INFO 07-31 17:02:58 [flash_attn.py:636] Using FlashAttention version 2 +(EngineCore pid=1690536) INFO 07-31 17:02:58 [weight_utils.py:922] Filesystem type for checkpoints: EXT4. Checkpoint size: 0.05 GiB. Available RAM: 387.72 GiB. +(EngineCore pid=1690536) INFO 07-31 17:02:58 [weight_utils.py:945] Auto-prefetch is disabled because the filesystem (EXT4) is not a recognized network FS (NFS/Lustre). If you want to force prefetching, start vLLM with --safetensors-load-strategy=prefetch. +(EngineCore pid=1690536) Loading safetensors checkpoint shards: 0% Completed | 0/1 [00:00 -i` +# snapshot. Only connections from the Reader process to the Store RoCE host are +# retained; unrelated shared-host connections are deliberately excluded. +# No TCP connection to the Store owner/data-plane port 50052 was present. + +ESTAB 0 0 10.10.10.3:49478 10.10.10.7:8080 +bytes_sent:107 bytes_acked:108 bytes_received:176 + +ESTAB 0 0 10.10.10.3:49466 10.10.10.7:8080 +bytes_sent:102 bytes_acked:103 bytes_received:721 + +ESTAB 0 0 10.10.10.3:52462 10.10.10.7:8080 +bytes_sent:6704 bytes_acked:6705 bytes_received:981 + +ESTAB 0 0 10.10.10.3:58304 10.10.10.7:50051 +bytes_sent:30273 bytes_acked:30274 bytes_received:8059 + +COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME +VLLM::Eng 4171592 admin 26u IPv4 1377661514 0t0 TCP 10.10.10.3:49466->10.10.10.7:8080 (ESTABLISHED) +VLLM::Eng 4171592 admin 29u IPv4 1377634725 0t0 TCP 10.10.10.3:49478->10.10.10.7:8080 (ESTABLISHED) +VLLM::Eng 4171592 admin 104u IPv4 1377656869 0t0 TCP 10.10.10.3:58304->10.10.10.7:50051 (ESTABLISHED) +VLLM::Eng 4171592 admin 111u IPv4 1377621202 0t0 TCP 10.10.10.3:52462->10.10.10.7:8080 (ESTABLISHED) diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/recompute-requests.jsonl b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/recompute-requests.jsonl new file mode 100644 index 0000000..e4777e2 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/recompute-requests.jsonl @@ -0,0 +1 @@ +{"run_id": "pythia14m-recompute-20260801", "request_id": "budget2048-prompt2047-hit1008-seed20260731-item0", "phase": "recompute", "protocol": "recompute", "sequence_budget_tokens": 2048, "context_tokens": 2047, "max_output_tokens": 1, "target_hit_rate": 0.5, "actual_hit_rate": 0.4924279433317049, "cached_tokens": 1008, "kv_bytes": 3096576, "scheduled_at_ns": 6239881237480005, "sent_at_ns": 6239881320949647, "first_token_at_ns": 6239881391055743, "completed_at_ns": 6239881391326621, "ttft_ms": 70.106096, "status": "success", "evidence_level": "MEASURED", "output_digest": "dbd3a49d0d906b4ed9216b73330d2fb080ef2f758c12f3885068222e5e17151c", "store_get_bytes": 0, "local_cache_hit_tokens": 0, "remote_hit_evidence": "unproven_remote_hit", "error": ""} diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/remote-hit-verdict.json b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/remote-hit-verdict.json new file mode 100644 index 0000000..84e7f11 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/remote-hit-verdict.json @@ -0,0 +1,13 @@ +{ + "proven": true, + "baseline_requests": 1, + "reader_requests": 1, + "successful_reader_requests": 1, + "matching_output_digests": 1, + "expected_kv_bytes": 3096576, + "observed_store_get_bytes": 3096576, + "observed_store_get_failed_keys": 0, + "expected_cached_tokens": 1008, + "observed_external_hit_tokens": 1008, + "reasons": [] +} diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/requests/reader.jsonl b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/requests/reader.jsonl new file mode 100644 index 0000000..2d09f76 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/requests/reader.jsonl @@ -0,0 +1 @@ +{"run_id": "pythia14m-reader-rdma-peermem-20260801", "request_id": "budget2048-prompt2047-hit1008-seed20260731-item0", "phase": "reader", "protocol": "rdma", "sequence_budget_tokens": 2048, "context_tokens": 2047, "max_output_tokens": 1, "target_hit_rate": 0.5, "actual_hit_rate": 0.4924279433317049, "cached_tokens": 1008, "kv_bytes": 3096576, "scheduled_at_ns": 6239716956978868, "sent_at_ns": 6239717040484874, "first_token_at_ns": 6239717153037053, "completed_at_ns": 6239717153307092, "ttft_ms": 112.552179, "status": "success", "evidence_level": "MEASURED", "output_digest": "dbd3a49d0d906b4ed9216b73330d2fb080ef2f758c12f3885068222e5e17151c", "store_get_bytes": 0, "local_cache_hit_tokens": 0, "remote_hit_evidence": "unproven_remote_hit", "error": ""} diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/requests/writer.jsonl b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/requests/writer.jsonl new file mode 100644 index 0000000..64ff713 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/requests/writer.jsonl @@ -0,0 +1 @@ +{"run_id": "pythia14m-writer-rdma-peermem-20260801", "request_id": "budget2048-prompt2047-hit1008-seed20260731-item0", "phase": "writer", "protocol": "rdma", "sequence_budget_tokens": 2048, "context_tokens": 2047, "max_output_tokens": 1, "target_hit_rate": 0.5, "actual_hit_rate": 0.4924279433317049, "cached_tokens": 1008, "kv_bytes": 3096576, "scheduled_at_ns": 6239541786715244, "sent_at_ns": 6239542134348796, "first_token_at_ns": 6239542194212178, "completed_at_ns": 6239542194478979, "ttft_ms": 59.863382, "status": "success", "evidence_level": "MEASURED", "output_digest": "88eb5a7ed2730b8af9fcab410bb1ca9d258e493830226b57b6a5fd9f3b062563", "store_get_bytes": 0, "local_cache_hit_tokens": 0, "remote_hit_evidence": "unproven_remote_hit", "error": ""} diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-metrics-after.txt b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-metrics-after.txt new file mode 100644 index 0000000..92c5e36 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-metrics-after.txt @@ -0,0 +1,651 @@ +# HELP python_gc_objects_collected_total Objects collected during gc +# TYPE python_gc_objects_collected_total counter +python_gc_objects_collected_total{generation="0"} 11970.0 +python_gc_objects_collected_total{generation="1"} 1958.0 +python_gc_objects_collected_total{generation="2"} 1035.0 +# HELP python_gc_objects_uncollectable_total Uncollectable objects found during GC +# TYPE python_gc_objects_uncollectable_total counter +python_gc_objects_uncollectable_total{generation="0"} 0.0 +python_gc_objects_uncollectable_total{generation="1"} 0.0 +python_gc_objects_uncollectable_total{generation="2"} 0.0 +# HELP python_gc_collections_total Number of times this generation was collected +# TYPE python_gc_collections_total counter +python_gc_collections_total{generation="0"} 1595.0 +python_gc_collections_total{generation="1"} 145.0 +python_gc_collections_total{generation="2"} 9.0 +# HELP python_info Python platform information +# TYPE python_info gauge +python_info{implementation="CPython",major="3",minor="12",patchlevel="3",version="3.12.3"} 1.0 +# HELP process_virtual_memory_bytes Virtual memory size in bytes. +# TYPE process_virtual_memory_bytes gauge +process_virtual_memory_bytes 2.3208103936e+10 +# HELP process_resident_memory_bytes Resident memory size in bytes. +# TYPE process_resident_memory_bytes gauge +process_resident_memory_bytes 1.06080256e+09 +# HELP process_start_time_seconds Start time of the process since unix epoch in seconds. +# TYPE process_start_time_seconds gauge +process_start_time_seconds 1.78552487746e+09 +# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. +# TYPE process_cpu_seconds_total counter +process_cpu_seconds_total 27.04 +# HELP process_open_fds Number of open file descriptors. +# TYPE process_open_fds gauge +process_open_fds 51.0 +# HELP process_max_fds Maximum number of open file descriptors. +# TYPE process_max_fds gauge +process_max_fds 65535.0 +# HELP vllm:mooncake_store_operation_time_seconds Histogram of Mooncake store communication time. +# TYPE vllm:mooncake_store_operation_time_seconds histogram +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.001",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.005",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="3.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="4.0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 0.0008605923503637314 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.001",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.005",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="3.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="4.0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +vllm:mooncake_store_operation_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.015130529180169106 +# HELP vllm:mooncake_store_operation_time_seconds_created Histogram of Mooncake store communication time. +# TYPE vllm:mooncake_store_operation_time_seconds_created gauge +vllm:mooncake_store_operation_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.785525012335572e+09 +vllm:mooncake_store_operation_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.785525012352916e+09 +# HELP vllm:mooncake_store_operation_total Number of Mooncake store communication operations. +# TYPE vllm:mooncake_store_operation_total counter +vllm:mooncake_store_operation_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.0 +vllm:mooncake_store_operation_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.0 +# HELP vllm:mooncake_store_operation_created Number of Mooncake store communication operations. +# TYPE vllm:mooncake_store_operation_created gauge +vllm:mooncake_store_operation_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.7855250123356242e+09 +vllm:mooncake_store_operation_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855250123529582e+09 +# HELP vllm:mooncake_store_operation_keys_total Number of Mooncake store keys touched by operations. +# TYPE vllm:mooncake_store_operation_keys_total counter +vllm:mooncake_store_operation_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 127.0 +vllm:mooncake_store_operation_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 63.0 +# HELP vllm:mooncake_store_operation_keys_created Number of Mooncake store keys touched by operations. +# TYPE vllm:mooncake_store_operation_keys_created gauge +vllm:mooncake_store_operation_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.7855250123356345e+09 +vllm:mooncake_store_operation_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855250123529665e+09 +# HELP vllm:mooncake_store_operation_bytes_total Number of bytes transferred by Mooncake store operations. +# TYPE vllm:mooncake_store_operation_bytes_total counter +vllm:mooncake_store_operation_bytes_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 0.0 +vllm:mooncake_store_operation_bytes_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 3.096576e+06 +# HELP vllm:mooncake_store_operation_bytes_created Number of bytes transferred by Mooncake store operations. +# TYPE vllm:mooncake_store_operation_bytes_created gauge +vllm:mooncake_store_operation_bytes_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.7855250123356426e+09 +vllm:mooncake_store_operation_bytes_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855250123529735e+09 +# HELP vllm:mooncake_store_operation_failed_keys_total Number of Mooncake store keys that failed in operations. +# TYPE vllm:mooncake_store_operation_failed_keys_total counter +vllm:mooncake_store_operation_failed_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 0.0 +vllm:mooncake_store_operation_failed_keys_total{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 0.0 +# HELP vllm:mooncake_store_operation_failed_keys_created Number of Mooncake store keys that failed in operations. +# TYPE vllm:mooncake_store_operation_failed_keys_created gauge +vllm:mooncake_store_operation_failed_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="lookup_exists",status="ok"} 1.78552501233565e+09 +vllm:mooncake_store_operation_failed_keys_created{engine="0",model_name="issue5-pythia-14m-smoke",operation="load_get",status="ok"} 1.7855250123529801e+09 +# HELP vllm:estimated_flops_per_gpu_total Estimated number of floating point operations per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_flops_per_gpu_total counter +vllm:estimated_flops_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_flops_per_gpu_created Estimated number of floating point operations per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_flops_per_gpu_created gauge +vllm:estimated_flops_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960778322e+09 +# HELP vllm:estimated_read_bytes_per_gpu_total Estimated number of bytes read from memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_read_bytes_per_gpu_total counter +vllm:estimated_read_bytes_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_read_bytes_per_gpu_created Estimated number of bytes read from memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_read_bytes_per_gpu_created gauge +vllm:estimated_read_bytes_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960778403e+09 +# HELP vllm:estimated_write_bytes_per_gpu_total Estimated number of bytes written to memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_write_bytes_per_gpu_total counter +vllm:estimated_write_bytes_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_write_bytes_per_gpu_created Estimated number of bytes written to memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_write_bytes_per_gpu_created gauge +vllm:estimated_write_bytes_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607784803e+09 +# HELP vllm:num_requests_running Number of requests in model execution batches. +# TYPE vllm:num_requests_running gauge +vllm:num_requests_running{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_requests_waiting Number of requests waiting to be processed. +# TYPE vllm:num_requests_waiting gauge +vllm:num_requests_waiting{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_requests_waiting_by_reason Number of waiting requests by reason. Reason labels: 'capacity' = waiting for scheduling capacity; 'deferred' = deferred by transient constraints (LoRA budget, KV transfer, blocked status). Sum of all reasons equals vllm:num_requests_waiting. +# TYPE vllm:num_requests_waiting_by_reason gauge +vllm:num_requests_waiting_by_reason{engine="0",model_name="issue5-pythia-14m-smoke",reason="capacity"} 0.0 +vllm:num_requests_waiting_by_reason{engine="0",model_name="issue5-pythia-14m-smoke",reason="deferred"} 0.0 +# HELP vllm:engine_sleep_state Engine sleep state; awake = 0 means engine is sleeping; awake = 1 means engine is awake; weights_offloaded = 1 means sleep level 1; discard_all = 1 means sleep level 2. +# TYPE vllm:engine_sleep_state gauge +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="awake"} 1.0 +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="weights_offloaded"} 0.0 +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="discard_all"} 0.0 +# HELP vllm:kv_cache_usage_perc KV-cache usage. 1 means 100 percent usage. +# TYPE vllm:kv_cache_usage_perc gauge +vllm:kv_cache_usage_perc{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prefix_cache_queries_total Prefix cache queries, in terms of number of queried tokens. +# TYPE vllm:prefix_cache_queries_total counter +vllm:prefix_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 2047.0 +# HELP vllm:prefix_cache_queries_created Prefix cache queries, in terms of number of queried tokens. +# TYPE vllm:prefix_cache_queries_created gauge +vllm:prefix_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607791762e+09 +# HELP vllm:prefix_cache_hits_total Prefix cache hits, in terms of number of cached tokens. +# TYPE vllm:prefix_cache_hits_total counter +vllm:prefix_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prefix_cache_hits_created Prefix cache hits, in terms of number of cached tokens. +# TYPE vllm:prefix_cache_hits_created gauge +vllm:prefix_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607792332e+09 +# HELP vllm:external_prefix_cache_queries_total External prefix cache queries from KV connector cross-instance cache sharing, in terms of number of queried tokens. +# TYPE vllm:external_prefix_cache_queries_total counter +vllm:external_prefix_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 2047.0 +# HELP vllm:external_prefix_cache_queries_created External prefix cache queries from KV connector cross-instance cache sharing, in terms of number of queried tokens. +# TYPE vllm:external_prefix_cache_queries_created gauge +vllm:external_prefix_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960780887e+09 +# HELP vllm:external_prefix_cache_hits_total External prefix cache hits from KV connector cross-instance cache sharing, in terms of number of cached tokens. +# TYPE vllm:external_prefix_cache_hits_total counter +vllm:external_prefix_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 1008.0 +# HELP vllm:external_prefix_cache_hits_created External prefix cache hits from KV connector cross-instance cache sharing, in terms of number of cached tokens. +# TYPE vllm:external_prefix_cache_hits_created gauge +vllm:external_prefix_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607809656e+09 +# HELP vllm:mm_cache_queries_total Multi-modal cache queries, in terms of number of queried items. +# TYPE vllm:mm_cache_queries_total counter +vllm:mm_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:mm_cache_queries_created Multi-modal cache queries, in terms of number of queried items. +# TYPE vllm:mm_cache_queries_created gauge +vllm:mm_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960781021e+09 +# HELP vllm:mm_cache_hits_total Multi-modal cache hits, in terms of number of cached items. +# TYPE vllm:mm_cache_hits_total counter +vllm:mm_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:mm_cache_hits_created Multi-modal cache hits, in terms of number of cached items. +# TYPE vllm:mm_cache_hits_created gauge +vllm:mm_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607810798e+09 +# HELP vllm:num_preemptions_total Cumulative number of preemption from the engine. +# TYPE vllm:num_preemptions_total counter +vllm:num_preemptions_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_preemptions_created Cumulative number of preemption from the engine. +# TYPE vllm:num_preemptions_created gauge +vllm:num_preemptions_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960781129e+09 +# HELP vllm:prompt_tokens_total Number of prefill tokens processed. +# TYPE vllm:prompt_tokens_total counter +vllm:prompt_tokens_total{engine="0",model_name="issue5-pythia-14m-smoke"} 2047.0 +# HELP vllm:prompt_tokens_created Number of prefill tokens processed. +# TYPE vllm:prompt_tokens_created gauge +vllm:prompt_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607811997e+09 +# HELP vllm:prompt_tokens_by_source_total Number of prompt tokens by source. +# TYPE vllm:prompt_tokens_by_source_total counter +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="local_compute"} 1039.0 +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="local_cache_hit"} 0.0 +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="external_kv_transfer"} 1008.0 +# HELP vllm:prompt_tokens_by_source_created Number of prompt tokens by source. +# TYPE vllm:prompt_tokens_by_source_created gauge +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="local_compute"} 1.785524960781268e+09 +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="local_cache_hit"} 1.785524960781294e+09 +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="external_kv_transfer"} 1.7855249607813153e+09 +# HELP vllm:prompt_tokens_cached_total Number of cached prompt tokens (local + external). +# TYPE vllm:prompt_tokens_cached_total counter +vllm:prompt_tokens_cached_total{engine="0",model_name="issue5-pythia-14m-smoke"} 1008.0 +# HELP vllm:prompt_tokens_cached_created Number of cached prompt tokens (local + external). +# TYPE vllm:prompt_tokens_cached_created gauge +vllm:prompt_tokens_cached_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607813666e+09 +# HELP vllm:generation_tokens_total Number of generation tokens processed. +# TYPE vllm:generation_tokens_total counter +vllm:generation_tokens_total{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +# HELP vllm:generation_tokens_created Number of generation tokens processed. +# TYPE vllm:generation_tokens_created gauge +vllm:generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607814186e+09 +# HELP vllm:request_success_total Count of successfully processed requests. +# TYPE vllm:request_success_total counter +vllm:request_success_total{engine="0",finished_reason="stop",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="length",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_success_total{engine="0",finished_reason="abort",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="error",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="repetition",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_success_created Count of successfully processed requests. +# TYPE vllm:request_success_created gauge +vllm:request_success_created{engine="0",finished_reason="stop",model_name="issue5-pythia-14m-smoke"} 1.7855249607815242e+09 +vllm:request_success_created{engine="0",finished_reason="length",model_name="issue5-pythia-14m-smoke"} 1.7855249607815545e+09 +vllm:request_success_created{engine="0",finished_reason="abort",model_name="issue5-pythia-14m-smoke"} 1.785524960781579e+09 +vllm:request_success_created{engine="0",finished_reason="error",model_name="issue5-pythia-14m-smoke"} 1.7855249607816014e+09 +vllm:request_success_created{engine="0",finished_reason="repetition",model_name="issue5-pythia-14m-smoke"} 1.7855249607816284e+09 +# HELP vllm:request_prompt_tokens Number of prefill tokens processed. +# TYPE vllm:request_prompt_tokens histogram +vllm:request_prompt_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prompt_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prompt_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 2047.0 +# HELP vllm:request_prompt_tokens_created Number of prefill tokens processed. +# TYPE vllm:request_prompt_tokens_created gauge +vllm:request_prompt_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607817905e+09 +# HELP vllm:request_generation_tokens Number of generation tokens processed. +# TYPE vllm:request_generation_tokens histogram +vllm:request_generation_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_generation_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +# HELP vllm:request_generation_tokens_created Number of generation tokens processed. +# TYPE vllm:request_generation_tokens_created gauge +vllm:request_generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607819853e+09 +# HELP vllm:iteration_tokens_total Histogram of number of tokens per engine_step. +# TYPE vllm:iteration_tokens_total histogram +vllm:iteration_tokens_total_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="8.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="16.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="32.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="64.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="128.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="256.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="512.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="1024.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="2048.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:iteration_tokens_total_bucket{engine="0",le="4096.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:iteration_tokens_total_bucket{engine="0",le="8192.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:iteration_tokens_total_bucket{engine="0",le="16384.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:iteration_tokens_total_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:iteration_tokens_total_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:iteration_tokens_total_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 1040.0 +# HELP vllm:iteration_tokens_total_created Histogram of number of tokens per engine_step. +# TYPE vllm:iteration_tokens_total_created gauge +vllm:iteration_tokens_total_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607821202e+09 +# HELP vllm:request_max_num_generation_tokens Histogram of maximum number of requested generation tokens. +# TYPE vllm:request_max_num_generation_tokens histogram +vllm:request_max_num_generation_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_max_num_generation_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +# HELP vllm:request_max_num_generation_tokens_created Histogram of maximum number of requested generation tokens. +# TYPE vllm:request_max_num_generation_tokens_created gauge +vllm:request_max_num_generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960782288e+09 +# HELP vllm:request_params_n Histogram of the n request parameter. +# TYPE vllm:request_params_n histogram +vllm:request_params_n_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_n_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_n_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_n_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_n_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_n_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_n_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_n_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +# HELP vllm:request_params_n_created Histogram of the n request parameter. +# TYPE vllm:request_params_n_created gauge +vllm:request_params_n_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607824104e+09 +# HELP vllm:request_params_max_tokens Histogram of the max_tokens request parameter. +# TYPE vllm:request_params_max_tokens histogram +vllm:request_params_max_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_params_max_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +# HELP vllm:request_params_max_tokens_created Histogram of the max_tokens request parameter. +# TYPE vllm:request_params_max_tokens_created gauge +vllm:request_params_max_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607825472e+09 +# HELP vllm:time_to_first_token_seconds Histogram of time to first token in seconds. +# TYPE vllm:time_to_first_token_seconds histogram +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.001",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.005",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.02",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.04",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.06",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.08",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.25",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="160.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="640.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="2560.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:time_to_first_token_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.10319781303405762 +# HELP vllm:time_to_first_token_seconds_created Histogram of time to first token in seconds. +# TYPE vllm:time_to_first_token_seconds_created gauge +vllm:time_to_first_token_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607826927e+09 +# HELP vllm:inter_token_latency_seconds Histogram of inter-token latency in seconds. +# TYPE vllm:inter_token_latency_seconds histogram +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.025",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.075",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.15",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:inter_token_latency_seconds_created Histogram of inter-token latency in seconds. +# TYPE vllm:inter_token_latency_seconds_created gauge +vllm:inter_token_latency_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607828743e+09 +# HELP vllm:request_time_per_output_token_seconds Histogram of time_per_output_token_seconds per request. +# TYPE vllm:request_time_per_output_token_seconds histogram +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.025",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.075",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.15",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_time_per_output_token_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_time_per_output_token_seconds_created Histogram of time_per_output_token_seconds per request. +# TYPE vllm:request_time_per_output_token_seconds_created gauge +vllm:request_time_per_output_token_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607830472e+09 +# HELP vllm:e2e_request_latency_seconds Histogram of e2e request latency in seconds. +# TYPE vllm:e2e_request_latency_seconds histogram +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:e2e_request_latency_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.10319781303405762 +# HELP vllm:e2e_request_latency_seconds_created Histogram of e2e request latency in seconds. +# TYPE vllm:e2e_request_latency_seconds_created gauge +vllm:e2e_request_latency_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.78552496078322e+09 +# HELP vllm:request_queue_time_seconds Histogram of time spent in WAITING phase for request. +# TYPE vllm:request_queue_time_seconds histogram +vllm:request_queue_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_queue_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.02390940673649311 +# HELP vllm:request_queue_time_seconds_created Histogram of time spent in WAITING phase for request. +# TYPE vllm:request_queue_time_seconds_created gauge +vllm:request_queue_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607833986e+09 +# HELP vllm:request_inference_time_seconds Histogram of time spent in RUNNING phase for request. +# TYPE vllm:request_inference_time_seconds histogram +vllm:request_inference_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_inference_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.06392929516732693 +# HELP vllm:request_inference_time_seconds_created Histogram of time spent in RUNNING phase for request. +# TYPE vllm:request_inference_time_seconds_created gauge +vllm:request_inference_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607835765e+09 +# HELP vllm:request_prefill_time_seconds Histogram of time spent in PREFILL phase for request. +# TYPE vllm:request_prefill_time_seconds histogram +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.06392929516732693 +# HELP vllm:request_prefill_time_seconds_created Histogram of time spent in PREFILL phase for request. +# TYPE vllm:request_prefill_time_seconds_created gauge +vllm:request_prefill_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960783908e+09 +# HELP vllm:request_decode_time_seconds Histogram of time spent in DECODE phase for request. +# TYPE vllm:request_decode_time_seconds histogram +vllm:request_decode_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_decode_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_decode_time_seconds_created Histogram of time spent in DECODE phase for request. +# TYPE vllm:request_decode_time_seconds_created gauge +vllm:request_decode_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607840912e+09 +# HELP vllm:request_prefill_kv_computed_tokens Histogram of new KV tokens computed during prefill (excluding cached tokens). +# TYPE vllm:request_prefill_kv_computed_tokens histogram +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_kv_computed_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 1.0 +vllm:request_prefill_kv_computed_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 1039.0 +# HELP vllm:request_prefill_kv_computed_tokens_created Histogram of new KV tokens computed during prefill (excluding cached tokens). +# TYPE vllm:request_prefill_kv_computed_tokens_created gauge +vllm:request_prefill_kv_computed_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607842798e+09 +# HELP vllm:cache_config_info Information of the LLMEngine CacheConfig +# TYPE vllm:cache_config_info gauge +vllm:cache_config_info{_block_size_resolved="True",block_size="16",cache_dtype="auto",calculate_kv_scales="False",enable_prefix_caching="True",engine="0",gpu_memory_utilization="0.92",hash_block_size="None",is_attention_free="False",kv_cache_dtype_skip_layers="[]",kv_cache_memory_bytes="None",kv_offloading_backend="native",kv_offloading_size="None",kv_sharing_fast_prefill="False",mamba_block_size="None",mamba_cache_dtype="auto",mamba_cache_mode="none",mamba_page_size_padded="None",mamba_ssm_cache_dtype="auto",num_cpu_blocks="None",num_gpu_blocks="886199",num_gpu_blocks_override="None",prefix_caching_hash_algo="sha256",sliding_window="None",user_specified_block_size="False",user_specified_mamba_block_size="False"} 1.0 +# HELP http_requests_total Total number of requests by method, status and handler. +# TYPE http_requests_total counter +http_requests_total{handler="/v1/completions",method="POST",status="2xx"} 1.0 +# HELP http_requests_created Total number of requests by method, status and handler. +# TYPE http_requests_created gauge +http_requests_created{handler="/v1/completions",method="POST",status="2xx"} 1.7855250124205337e+09 +# HELP http_request_size_bytes Content length of incoming requests by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_request_size_bytes summary +http_request_size_bytes_count{handler="/v1/completions"} 1.0 +http_request_size_bytes_sum{handler="/v1/completions"} 12011.0 +# HELP http_request_size_bytes_created Content length of incoming requests by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_request_size_bytes_created gauge +http_request_size_bytes_created{handler="/v1/completions"} 1.785525012420558e+09 +# HELP http_response_size_bytes Content length of outgoing responses by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_response_size_bytes summary +http_response_size_bytes_count{handler="/v1/completions"} 1.0 +http_response_size_bytes_sum{handler="/v1/completions"} 0.0 +# HELP http_response_size_bytes_created Content length of outgoing responses by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_response_size_bytes_created gauge +http_response_size_bytes_created{handler="/v1/completions"} 1.7855250124205868e+09 +# HELP http_request_duration_highr_seconds Latency with many buckets but no API specific labels. Made for more accurate percentile calculations. +# TYPE http_request_duration_highr_seconds histogram +http_request_duration_highr_seconds_bucket{le="0.01"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.025"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.05"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.075"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.1"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.25"} 1.0 +http_request_duration_highr_seconds_bucket{le="0.5"} 1.0 +http_request_duration_highr_seconds_bucket{le="0.75"} 1.0 +http_request_duration_highr_seconds_bucket{le="1.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="1.5"} 1.0 +http_request_duration_highr_seconds_bucket{le="2.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="2.5"} 1.0 +http_request_duration_highr_seconds_bucket{le="3.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="3.5"} 1.0 +http_request_duration_highr_seconds_bucket{le="4.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="4.5"} 1.0 +http_request_duration_highr_seconds_bucket{le="5.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="7.5"} 1.0 +http_request_duration_highr_seconds_bucket{le="10.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="30.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="60.0"} 1.0 +http_request_duration_highr_seconds_bucket{le="+Inf"} 1.0 +http_request_duration_highr_seconds_count 1.0 +http_request_duration_highr_seconds_sum 0.10707690753042698 +# HELP http_request_duration_highr_seconds_created Latency with many buckets but no API specific labels. Made for more accurate percentile calculations. +# TYPE http_request_duration_highr_seconds_created gauge +http_request_duration_highr_seconds_created 1.785524960963732e+09 +# HELP http_request_duration_seconds Latency with only few buckets by handler. Made to be only used if aggregation by handler is important. +# TYPE http_request_duration_seconds histogram +http_request_duration_seconds_bucket{handler="/v1/completions",le="0.1",method="POST"} 0.0 +http_request_duration_seconds_bucket{handler="/v1/completions",le="0.5",method="POST"} 1.0 +http_request_duration_seconds_bucket{handler="/v1/completions",le="1.0",method="POST"} 1.0 +http_request_duration_seconds_bucket{handler="/v1/completions",le="+Inf",method="POST"} 1.0 +http_request_duration_seconds_count{handler="/v1/completions",method="POST"} 1.0 +http_request_duration_seconds_sum{handler="/v1/completions",method="POST"} 0.10707690753042698 +# HELP http_request_duration_seconds_created Latency with only few buckets by handler. Made to be only used if aggregation by handler is important. +# TYPE http_request_duration_seconds_created gauge +http_request_duration_seconds_created{handler="/v1/completions",method="POST"} 1.7855250124206166e+09 diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-metrics-before.txt b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-metrics-before.txt new file mode 100644 index 0000000..5e725d3 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-metrics-before.txt @@ -0,0 +1,564 @@ +# HELP python_gc_objects_collected_total Objects collected during gc +# TYPE python_gc_objects_collected_total counter +python_gc_objects_collected_total{generation="0"} 11970.0 +python_gc_objects_collected_total{generation="1"} 1958.0 +python_gc_objects_collected_total{generation="2"} 1035.0 +# HELP python_gc_objects_uncollectable_total Uncollectable objects found during GC +# TYPE python_gc_objects_uncollectable_total counter +python_gc_objects_uncollectable_total{generation="0"} 0.0 +python_gc_objects_uncollectable_total{generation="1"} 0.0 +python_gc_objects_uncollectable_total{generation="2"} 0.0 +# HELP python_gc_collections_total Number of times this generation was collected +# TYPE python_gc_collections_total counter +python_gc_collections_total{generation="0"} 1594.0 +python_gc_collections_total{generation="1"} 145.0 +python_gc_collections_total{generation="2"} 9.0 +# HELP python_info Python platform information +# TYPE python_info gauge +python_info{implementation="CPython",major="3",minor="12",patchlevel="3",version="3.12.3"} 1.0 +# HELP process_virtual_memory_bytes Virtual memory size in bytes. +# TYPE process_virtual_memory_bytes gauge +process_virtual_memory_bytes 2.3208103936e+10 +# HELP process_resident_memory_bytes Resident memory size in bytes. +# TYPE process_resident_memory_bytes gauge +process_resident_memory_bytes 1.06080256e+09 +# HELP process_start_time_seconds Start time of the process since unix epoch in seconds. +# TYPE process_start_time_seconds gauge +process_start_time_seconds 1.78552487746e+09 +# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds. +# TYPE process_cpu_seconds_total counter +process_cpu_seconds_total 27.0 +# HELP process_open_fds Number of open file descriptors. +# TYPE process_open_fds gauge +process_open_fds 51.0 +# HELP process_max_fds Maximum number of open file descriptors. +# TYPE process_max_fds gauge +process_max_fds 65535.0 +# HELP vllm:mooncake_store_operation_time_seconds Histogram of Mooncake store communication time. +# TYPE vllm:mooncake_store_operation_time_seconds histogram +# HELP vllm:mooncake_store_operation_total Number of Mooncake store communication operations. +# TYPE vllm:mooncake_store_operation_total counter +# HELP vllm:mooncake_store_operation_keys_total Number of Mooncake store keys touched by operations. +# TYPE vllm:mooncake_store_operation_keys_total counter +# HELP vllm:mooncake_store_operation_bytes_total Number of bytes transferred by Mooncake store operations. +# TYPE vllm:mooncake_store_operation_bytes_total counter +# HELP vllm:mooncake_store_operation_failed_keys_total Number of Mooncake store keys that failed in operations. +# TYPE vllm:mooncake_store_operation_failed_keys_total counter +# HELP vllm:estimated_flops_per_gpu_total Estimated number of floating point operations per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_flops_per_gpu_total counter +vllm:estimated_flops_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_flops_per_gpu_created Estimated number of floating point operations per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_flops_per_gpu_created gauge +vllm:estimated_flops_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960778322e+09 +# HELP vllm:estimated_read_bytes_per_gpu_total Estimated number of bytes read from memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_read_bytes_per_gpu_total counter +vllm:estimated_read_bytes_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_read_bytes_per_gpu_created Estimated number of bytes read from memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_read_bytes_per_gpu_created gauge +vllm:estimated_read_bytes_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960778403e+09 +# HELP vllm:estimated_write_bytes_per_gpu_total Estimated number of bytes written to memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_write_bytes_per_gpu_total counter +vllm:estimated_write_bytes_per_gpu_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:estimated_write_bytes_per_gpu_created Estimated number of bytes written to memory per GPU (for Model Flops Utilization calculations). +# TYPE vllm:estimated_write_bytes_per_gpu_created gauge +vllm:estimated_write_bytes_per_gpu_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607784803e+09 +# HELP vllm:num_requests_running Number of requests in model execution batches. +# TYPE vllm:num_requests_running gauge +vllm:num_requests_running{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_requests_waiting Number of requests waiting to be processed. +# TYPE vllm:num_requests_waiting gauge +vllm:num_requests_waiting{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_requests_waiting_by_reason Number of waiting requests by reason. Reason labels: 'capacity' = waiting for scheduling capacity; 'deferred' = deferred by transient constraints (LoRA budget, KV transfer, blocked status). Sum of all reasons equals vllm:num_requests_waiting. +# TYPE vllm:num_requests_waiting_by_reason gauge +vllm:num_requests_waiting_by_reason{engine="0",model_name="issue5-pythia-14m-smoke",reason="capacity"} 0.0 +vllm:num_requests_waiting_by_reason{engine="0",model_name="issue5-pythia-14m-smoke",reason="deferred"} 0.0 +# HELP vllm:engine_sleep_state Engine sleep state; awake = 0 means engine is sleeping; awake = 1 means engine is awake; weights_offloaded = 1 means sleep level 1; discard_all = 1 means sleep level 2. +# TYPE vllm:engine_sleep_state gauge +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="awake"} 1.0 +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="weights_offloaded"} 0.0 +vllm:engine_sleep_state{engine="0",model_name="issue5-pythia-14m-smoke",sleep_state="discard_all"} 0.0 +# HELP vllm:kv_cache_usage_perc KV-cache usage. 1 means 100 percent usage. +# TYPE vllm:kv_cache_usage_perc gauge +vllm:kv_cache_usage_perc{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prefix_cache_queries_total Prefix cache queries, in terms of number of queried tokens. +# TYPE vllm:prefix_cache_queries_total counter +vllm:prefix_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prefix_cache_queries_created Prefix cache queries, in terms of number of queried tokens. +# TYPE vllm:prefix_cache_queries_created gauge +vllm:prefix_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607791762e+09 +# HELP vllm:prefix_cache_hits_total Prefix cache hits, in terms of number of cached tokens. +# TYPE vllm:prefix_cache_hits_total counter +vllm:prefix_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prefix_cache_hits_created Prefix cache hits, in terms of number of cached tokens. +# TYPE vllm:prefix_cache_hits_created gauge +vllm:prefix_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607792332e+09 +# HELP vllm:external_prefix_cache_queries_total External prefix cache queries from KV connector cross-instance cache sharing, in terms of number of queried tokens. +# TYPE vllm:external_prefix_cache_queries_total counter +vllm:external_prefix_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:external_prefix_cache_queries_created External prefix cache queries from KV connector cross-instance cache sharing, in terms of number of queried tokens. +# TYPE vllm:external_prefix_cache_queries_created gauge +vllm:external_prefix_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960780887e+09 +# HELP vllm:external_prefix_cache_hits_total External prefix cache hits from KV connector cross-instance cache sharing, in terms of number of cached tokens. +# TYPE vllm:external_prefix_cache_hits_total counter +vllm:external_prefix_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:external_prefix_cache_hits_created External prefix cache hits from KV connector cross-instance cache sharing, in terms of number of cached tokens. +# TYPE vllm:external_prefix_cache_hits_created gauge +vllm:external_prefix_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607809656e+09 +# HELP vllm:mm_cache_queries_total Multi-modal cache queries, in terms of number of queried items. +# TYPE vllm:mm_cache_queries_total counter +vllm:mm_cache_queries_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:mm_cache_queries_created Multi-modal cache queries, in terms of number of queried items. +# TYPE vllm:mm_cache_queries_created gauge +vllm:mm_cache_queries_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960781021e+09 +# HELP vllm:mm_cache_hits_total Multi-modal cache hits, in terms of number of cached items. +# TYPE vllm:mm_cache_hits_total counter +vllm:mm_cache_hits_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:mm_cache_hits_created Multi-modal cache hits, in terms of number of cached items. +# TYPE vllm:mm_cache_hits_created gauge +vllm:mm_cache_hits_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607810798e+09 +# HELP vllm:num_preemptions_total Cumulative number of preemption from the engine. +# TYPE vllm:num_preemptions_total counter +vllm:num_preemptions_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:num_preemptions_created Cumulative number of preemption from the engine. +# TYPE vllm:num_preemptions_created gauge +vllm:num_preemptions_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960781129e+09 +# HELP vllm:prompt_tokens_total Number of prefill tokens processed. +# TYPE vllm:prompt_tokens_total counter +vllm:prompt_tokens_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prompt_tokens_created Number of prefill tokens processed. +# TYPE vllm:prompt_tokens_created gauge +vllm:prompt_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607811997e+09 +# HELP vllm:prompt_tokens_by_source_total Number of prompt tokens by source. +# TYPE vllm:prompt_tokens_by_source_total counter +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="local_compute"} 0.0 +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="local_cache_hit"} 0.0 +vllm:prompt_tokens_by_source_total{engine="0",model_name="issue5-pythia-14m-smoke",source="external_kv_transfer"} 0.0 +# HELP vllm:prompt_tokens_by_source_created Number of prompt tokens by source. +# TYPE vllm:prompt_tokens_by_source_created gauge +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="local_compute"} 1.785524960781268e+09 +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="local_cache_hit"} 1.785524960781294e+09 +vllm:prompt_tokens_by_source_created{engine="0",model_name="issue5-pythia-14m-smoke",source="external_kv_transfer"} 1.7855249607813153e+09 +# HELP vllm:prompt_tokens_cached_total Number of cached prompt tokens (local + external). +# TYPE vllm:prompt_tokens_cached_total counter +vllm:prompt_tokens_cached_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:prompt_tokens_cached_created Number of cached prompt tokens (local + external). +# TYPE vllm:prompt_tokens_cached_created gauge +vllm:prompt_tokens_cached_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607813666e+09 +# HELP vllm:generation_tokens_total Number of generation tokens processed. +# TYPE vllm:generation_tokens_total counter +vllm:generation_tokens_total{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:generation_tokens_created Number of generation tokens processed. +# TYPE vllm:generation_tokens_created gauge +vllm:generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607814186e+09 +# HELP vllm:request_success_total Count of successfully processed requests. +# TYPE vllm:request_success_total counter +vllm:request_success_total{engine="0",finished_reason="stop",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="length",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="abort",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="error",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_success_total{engine="0",finished_reason="repetition",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_success_created Count of successfully processed requests. +# TYPE vllm:request_success_created gauge +vllm:request_success_created{engine="0",finished_reason="stop",model_name="issue5-pythia-14m-smoke"} 1.7855249607815242e+09 +vllm:request_success_created{engine="0",finished_reason="length",model_name="issue5-pythia-14m-smoke"} 1.7855249607815545e+09 +vllm:request_success_created{engine="0",finished_reason="abort",model_name="issue5-pythia-14m-smoke"} 1.785524960781579e+09 +vllm:request_success_created{engine="0",finished_reason="error",model_name="issue5-pythia-14m-smoke"} 1.7855249607816014e+09 +vllm:request_success_created{engine="0",finished_reason="repetition",model_name="issue5-pythia-14m-smoke"} 1.7855249607816284e+09 +# HELP vllm:request_prompt_tokens Number of prefill tokens processed. +# TYPE vllm:request_prompt_tokens histogram +vllm:request_prompt_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prompt_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_prompt_tokens_created Number of prefill tokens processed. +# TYPE vllm:request_prompt_tokens_created gauge +vllm:request_prompt_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607817905e+09 +# HELP vllm:request_generation_tokens Number of generation tokens processed. +# TYPE vllm:request_generation_tokens histogram +vllm:request_generation_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_generation_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_generation_tokens_created Number of generation tokens processed. +# TYPE vllm:request_generation_tokens_created gauge +vllm:request_generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607819853e+09 +# HELP vllm:iteration_tokens_total Histogram of number of tokens per engine_step. +# TYPE vllm:iteration_tokens_total histogram +vllm:iteration_tokens_total_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="8.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="16.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="32.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="64.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="128.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="256.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="512.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="1024.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="2048.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="4096.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="8192.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="16384.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:iteration_tokens_total_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:iteration_tokens_total_created Histogram of number of tokens per engine_step. +# TYPE vllm:iteration_tokens_total_created gauge +vllm:iteration_tokens_total_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607821202e+09 +# HELP vllm:request_max_num_generation_tokens Histogram of maximum number of requested generation tokens. +# TYPE vllm:request_max_num_generation_tokens histogram +vllm:request_max_num_generation_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_max_num_generation_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_max_num_generation_tokens_created Histogram of maximum number of requested generation tokens. +# TYPE vllm:request_max_num_generation_tokens_created gauge +vllm:request_max_num_generation_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960782288e+09 +# HELP vllm:request_params_n Histogram of the n request parameter. +# TYPE vllm:request_params_n histogram +vllm:request_params_n_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_n_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_n_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_n_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_n_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_n_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_n_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_n_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_params_n_created Histogram of the n request parameter. +# TYPE vllm:request_params_n_created gauge +vllm:request_params_n_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607824104e+09 +# HELP vllm:request_params_max_tokens Histogram of the max_tokens request parameter. +# TYPE vllm:request_params_max_tokens histogram +vllm:request_params_max_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_params_max_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_params_max_tokens_created Histogram of the max_tokens request parameter. +# TYPE vllm:request_params_max_tokens_created gauge +vllm:request_params_max_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607825472e+09 +# HELP vllm:time_to_first_token_seconds Histogram of time to first token in seconds. +# TYPE vllm:time_to_first_token_seconds histogram +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.001",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.005",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.02",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.04",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.06",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.08",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.25",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="160.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="640.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="2560.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:time_to_first_token_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:time_to_first_token_seconds_created Histogram of time to first token in seconds. +# TYPE vllm:time_to_first_token_seconds_created gauge +vllm:time_to_first_token_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607826927e+09 +# HELP vllm:inter_token_latency_seconds Histogram of inter-token latency in seconds. +# TYPE vllm:inter_token_latency_seconds histogram +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.025",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.075",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.15",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:inter_token_latency_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:inter_token_latency_seconds_created Histogram of inter-token latency in seconds. +# TYPE vllm:inter_token_latency_seconds_created gauge +vllm:inter_token_latency_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607828743e+09 +# HELP vllm:request_time_per_output_token_seconds Histogram of time_per_output_token_seconds per request. +# TYPE vllm:request_time_per_output_token_seconds histogram +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.01",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.025",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.05",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.075",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.1",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.15",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.2",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.4",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="0.75",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="7.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="80.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_time_per_output_token_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_time_per_output_token_seconds_created Histogram of time_per_output_token_seconds per request. +# TYPE vllm:request_time_per_output_token_seconds_created gauge +vllm:request_time_per_output_token_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607830472e+09 +# HELP vllm:e2e_request_latency_seconds Histogram of e2e request latency in seconds. +# TYPE vllm:e2e_request_latency_seconds histogram +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:e2e_request_latency_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:e2e_request_latency_seconds_created Histogram of e2e request latency in seconds. +# TYPE vllm:e2e_request_latency_seconds_created gauge +vllm:e2e_request_latency_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.78552496078322e+09 +# HELP vllm:request_queue_time_seconds Histogram of time spent in WAITING phase for request. +# TYPE vllm:request_queue_time_seconds histogram +vllm:request_queue_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_queue_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_queue_time_seconds_created Histogram of time spent in WAITING phase for request. +# TYPE vllm:request_queue_time_seconds_created gauge +vllm:request_queue_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607833986e+09 +# HELP vllm:request_inference_time_seconds Histogram of time spent in RUNNING phase for request. +# TYPE vllm:request_inference_time_seconds histogram +vllm:request_inference_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_inference_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_inference_time_seconds_created Histogram of time spent in RUNNING phase for request. +# TYPE vllm:request_inference_time_seconds_created gauge +vllm:request_inference_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607835765e+09 +# HELP vllm:request_prefill_time_seconds Histogram of time spent in PREFILL phase for request. +# TYPE vllm:request_prefill_time_seconds histogram +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_prefill_time_seconds_created Histogram of time spent in PREFILL phase for request. +# TYPE vllm:request_prefill_time_seconds_created gauge +vllm:request_prefill_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.785524960783908e+09 +# HELP vllm:request_decode_time_seconds Histogram of time spent in DECODE phase for request. +# TYPE vllm:request_decode_time_seconds histogram +vllm:request_decode_time_seconds_bucket{engine="0",le="0.3",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="0.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="0.8",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="2.5",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="15.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="30.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="40.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="60.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="120.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="240.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="480.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="960.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="1920.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="7680.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_decode_time_seconds_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_decode_time_seconds_created Histogram of time spent in DECODE phase for request. +# TYPE vllm:request_decode_time_seconds_created gauge +vllm:request_decode_time_seconds_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607840912e+09 +# HELP vllm:request_prefill_kv_computed_tokens Histogram of new KV tokens computed during prefill (excluding cached tokens). +# TYPE vllm:request_prefill_kv_computed_tokens histogram +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="1.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="2.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="5.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="10.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="20.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="50.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="100.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="200.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="500.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="1000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="2000.0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_bucket{engine="0",le="+Inf",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_count{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +vllm:request_prefill_kv_computed_tokens_sum{engine="0",model_name="issue5-pythia-14m-smoke"} 0.0 +# HELP vllm:request_prefill_kv_computed_tokens_created Histogram of new KV tokens computed during prefill (excluding cached tokens). +# TYPE vllm:request_prefill_kv_computed_tokens_created gauge +vllm:request_prefill_kv_computed_tokens_created{engine="0",model_name="issue5-pythia-14m-smoke"} 1.7855249607842798e+09 +# HELP vllm:cache_config_info Information of the LLMEngine CacheConfig +# TYPE vllm:cache_config_info gauge +vllm:cache_config_info{_block_size_resolved="True",block_size="16",cache_dtype="auto",calculate_kv_scales="False",enable_prefix_caching="True",engine="0",gpu_memory_utilization="0.92",hash_block_size="None",is_attention_free="False",kv_cache_dtype_skip_layers="[]",kv_cache_memory_bytes="None",kv_offloading_backend="native",kv_offloading_size="None",kv_sharing_fast_prefill="False",mamba_block_size="None",mamba_cache_dtype="auto",mamba_cache_mode="none",mamba_page_size_padded="None",mamba_ssm_cache_dtype="auto",num_cpu_blocks="None",num_gpu_blocks="886199",num_gpu_blocks_override="None",prefix_caching_hash_algo="sha256",sliding_window="None",user_specified_block_size="False",user_specified_mamba_block_size="False"} 1.0 +# HELP http_requests_total Total number of requests by method, status and handler. +# TYPE http_requests_total counter +# HELP http_request_size_bytes Content length of incoming requests by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_request_size_bytes summary +# HELP http_response_size_bytes Content length of outgoing responses by handler. Only value of header is respected. Otherwise ignored. No percentile calculated. +# TYPE http_response_size_bytes summary +# HELP http_request_duration_highr_seconds Latency with many buckets but no API specific labels. Made for more accurate percentile calculations. +# TYPE http_request_duration_highr_seconds histogram +http_request_duration_highr_seconds_bucket{le="0.01"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.025"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.05"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.075"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.1"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.25"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.5"} 0.0 +http_request_duration_highr_seconds_bucket{le="0.75"} 0.0 +http_request_duration_highr_seconds_bucket{le="1.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="1.5"} 0.0 +http_request_duration_highr_seconds_bucket{le="2.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="2.5"} 0.0 +http_request_duration_highr_seconds_bucket{le="3.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="3.5"} 0.0 +http_request_duration_highr_seconds_bucket{le="4.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="4.5"} 0.0 +http_request_duration_highr_seconds_bucket{le="5.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="7.5"} 0.0 +http_request_duration_highr_seconds_bucket{le="10.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="30.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="60.0"} 0.0 +http_request_duration_highr_seconds_bucket{le="+Inf"} 0.0 +http_request_duration_highr_seconds_count 0.0 +http_request_duration_highr_seconds_sum 0.0 +# HELP http_request_duration_highr_seconds_created Latency with many buckets but no API specific labels. Made for more accurate percentile calculations. +# TYPE http_request_duration_highr_seconds_created gauge +http_request_duration_highr_seconds_created 1.785524960963732e+09 +# HELP http_request_duration_seconds Latency with only few buckets by handler. Made to be only used if aggregation by handler is important. +# TYPE http_request_duration_seconds histogram diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.command b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.command new file mode 100644 index 0000000..2329dfb --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.command @@ -0,0 +1 @@ +vllm serve /mnt/sda1/yxz/pythia_test/pythia-14m_main --host 0.0.0.0 --port 8020 --served-model-name issue5-pythia-14m-smoke --revision local-config-sha256-5536386c1709fd29d9617fca802bb8f592071ac279f772b5c63a6be3db3488e2 --tokenizer-revision local-tokenizer-sha256-3cf430678137c8491ca82fb7092ee49e44ad38857fffe1e4a4a5ed860139a5b8 --tensor-parallel-size 1 --max-model-len 2048 --dtype float16 --seed 20260731 --hf-overrides \{\"rope_scaling\":\{\}\} --safetensors-load-strategy eager --enforce-eager --kv-transfer-config \{\"kv_connector\":\"MooncakeStoreConnector\"\,\"kv_role\":\"kv_consumer\"\} diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.environment.json b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.environment.json new file mode 100644 index 0000000..5e4debc --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.environment.json @@ -0,0 +1,15 @@ +{ + "CUDA_VISIBLE_DEVICES": "0", + "HF_HOME": "/mnt/sda1/admin/hpn-issue5/hf-home", + "ISSUE5_ENFORCE_EAGER": "1", + "ISSUE5_MODEL_CONFIG": "/mnt/sda1/admin/hpn-issue5/results/runtime/model-pythia14m-smoke.resolved.yaml", + "ISSUE5_RDMA_GPU_REGISTRATION": "peermem", + "ISSUE5_READER_GPUS": "0", + "ISSUE5_SAFETENSORS_LOAD_STRATEGY": "eager", + "MC_TE_METRIC": "1", + "MOONCAKE_REQUESTER_HOST": "10.10.10.3", + "MOONCAKE_STORE_HOST": "10.10.10.7", + "PYTHONHASHSEED": "0", + "VLLM_MOONCAKE_STORE_TIER_LOG": "1", + "WITH_NVIDIA_PEERMEM": "1" +} diff --git a/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.log b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.log new file mode 100644 index 0000000..e50f189 --- /dev/null +++ b/src/code/issue5/results/raw/remote-20260801-peermem-smoke/node1/vllm-reader-rdma.log @@ -0,0 +1,125 @@ +(APIServer pid=4158209) INFO 07-31 19:08:40 [api_utils.py:339] +(APIServer pid=4158209) INFO 07-31 19:08:40 [api_utils.py:339] █ █ █▄ ▄█ +(APIServer pid=4158209) INFO 07-31 19:08:40 [api_utils.py:339] ▄▄ ▄█ █ █ █ ▀▄▀ █ version 0.23.0 +(APIServer pid=4158209) INFO 07-31 19:08:40 [api_utils.py:339] █▄█▀ █ █ █ █ model /mnt/sda1/yxz/pythia_test/pythia-14m_main +(APIServer pid=4158209) INFO 07-31 19:08:40 [api_utils.py:339] ▀▀ ▀▀▀▀▀ ▀▀▀▀▀ ▀ ▀ +(APIServer pid=4158209) INFO 07-31 19:08:40 [api_utils.py:339] +(APIServer pid=4158209) INFO 07-31 19:08:40 [api_utils.py:273] non-default args: {'model_tag': '/mnt/sda1/yxz/pythia_test/pythia-14m_main', 'host': '0.0.0.0', 'port': 8020, 'model': '/mnt/sda1/yxz/pythia_test/pythia-14m_main', 'dtype': 'float16', 'seed': 20260731, 'revision': 'local-config-sha256-5536386c1709fd29d9617fca802bb8f592071ac279f772b5c63a6be3db3488e2', 'tokenizer_revision': 'local-tokenizer-sha256-3cf430678137c8491ca82fb7092ee49e44ad38857fffe1e4a4a5ed860139a5b8', 'max_model_len': 2048, 'enforce_eager': True, 'served_model_name': ['issue5-pythia-14m-smoke'], 'hf_overrides': {'rope_scaling': {}}, 'safetensors_load_strategy': 'eager', 'kv_transfer_config': KVTransferConfig(kv_connector='MooncakeStoreConnector', engine_id='dc0aaef7-2252-48b2-907d-7ae827b9b1eb', kv_buffer_device='cuda', kv_buffer_size=1000000000.0, kv_role='kv_consumer', kv_rank=None, kv_parallel_size=1, kv_ip='127.0.0.1', kv_port=14579, kv_connector_extra_config={}, kv_connector_module_path=None, enable_permute_local_kv=False, kv_load_failure_policy='fail')} +(APIServer pid=4158209) INFO 07-31 19:08:40 [model.py:611] Resolved architecture: GPTNeoXForCausalLM +(APIServer pid=4158209) INFO 07-31 19:08:40 [model.py:1745] Using max model len 2048 +(APIServer pid=4158209) INFO 07-31 19:08:40 [vllm.py:999] Asynchronous scheduling is enabled. +(APIServer pid=4158209) WARNING 07-31 19:08:40 [vllm.py:1055] Enforce eager set, disabling torch.compile and CUDAGraphs. This is equivalent to setting -cc.mode=none -cc.cudagraph_mode=none +(APIServer pid=4158209) WARNING 07-31 19:08:40 [vllm.py:1097] Inductor compilation was disabled by user settings, optimizations settings that are only active during inductor compilation will be ignored. +(APIServer pid=4158209) INFO 07-31 19:08:40 [kernel.py:270] Final IR op priority after setting platform defaults: IrOpPriorityConfig(rms_norm=['vllm_c', 'native'], fused_add_rms_norm=['vllm_c', 'native']) +(APIServer pid=4158209) INFO 07-31 19:08:40 [vllm.py:1273] Cudagraph is disabled under eager mode +(APIServer pid=4158209) INFO 07-31 19:08:40 [compilation.py:321] Enabled custom fusions: norm_quant, act_quant +(EngineCore pid=4171592) INFO 07-31 19:08:48 [core.py:113] Initializing a V1 LLM engine (v0.23.0) with config: model='/mnt/sda1/yxz/pythia_test/pythia-14m_main', speculative_config=None, tokenizer='/mnt/sda1/yxz/pythia_test/pythia-14m_main', skip_tokenizer_init=False, tokenizer_mode=auto, revision=local-config-sha256-5536386c1709fd29d9617fca802bb8f592071ac279f772b5c63a6be3db3488e2, tokenizer_revision=local-tokenizer-sha256-3cf430678137c8491ca82fb7092ee49e44ad38857fffe1e4a4a5ed860139a5b8, trust_remote_code=False, dtype=torch.float16, max_seq_len=2048, download_dir=None, load_format=auto, tensor_parallel_size=1, pipeline_parallel_size=1, data_parallel_size=1, decode_context_parallel_size=1, dcp_comm_backend=ag_rs, disable_custom_all_reduce=False, quantization=None, quantization_config=None, enforce_eager=True, enable_return_routed_experts=False, kv_cache_dtype=auto, device_config=cuda, structured_outputs_config=StructuredOutputsConfig(backend='auto', disable_any_whitespace=False, disable_additional_properties=False, reasoning_parser='', reasoning_parser_plugin='', enable_in_reasoning=False), observability_config=ObservabilityConfig(show_hidden_metrics_for_version=None, otlp_traces_endpoint=None, collect_detailed_traces=None, kv_cache_metrics=False, kv_cache_metrics_sample=0.01, cudagraph_metrics=False, enable_layerwise_nvtx_tracing=False, enable_mfu_metrics=False, enable_mm_processor_stats=False, enable_logging_iteration_details=False), seed=20260731, served_model_name=issue5-pythia-14m-smoke, enable_prefix_caching=True, enable_chunked_prefill=True, pooler_config=None, compilation_config={'mode': , 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['all'], 'ir_enable_torch_wrap': False, 'splitting_ops': [], 'compile_mm_encoder': False, 'cudagraph_mm_encoder': False, 'encoder_cudagraph_token_budgets': [], 'encoder_cudagraph_max_vision_items_per_batch': 0, 'encoder_cudagraph_max_frames_per_batch': None, 'compile_sizes': [], 'compile_ranges_endpoints': [2048], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'size_asserts': False, 'alignment_asserts': False, 'scalar_asserts': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': , 'cudagraph_num_of_warmups': 0, 'cudagraph_capture_sizes': [], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': True, 'fuse_act_quant': True, 'fuse_attn_quant': False, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False, 'fuse_rope_kvcache_cat_mla': False, 'fuse_act_padding': False}, 'max_cudagraph_capture_size': 0, 'dynamic_shapes_config': {'type': , 'evaluate_guards': False, 'assume_32_bit_indexing': False}, 'local_cache_dir': None, 'fast_moe_cold_start': False, 'static_all_moe_layers': []}, kernel_config=KernelConfig(ir_op_priority=IrOpPriorityConfig(rms_norm=['vllm_c', 'native'], fused_add_rms_norm=['vllm_c', 'native']), enable_flashinfer_autotune=True, moe_backend='auto', linear_backend='auto') +(EngineCore pid=4171592) INFO 07-31 19:08:49 [parallel_state.py:1568] world_size=1 rank=0 local_rank=0 distributed_init_method=tcp://192.168.77.3:48011 backend=nccl +(EngineCore pid=4171592) INFO 07-31 19:08:49 [parallel_state.py:1903] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank N/A, EPLB rank N/A +(EngineCore pid=4171592) INFO 07-31 19:08:51 [topk_topp_sampler.py:55] Using FlashInfer for top-p & top-k sampling. +(EngineCore pid=4171592) INFO 07-31 19:08:51 [gpu_model_runner.py:5092] Starting to load model /mnt/sda1/yxz/pythia_test/pythia-14m_main... +(EngineCore pid=4171592) INFO 07-31 19:08:51 [cuda.py:378] Using FLASH_ATTN attention backend out of potential backends: ['FLASH_ATTN', 'TRITON_ATTN', 'FLEX_ATTENTION']. +(EngineCore pid=4171592) INFO 07-31 19:08:51 [flash_attn.py:636] Using FlashAttention version 2 +(EngineCore pid=4171592) INFO 07-31 19:08:51 [weight_utils.py:922] Filesystem type for checkpoints: EXT4. Checkpoint size: 0.05 GiB. Available RAM: 392.95 GiB. +(EngineCore pid=4171592) Loading safetensors checkpoint shards (eager): 0% Completed | 0/1 [00:00, 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['all'], 'ir_enable_torch_wrap': False, 'splitting_ops': [], 'compile_mm_encoder': False, 'cudagraph_mm_encoder': False, 'encoder_cudagraph_token_budgets': [], 'encoder_cudagraph_max_vision_items_per_batch': 0, 'encoder_cudagraph_max_frames_per_batch': None, 'compile_sizes': [], 'compile_ranges_endpoints': [2048], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'size_asserts': False, 'alignment_asserts': False, 'scalar_asserts': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': , 'cudagraph_num_of_warmups': 0, 'cudagraph_capture_sizes': [], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': True, 'fuse_act_quant': True, 'fuse_attn_quant': False, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False, 'fuse_rope_kvcache_cat_mla': False, 'fuse_act_padding': False}, 'max_cudagraph_capture_size': 0, 'dynamic_shapes_config': {'type': , 'evaluate_guards': False, 'assume_32_bit_indexing': False}, 'local_cache_dir': None, 'fast_moe_cold_start': False, 'static_all_moe_layers': []}, kernel_config=KernelConfig(ir_op_priority=IrOpPriorityConfig(rms_norm=['vllm_c', 'native'], fused_add_rms_norm=['vllm_c', 'native']), enable_flashinfer_autotune=True, moe_backend='auto', linear_backend='auto') +(EngineCore pid=56588) INFO 07-31 19:12:40 [parallel_state.py:1568] world_size=1 rank=0 local_rank=0 distributed_init_method=tcp://192.168.77.3:47601 backend=nccl +(EngineCore pid=56588) INFO 07-31 19:12:40 [parallel_state.py:1903] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank N/A, EPLB rank N/A +(EngineCore pid=56588) INFO 07-31 19:12:41 [topk_topp_sampler.py:55] Using FlashInfer for top-p & top-k sampling. +(EngineCore pid=56588) INFO 07-31 19:12:41 [gpu_model_runner.py:5092] Starting to load model /mnt/sda1/yxz/pythia_test/pythia-14m_main... +(EngineCore pid=56588) INFO 07-31 19:12:42 [cuda.py:378] Using FLASH_ATTN attention backend out of potential backends: ['FLASH_ATTN', 'TRITON_ATTN', 'FLEX_ATTENTION']. +(EngineCore pid=56588) INFO 07-31 19:12:42 [flash_attn.py:636] Using FlashAttention version 2 +(EngineCore pid=56588) INFO 07-31 19:12:42 [weight_utils.py:922] Filesystem type for checkpoints: EXT4. Checkpoint size: 0.05 GiB. Available RAM: 391.42 GiB. +(EngineCore pid=56588) Loading safetensors checkpoint shards (eager): 0% Completed | 0/1 [00:00, 'debug_dump_path': None, 'cache_dir': '', 'compile_cache_save_format': 'binary', 'backend': 'inductor', 'custom_ops': ['all'], 'ir_enable_torch_wrap': False, 'splitting_ops': [], 'compile_mm_encoder': False, 'cudagraph_mm_encoder': False, 'encoder_cudagraph_token_budgets': [], 'encoder_cudagraph_max_vision_items_per_batch': 0, 'encoder_cudagraph_max_frames_per_batch': None, 'compile_sizes': [], 'compile_ranges_endpoints': [2048], 'inductor_compile_config': {'enable_auto_functionalized_v2': False, 'size_asserts': False, 'alignment_asserts': False, 'scalar_asserts': False, 'combo_kernels': True, 'benchmark_combo_kernel': True}, 'inductor_passes': {}, 'cudagraph_mode': , 'cudagraph_num_of_warmups': 0, 'cudagraph_capture_sizes': [], 'cudagraph_copy_inputs': False, 'cudagraph_specialize_lora': True, 'use_inductor_graph_partition': False, 'pass_config': {'fuse_norm_quant': True, 'fuse_act_quant': True, 'fuse_attn_quant': False, 'enable_sp': False, 'fuse_gemm_comms': False, 'fuse_allreduce_rms': False, 'fuse_rope_kvcache_cat_mla': False, 'fuse_act_padding': False}, 'max_cudagraph_capture_size': 0, 'dynamic_shapes_config': {'type': , 'evaluate_guards': False, 'assume_32_bit_indexing': False}, 'local_cache_dir': None, 'fast_moe_cold_start': False, 'static_all_moe_layers': []}, kernel_config=KernelConfig(ir_op_priority=IrOpPriorityConfig(rms_norm=['vllm_c', 'native'], fused_add_rms_norm=['vllm_c', 'native']), enable_flashinfer_autotune=True, moe_backend='auto', linear_backend='auto') +(EngineCore pid=4131204) INFO 07-31 19:06:48 [parallel_state.py:1568] world_size=1 rank=0 local_rank=0 distributed_init_method=tcp://192.168.77.3:42871 backend=nccl +(EngineCore pid=4131204) INFO 07-31 19:06:48 [parallel_state.py:1903] rank 0 in world size 1 is assigned as DP rank 0, PP rank 0, PCP rank 0, TP rank 0, EP rank N/A, EPLB rank N/A +(EngineCore pid=4131204) INFO 07-31 19:06:49 [topk_topp_sampler.py:55] Using FlashInfer for top-p & top-k sampling. +(EngineCore pid=4131204) INFO 07-31 19:06:49 [gpu_model_runner.py:5092] Starting to load model /mnt/sda1/yxz/pythia_test/pythia-14m_main... +(EngineCore pid=4131204) INFO 07-31 19:06:49 [cuda.py:378] Using FLASH_ATTN attention backend out of potential backends: ['FLASH_ATTN', 'TRITON_ATTN', 'FLEX_ATTENTION']. +(EngineCore pid=4131204) INFO 07-31 19:06:49 [flash_attn.py:636] Using FlashAttention version 2 +(EngineCore pid=4131204) INFO 07-31 19:06:49 [weight_utils.py:922] Filesystem type for checkpoints: EXT4. Checkpoint size: 0.05 GiB. Available RAM: 391.37 GiB. +(EngineCore pid=4131204) Loading safetensors checkpoint shards (eager): 0% Completed | 0/1 [00:00 None: + result = analyze_requests(FIXTURE, measurement_s=60) + assert len(result.cells) == 1 + cell = result.cells[0] + assert cell.error_rate == pytest.approx(0.25) + assert cell.median_ttft_ms == 220 + assert cell.actual_qpm == 3 + assert set(cell.source_run_ids) == {"run-a", "run-b", "run-c", "run-d"} + paths = write_analysis(result, tmp_path) + assert paths[0].read_text(encoding="utf-8").startswith("protocol,") diff --git a/src/code/issue5/tests/test_configuration.py b/src/code/issue5/tests/test_configuration.py new file mode 100644 index 0000000..2bc012e --- /dev/null +++ b/src/code/issue5/tests/test_configuration.py @@ -0,0 +1,56 @@ +import json + +import pytest + +from kvbreak.configuration import render_mooncake_config + + +def test_runtime_config_resolves_store_and_requester_without_mutating_template( + tmp_path, +) -> None: + template = tmp_path / "template.json" + output = tmp_path / "resolved.json" + template.write_text( + json.dumps( + { + "mode": "standalone-store", + "metadata_server": "http://STORE_HOST:8080/metadata", + "master_server_address": "STORE_HOST:50051", + "global_segment_size": 0, + "protocol": "rdma", + "device_name": "mlx5_0", + } + ), + encoding="utf-8", + ) + + resolved = render_mooncake_config( + template, + output, + store_host="10.10.10.7", + requester_host="10.10.10.3", + ) + + assert resolved["metadata_server"] == "http://10.10.10.7:8080/metadata" + assert resolved["master_server_address"] == "10.10.10.7:50051" + assert resolved["local_hostname"] == "10.10.10.3" + assert resolved["preferred_segment"] == "10.10.10.7:50052" + assert json.loads(output.read_text(encoding="utf-8")) == resolved + assert "STORE_HOST" in template.read_text(encoding="utf-8") + + +def test_runtime_config_rejects_non_ip_and_same_host(tmp_path) -> None: + template = tmp_path / "template.json" + template.write_text( + '{"mode":"standalone-store","protocol":"tcp","device_name":""}', + encoding="utf-8", + ) + with pytest.raises(ValueError, match="IP address"): + render_mooncake_config(template, tmp_path / "a.json", "host", "10.10.10.3") + with pytest.raises(ValueError, match="must be distinct"): + render_mooncake_config( + template, + tmp_path / "b.json", + "10.10.10.3", + "10.10.10.3", + ) diff --git a/src/code/issue5/tests/test_evidence.py b/src/code/issue5/tests/test_evidence.py new file mode 100644 index 0000000..bf5c527 --- /dev/null +++ b/src/code/issue5/tests/test_evidence.py @@ -0,0 +1,51 @@ +from dataclasses import replace + +import pytest + +from kvbreak.evidence import DataPathEvidence, classify_data_path, remote_hit_is_proven + + +def rdma_evidence() -> DataPathEvidence: + return DataPathEvidence( + configured_protocol="rdma", + rdma_transport_loaded=True, + fallback_warning=False, + rdma_counter_delta_bytes=1_000_000, + tcp_payload_delta_bytes=0, + expected_payload_bytes=1_000_000, + cuda_memory_registered=False, + host_staging_observed=True, + ) + + +def test_single_use_and_eviction_ring_remote_hits() -> None: + common = { + "cached_tokens": 4096, + "store_get_bytes": 300_000_000, + "expected_kv_bytes": 300_000_000, + "local_cache_hit_tokens": 0, + } + assert remote_hit_is_proven(**common, reader_use_count=1, workload_mode="single_use") + assert remote_hit_is_proven( + **common, + reader_use_count=9, + workload_mode="verified_eviction_ring", + eviction_ring_size=5, + local_capacity_prefixes=4, + ) + + +def test_rdma_and_gpudirect_have_distinct_evidence() -> None: + assert classify_data_path(rdma_evidence()) == "RDMA_HOST_STAGING" + assert ( + classify_data_path( + replace(rdma_evidence(), cuda_memory_registered=True, host_staging_observed=False) + ) + == "GPUDIRECT_RDMA" + ) + assert classify_data_path(replace(rdma_evidence(), fallback_warning=True)) == "UNPROVEN_RDMA" + + +def test_invalid_evidence_is_rejected() -> None: + with pytest.raises(ValueError, match="expected_payload_bytes"): + replace(rdma_evidence(), expected_payload_bytes=0) diff --git a/src/code/issue5/tests/test_gpu_registration.py b/src/code/issue5/tests/test_gpu_registration.py new file mode 100644 index 0000000..74b8471 --- /dev/null +++ b/src/code/issue5/tests/test_gpu_registration.py @@ -0,0 +1,52 @@ +from __future__ import annotations + +import pytest + +from kvbreak.gpu_registration import GpuRegistrationCapabilities, select_registration_path + + +def capabilities( + *, + dma_buf_supported: bool = False, + gpu_direct_rdma_supported: bool = True, + nvidia_peermem_loaded: bool = False, + nv_peer_mem_loaded: bool = False, +) -> GpuRegistrationCapabilities: + return GpuRegistrationCapabilities( + dma_buf_supported=dma_buf_supported, + gpu_direct_rdma_supported=gpu_direct_rdma_supported, + nvidia_peermem_loaded=nvidia_peermem_loaded, + nv_peer_mem_loaded=nv_peer_mem_loaded, + ) + + +def test_dmabuf_selects_mooncake_non_peermem_path() -> None: + assert select_registration_path("dmabuf", capabilities(dma_buf_supported=True)) == "0" + + +def test_dmabuf_rejects_gpu_without_dmabuf_support() -> None: + with pytest.raises(ValueError, match="DMA-BUF"): + select_registration_path("dmabuf", capabilities(dma_buf_supported=False)) + + +def test_peermem_selects_legacy_path_when_module_is_loaded() -> None: + assert select_registration_path("peermem", capabilities(nvidia_peermem_loaded=True)) == "1" + + +def test_peermem_rejects_host_without_loaded_module() -> None: + with pytest.raises(ValueError, match="nvidia-peermem"): + select_registration_path("peermem", capabilities()) + + +@pytest.mark.parametrize("mode", ["", "auto", "legacy", "DMABUF"]) +def test_registration_mode_must_be_explicit_and_canonical(mode: str) -> None: + with pytest.raises(ValueError, match="dmabuf or peermem"): + select_registration_path(mode, capabilities(dma_buf_supported=True)) + + +def test_both_paths_reject_gpu_without_gpudirect_rdma() -> None: + with pytest.raises(ValueError, match="GPUDirect RDMA"): + select_registration_path( + "dmabuf", + capabilities(dma_buf_supported=True, gpu_direct_rdma_supported=False), + ) diff --git a/src/code/issue5/tests/test_loadgen.py b/src/code/issue5/tests/test_loadgen.py new file mode 100644 index 0000000..42e9ea3 --- /dev/null +++ b/src/code/issue5/tests/test_loadgen.py @@ -0,0 +1,31 @@ +import pytest + +from benchmarks.loadgen import ( + RequestTiming, + arrival_schedule, + max_inflight, + summarize_load_point, +) + + +def test_arrival_schedule_is_open_loop() -> None: + assert arrival_schedule(offered_qps=2, count=4, start_s=10) == [10, 10.5, 11, 11.5] + + +def test_actual_concurrency_and_qpm_use_completed_requests() -> None: + timings = [ + RequestTiming("a", 0, 0, 0.1, 1.0, True), + RequestTiming("b", 0.2, 0.2, 0.4, 1.2, True), + RequestTiming("c", 0.4, 0.4, None, 1.4, False), + ] + assert max_inflight(timings) == 3 + summary = summarize_load_point(timings, measurement_s=2, slo_ms=500, max_error_rate=0.34) + assert summary.successful_requests == 2 + assert summary.actual_qpm == pytest.approx(60) + assert summary.error_rate == pytest.approx(1 / 3) + assert summary.compliant + + +def test_non_compliant_slo_is_not_reported_as_capacity() -> None: + timings = [RequestTiming("a", 0, 0, 0.6, 1, True)] + assert not summarize_load_point(timings, measurement_s=1, slo_ms=500).compliant diff --git a/src/code/issue5/tests/test_model.py b/src/code/issue5/tests/test_model.py new file mode 100644 index 0000000..9d3a0d3 --- /dev/null +++ b/src/code/issue5/tests/test_model.py @@ -0,0 +1,123 @@ +import math + +import numpy as np +import pytest + +from kvbreak.model import ( + ResourceCost, + fit_overlap_ratio, + fit_prefill_curve, + is_profitable, + kv_cache_bytes, + overlap_break_even, + overlap_cache_time, + prefill_seconds_from_flops, + resource_cost, + serial_break_even, + transformer_prefill_flops, +) + + +def test_serial_break_even_and_boundaries() -> None: + result = serial_break_even( + full_prefill_s=1, + suffix_prefill_s=0.4, + hit_rate=0.5, + kv_bytes=300_000_000, + metadata_s=0.02, + transfer_startup_s=0.01, + restore_s=0.07, + ) + assert result.bandwidth_bytes_per_s == pytest.approx(600_000_000) + assert not is_profitable(600_000_000, result) + assert is_profitable(600_000_001, result) + no_hit = serial_break_even( + full_prefill_s=1, + suffix_prefill_s=1, + hit_rate=0, + kv_bytes=0, + metadata_s=0, + transfer_startup_s=0, + restore_s=0, + ) + assert no_hit.status == "no_hit" and no_hit.bandwidth_bytes_per_s is None + never = serial_break_even( + full_prefill_s=1, + suffix_prefill_s=0.9, + hit_rate=0.1, + kv_bytes=100, + metadata_s=0.05, + transfer_startup_s=0.02, + restore_s=0.04, + ) + assert never.status == "never_profitable" and math.isinf(never.bandwidth_bytes_per_s) + + +def test_theoretical_compute_kv_bytes_and_cost() -> None: + assert ( + transformer_prefill_flops( + tokens=1, + layers=1, + hidden_size=4, + intermediate_size=8, + num_attention_heads=2, + num_key_value_heads=1, + head_dim=2, + ) + == 304 + ) + assert ( + prefill_seconds_from_flops( + prefill_flops=2_000_000_000_000, + effective_flops_per_s=1_000_000_000_000, + ) + == 2 + ) + assert ( + kv_cache_bytes( + cached_tokens=100, + layers=2, + num_key_value_heads=4, + head_dim=8, + bytes_per_element=2, + ) + == 25_600 + ) + assert resource_cost( + active_gpu_count=2, + successful_qps=4, + allocated_cpu_cores=8, + transferred_bytes=4_000_000_000, + successful_requests=4, + ) == ResourceCost(0.5, 2.0, 1.0) + + +def test_prefill_fit_and_overlap_root() -> None: + tokens = np.array([1000, 2000, 4000, 8000], dtype=float) + seconds = 2e-4 * tokens + 3e-8 * tokens**2 + curve = fit_prefill_curve(tokens, seconds) + assert curve.predict(3000) == pytest.approx(0.87) + root = overlap_break_even( + full_prefill_s=1, + suffix_prefill_s=0.5, + kv_bytes=200_000_000, + metadata_s=0.02, + transfer_startup_s=0.01, + restore_s=0.03, + overlap_ratio=0.5, + lower_bandwidth=1_000_000, + upper_bandwidth=100_000_000_000, + ) + below = overlap_cache_time(actual_bandwidth=root.bandwidth_bytes_per_s * 0.999, **root.inputs) + above = overlap_cache_time(actual_bandwidth=root.bandwidth_bytes_per_s * 1.001, **root.inputs) + assert below > 1 > above + fit = fit_overlap_ratio( + observed_cache_s=0.655, + actual_bandwidth=1_000_000_000, + suffix_prefill_s=0.5, + kv_bytes=200_000_000, + metadata_s=0.02, + transfer_startup_s=0.01, + restore_s=0.03, + ) + assert fit.status == "finite" and fit.overlap_ratio == pytest.approx(0.5) diff --git a/src/code/issue5/tests/test_network_probe.py b/src/code/issue5/tests/test_network_probe.py new file mode 100644 index 0000000..af0cfeb --- /dev/null +++ b/src/code/issue5/tests/test_network_probe.py @@ -0,0 +1,39 @@ +import socket + +import pytest + +from benchmarks.network_probe import ( + encode_frame, + recv_frame, + summarize_bandwidth, + summarize_latency_us, +) + + +def test_frame_round_trip_and_checksum_rejection() -> None: + sender, receiver = socket.socketpair() + try: + sender.sendall(encode_frame(7, b"validated payload")) + assert recv_frame(receiver) == (7, b"validated payload") + damaged = bytearray(encode_frame(8, b"payload")) + damaged[-1] ^= 1 + sender.sendall(damaged) + with pytest.raises(ValueError, match="checksum"): + recv_frame(receiver) + finally: + sender.close() + receiver.close() + + +def test_network_summaries_use_aggregate_wall_time() -> None: + bandwidth = summarize_bandwidth( + completed_bytes=[1_000_000, 1_000_000], + started_at_s=[10.0, 10.2], + completed_at_s=[11.0, 11.4], + ) + assert bandwidth["wall_s"] == pytest.approx(1.4) + assert bandwidth["bandwidth_gbit_s"] == pytest.approx(2_000_000 * 8 / 1.4 / 1e9) + + latency = summarize_latency_us([1, 2, 3, 100]) + assert latency["median_us"] == 2.5 + assert latency["p99_us"] > 3 diff --git a/src/code/issue5/tests/test_orchestration.py b/src/code/issue5/tests/test_orchestration.py new file mode 100644 index 0000000..d714433 --- /dev/null +++ b/src/code/issue5/tests/test_orchestration.py @@ -0,0 +1,106 @@ +import json +from pathlib import Path + +ROOT = Path(__file__).parents[1] + + +def load_config(name: str) -> dict[str, object]: + return json.loads((ROOT / "configs" / name).read_text(encoding="utf-8")) + + +def test_store_configs_only_change_transport_fields() -> None: + tcp = load_config("mooncake-store-tcp.json") + rdma = load_config("mooncake-store-rdma.json") + assert tcp["mode"] == rdma["mode"] == "standalone-store" + assert tcp["global_segment_size"] == rdma["global_segment_size"] == 0 + assert tcp["protocol"] == "tcp" and rdma["protocol"] == "rdma" + ignored = {"protocol", "device_name"} + assert {k: v for k, v in tcp.items() if k not in ignored} == { + k: v for k, v in rdma.items() if k not in ignored + } + assert "STORE_HOST" in tcp["metadata_server"] + + +def test_scripts_are_safe_and_pin_vllm() -> None: + scripts = list((ROOT / "orchestration").glob("*.sh")) + assert scripts + for script in scripts: + text = script.read_text(encoding="utf-8") + assert "pkill" not in text and "killall" not in text + start = (ROOT / "orchestration" / "start_vllm.sh").read_text(encoding="utf-8") + assert "10.10.10." not in start + for required in ( + "--revision", + "--tokenizer-revision", + "--hf-overrides", + "--max-model-len", + "--tensor-parallel-size", + "PYTHONHASHSEED", + "ISSUE5_WRITER_GPUS", + "ISSUE5_READER_GPUS", + "ISSUE5_RECOMPUTE_GPUS", + "ISSUE5_MODEL_CONFIG", + "ISSUE5_SAFETENSORS_LOAD_STRATEGY", + "ISSUE5_ENFORCE_EAGER", + ): + assert required in start + assert "--rope-scaling" not in start + assert "--safetensors-load-strategy" in start + assert "--enforce-eager" in start + + +def test_rdma_start_requires_an_explicit_validated_gpu_registration_path() -> None: + start = (ROOT / "orchestration" / "start_vllm.sh").read_text(encoding="utf-8") + assert "ISSUE5_RDMA_GPU_REGISTRATION" in start + assert "validate-gpu-registration" in start + assert "export WITH_NVIDIA_PEERMEM" in start + assert '[[ "$PROTOCOL" = "rdma" ]]' in start + assert "snapshot-environment" in start + assert "vllm-${ROLE}-${PROTOCOL}.environment.json" in start + + +def test_vllm_process_slot_is_checked_before_any_runtime_evidence_is_overwritten() -> None: + start = (ROOT / "orchestration" / "start_vllm.sh").read_text(encoding="utf-8") + guard = 'ensure_process_slot "vllm-${ROLE}-${PROTOCOL}"' + assert guard in start + for evidence_write in ("render-config", "snapshot-environment", ".command"): + assert start.index(guard) < start.index(evidence_write) + + +def test_gpu_indices_are_inspected_before_cuda_visibility_remaps_them() -> None: + start = (ROOT / "orchestration" / "start_vllm.sh").read_text(encoding="utf-8") + assert "unset CUDA_VISIBLE_DEVICES" in start + assert start.index("unset CUDA_VISIBLE_DEVICES") < start.index("validate-gpu-registration") + assert start.index("validate-gpu-registration") < start.index( + 'export CUDA_VISIBLE_DEVICES="$gpu_set"' + ) + + +def test_preflight_records_cuda_rdma_registration_capabilities() -> None: + preflight = (ROOT / "orchestration" / "preflight.sh").read_text(encoding="utf-8") + assert "unset CUDA_VISIBLE_DEVICES" in preflight + assert "inspect_registration_capabilities" in preflight + assert '"gpu_registration"' in preflight + + +def test_matrix_has_gate_order() -> None: + text = (ROOT / "orchestration" / "run_matrix.sh").read_text(encoding="utf-8") + gates = ["rdma_transport", "8k_smoke", "32k_matrix", "128k_single", "open_loop_load"] + positions = [text.index(f'run_gate "{gate}"') for gate in gates] + assert positions == sorted(positions) + + +def test_store_owner_separates_host_and_port_flags() -> None: + start = (ROOT / "orchestration" / "start_store.sh").read_text(encoding="utf-8") + assert '--host="$owner_host"' in start + assert '--port="$owner_port"' in start + assert '--host="$owner_host:$owner_port"' not in start + + +def test_owned_processes_use_dedicated_session_for_child_cleanup() -> None: + common = (ROOT / "orchestration" / "common.sh").read_text(encoding="utf-8") + assert "ensure_process_slot" in common + assert 'setsid "$@"' in common + assert 'kill -TERM -- "-$pid"' in common + assert 'kill -KILL -- "-$pid"' in common + assert 'pgrep -s "$pid"' in common diff --git a/src/code/issue5/tests/test_prefill_probe.py b/src/code/issue5/tests/test_prefill_probe.py new file mode 100644 index 0000000..bc4b6f1 --- /dev/null +++ b/src/code/issue5/tests/test_prefill_probe.py @@ -0,0 +1,19 @@ +from dataclasses import replace + +from benchmarks.prefill_probe import ProbeObservation, classify_probe + + +def test_probe_requires_remote_bytes_and_matching_output() -> None: + valid = ProbeObservation( + cached_tokens=4096, + store_get_bytes=300_000_000, + expected_kv_bytes=300_000_000, + reader_use_count=1, + local_cache_hit_tokens=0, + workload_mode="single_use", + expected_output_digest="abc", + actual_output_digest="abc", + ) + assert classify_probe(valid) == "success" + assert classify_probe(replace(valid, store_get_bytes=0)) == "unproven_remote_hit" + assert classify_probe(replace(valid, actual_output_digest="def")) == "output_mismatch" diff --git a/src/code/issue5/tests/test_provenance.py b/src/code/issue5/tests/test_provenance.py new file mode 100644 index 0000000..e4ac5a9 --- /dev/null +++ b/src/code/issue5/tests/test_provenance.py @@ -0,0 +1,99 @@ +import json +import subprocess +import sys +from pathlib import Path + +import pytest + +from kvbreak.provenance import ( + build_manifest, + file_sha256, + sanitize_environment, + verify_manifest, + write_json_atomic, +) + + +def test_hash_and_environment_filtering(tmp_path: Path) -> None: + path = tmp_path / "data.txt" + path.write_bytes(b"abc") + assert file_sha256(path) == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + assert sanitize_environment( + { + "MOONCAKE_PROTOCOL": "rdma", + "MOONCAKE_STORE_HOST": "10.10.10.7", + "ISSUE5_READER_GPUS": "0,1", + "ISSUE5_MODEL_CONFIG": "results/runtime/model-smoke.yaml", + "ISSUE5_SAFETENSORS_LOAD_STRATEGY": "eager", + "ISSUE5_ENFORCE_EAGER": "1", + "ISSUE5_RDMA_GPU_REGISTRATION": "peermem", + "CUDA_VISIBLE_DEVICES": "0,1", + "MC_TE_METRIC": "1", + "VLLM_MOONCAKE_STORE_TIER_LOG": "1", + "HF_TOKEN": "secret", + } + ) == { + "CUDA_VISIBLE_DEVICES": "0,1", + "ISSUE5_ENFORCE_EAGER": "1", + "ISSUE5_MODEL_CONFIG": "results/runtime/model-smoke.yaml", + "ISSUE5_RDMA_GPU_REGISTRATION": "peermem", + "ISSUE5_READER_GPUS": "0,1", + "ISSUE5_SAFETENSORS_LOAD_STRATEGY": "eager", + "MC_TE_METRIC": "1", + "MOONCAKE_PROTOCOL": "rdma", + "MOONCAKE_STORE_HOST": "10.10.10.7", + "VLLM_MOONCAKE_STORE_TIER_LOG": "1", + } + + +def test_manifest_verification_and_path_escape(tmp_path: Path) -> None: + data = tmp_path / "run" / "data.jsonl" + data.parent.mkdir() + data.write_text("{}\n", encoding="utf-8") + manifest = tmp_path / "run" / "manifest.json" + write_json_atomic(manifest, {"files": {"data.jsonl": file_sha256(data)}}) + assert verify_manifest(manifest) == [] + write_json_atomic(manifest, {"files": {"../escape": "bad"}}) + with pytest.raises(ValueError, match="escapes"): + verify_manifest(manifest) + + +def test_build_manifest_is_deterministic_and_excludes_itself(tmp_path: Path) -> None: + run = tmp_path / "run" + (run / "nested").mkdir(parents=True) + (run / "z.txt").write_text("z", encoding="utf-8") + (run / "nested" / "a.txt").write_text("a", encoding="utf-8") + manifest_path = run / "manifest.json" + manifest = build_manifest(run, manifest_path=manifest_path, metadata={"commit": "abc"}) + assert list(manifest["files"]) == ["nested/a.txt", "z.txt"] + assert manifest["metadata"] == {"commit": "abc"} + assert verify_manifest(manifest_path) == [] + + +def test_snapshot_environment_cli_writes_only_audited_keys(tmp_path: Path) -> None: + output = tmp_path / "environment.json" + environment = { + "CUDA_VISIBLE_DEVICES": "0,1", + "ISSUE5_RDMA_GPU_REGISTRATION": "peermem", + "WITH_NVIDIA_PEERMEM": "1", + "HF_TOKEN": "must-not-leak", + } + subprocess.run( + [ + sys.executable, + "-m", + "kvbreak.cli", + "snapshot-environment", + "--output", + str(output), + ], + check=True, + env=environment, + text=True, + capture_output=True, + ) + assert json.loads(output.read_text(encoding="utf-8")) == { + "CUDA_VISIBLE_DEVICES": "0,1", + "ISSUE5_RDMA_GPU_REGISTRATION": "peermem", + "WITH_NVIDIA_PEERMEM": "1", + } diff --git a/src/code/issue5/tests/test_remote_verification.py b/src/code/issue5/tests/test_remote_verification.py new file mode 100644 index 0000000..d552d60 --- /dev/null +++ b/src/code/issue5/tests/test_remote_verification.py @@ -0,0 +1,106 @@ +import json +from pathlib import Path + +from kvbreak.remote_verification import verify_remote_hit + + +def write_jsonl(path: Path, records: list[dict[str, object]]) -> None: + path.write_text( + "".join(json.dumps(record) + "\n" for record in records), + encoding="utf-8", + ) + + +def write_metrics( + path: Path, + *, + get_bytes: int = 2_000, + failed_keys: int = 0, + external_hit_tokens: int = 20, +) -> None: + labels = 'engine="0",model_name="smoke",operation="load_get",status="ok"' + path.write_text( + "\n".join( + ( + f"vllm:mooncake_store_operation_bytes_total{{{labels}}} {get_bytes}", + f"vllm:mooncake_store_operation_failed_keys_total{{{labels}}} {failed_keys}", + ( + "vllm:external_prefix_cache_hits_total" + f'{{engine="0",model_name="smoke"}} {external_hit_tokens}' + ), + ) + ) + + "\n", + encoding="utf-8", + ) + + +def records() -> tuple[list[dict[str, object]], list[dict[str, object]]]: + baseline = [ + { + "request_id": "a", + "status": "success", + "output_digest": "digest-a", + "cached_tokens": 10, + "kv_bytes": 1_000, + }, + { + "request_id": "b", + "status": "success", + "output_digest": "digest-b", + "cached_tokens": 10, + "kv_bytes": 1_000, + }, + ] + reader = [dict(record) for record in reversed(baseline)] + return baseline, reader + + +def test_remote_hit_verdict_joins_requests_and_prometheus(tmp_path: Path) -> None: + baseline_path = tmp_path / "baseline.jsonl" + reader_path = tmp_path / "reader.jsonl" + metrics_path = tmp_path / "metrics.txt" + baseline, reader = records() + write_jsonl(baseline_path, baseline) + write_jsonl(reader_path, reader) + write_metrics(metrics_path) + + verdict = verify_remote_hit( + baseline_path=baseline_path, + reader_path=reader_path, + metrics_path=metrics_path, + model_name="smoke", + ) + + assert verdict.proven + assert verdict.matching_output_digests == 2 + assert verdict.expected_kv_bytes == verdict.observed_store_get_bytes == 2_000 + assert verdict.observed_store_get_failed_keys == 0 + assert verdict.expected_cached_tokens == verdict.observed_external_hit_tokens == 20 + assert verdict.reasons == () + + +def test_remote_hit_verdict_rejects_digest_mismatch_and_short_get(tmp_path: Path) -> None: + baseline_path = tmp_path / "baseline.jsonl" + reader_path = tmp_path / "reader.jsonl" + metrics_path = tmp_path / "metrics.txt" + baseline, reader = records() + reader[0]["output_digest"] = "wrong" + write_jsonl(baseline_path, baseline) + write_jsonl(reader_path, reader) + write_metrics(metrics_path, get_bytes=100, failed_keys=1, external_hit_tokens=2) + + verdict = verify_remote_hit( + baseline_path=baseline_path, + reader_path=reader_path, + metrics_path=metrics_path, + model_name="smoke", + ) + + assert not verdict.proven + assert set(verdict.reasons) == { + "output_digest_mismatch", + "store_get_bytes_below_threshold", + "store_get_failed_keys_nonzero", + "external_hit_tokens_below_threshold", + } diff --git a/src/code/issue5/tests/test_statistics.py b/src/code/issue5/tests/test_statistics.py new file mode 100644 index 0000000..4a4861c --- /dev/null +++ b/src/code/issue5/tests/test_statistics.py @@ -0,0 +1,17 @@ +import pytest + +from kvbreak.statistics import bootstrap_ci, summarize + + +def test_summary_and_bootstrap_are_deterministic() -> None: + summary = summarize([1, 2, 3, 4, 5]) + assert summary.median == 3 + assert summary.p95 == pytest.approx(4.8) + assert bootstrap_ci([1, 2, 3, 4, 5], seed=7, iterations=500) == bootstrap_ci( + [1, 2, 3, 4, 5], seed=7, iterations=500 + ) + + +def test_empty_samples_are_rejected() -> None: + with pytest.raises(ValueError, match="non-empty"): + summarize([]) diff --git a/src/code/issue5/tests/test_store_bench.py b/src/code/issue5/tests/test_store_bench.py new file mode 100644 index 0000000..1b19274 --- /dev/null +++ b/src/code/issue5/tests/test_store_bench.py @@ -0,0 +1,9 @@ +from benchmarks.mooncake_store_bench import bandwidth_bytes_per_s, make_payload, verify_payload + + +def test_payload_and_bandwidth_are_deterministic() -> None: + payload = make_payload(1024, seed=3) + assert payload == make_payload(1024, seed=3) + assert payload != make_payload(1024, seed=4) + assert verify_payload(payload, payload) + assert bandwidth_bytes_per_s(completed_bytes=1_000_000, wall_s=0.25) == 4_000_000 diff --git a/src/code/issue5/tests/test_types.py b/src/code/issue5/tests/test_types.py new file mode 100644 index 0000000..c6eb4fd --- /dev/null +++ b/src/code/issue5/tests/test_types.py @@ -0,0 +1,35 @@ +from dataclasses import replace + +import pytest + +from kvbreak.types import EvidenceLevel, RunRecord, RunStatus + + +def valid_record() -> RunRecord: + return RunRecord( + run_id="run-001", + request_id="req-001", + protocol="rdma", + sequence_budget_tokens=8192, + context_tokens=8191, + max_output_tokens=1, + target_hit_rate=0.3, + cached_tokens=2432, + kv_bytes=139_460_608, + ttft_ms=120.0, + status=RunStatus.SUCCESS, + evidence_level=EvidenceLevel.MEASURED, + ) + + +def test_actual_hit_rate_uses_aligned_tokens() -> None: + assert valid_record().actual_hit_rate == pytest.approx(2432 / 8191) + + +def test_invalid_token_and_latency_values_are_rejected() -> None: + with pytest.raises(ValueError, match="cached_tokens"): + replace(valid_record(), cached_tokens=9000) + with pytest.raises(ValueError, match="sequence budget"): + replace(valid_record(), context_tokens=8192) + with pytest.raises(ValueError, match="ttft_ms"): + replace(valid_record(), ttft_ms=-1) diff --git a/src/code/issue5/tests/test_workload.py b/src/code/issue5/tests/test_workload.py new file mode 100644 index 0000000..d4e94ff --- /dev/null +++ b/src/code/issue5/tests/test_workload.py @@ -0,0 +1,43 @@ +import pytest + +from benchmarks.workload import ( + aligned_cached_tokens, + build_request_plan, + build_token_payload, + plan_eviction_ring, +) + + +def test_plan_and_payload_are_exact_and_reproducible() -> None: + assert aligned_cached_tokens(8191, 0.3, 16) == 2448 + plans = build_request_plan( + sequence_budget_tokens=8192, + max_output_tokens=1, + hit_rate=0.5, + count=4, + seed=17, + ) + assert len({plan.prefix_id for plan in plans}) == 4 + payload = build_token_payload(plans[0], seed=23, vocab_size=10_000) + assert len(payload.reader_prompt_token_ids) == 8191 + assert ( + payload.reader_prompt_token_ids[: plans[0].cached_tokens] == payload.writer_prompt_token_ids + ) + assert payload == build_token_payload(plans[0], seed=23, vocab_size=10_000) + + +def test_eviction_ring_must_fit_store() -> None: + ring = plan_eviction_ring( + local_capacity_tokens=32768, + cached_tokens_per_prefix=8192, + kv_bytes_per_prefix=1_000_000_000, + store_capacity_bytes=10_000_000_000, + ) + assert (ring.local_capacity_prefixes, ring.ring_size) == (4, 5) + with pytest.raises(ValueError, match="Store safe capacity"): + plan_eviction_ring( + local_capacity_tokens=32768, + cached_tokens_per_prefix=8192, + kv_bytes_per_prefix=1_000_000_000, + store_capacity_bytes=5_000_000_000, + ) diff --git a/src/code/issue5/uv.lock b/src/code/issue5/uv.lock new file mode 100644 index 0000000..b47e8d5 --- /dev/null +++ b/src/code/issue5/uv.lock @@ -0,0 +1,760 @@ +version = 1 +revision = 3 +requires-python = ">=3.10, <3.13" +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", + "python_full_version < '3.11'", +] + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, + { url = "https://files.pythonhosted.org/packages/b3/b9/ede788a0b56fc5b071639d06c33cb893f68b1178938f3425debebe2dab78/contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445", size = 269636, upload-time = "2025-04-15T17:35:54.473Z" }, + { url = "https://files.pythonhosted.org/packages/e6/75/3469f011d64b8bbfa04f709bfc23e1dd71be54d05b1b083be9f5b22750d1/contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773", size = 254636, upload-time = "2025-04-15T17:35:58.283Z" }, + { url = "https://files.pythonhosted.org/packages/8d/2f/95adb8dae08ce0ebca4fd8e7ad653159565d9739128b2d5977806656fcd2/contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1", size = 313053, upload-time = "2025-04-15T17:36:03.235Z" }, + { url = "https://files.pythonhosted.org/packages/c3/a6/8ccf97a50f31adfa36917707fe39c9a0cbc24b3bbb58185577f119736cc9/contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43", size = 352985, upload-time = "2025-04-15T17:36:08.275Z" }, + { url = "https://files.pythonhosted.org/packages/1d/b6/7925ab9b77386143f39d9c3243fdd101621b4532eb126743201160ffa7e6/contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab", size = 323750, upload-time = "2025-04-15T17:36:13.29Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f3/20c5d1ef4f4748e52d60771b8560cf00b69d5c6368b5c2e9311bcfa2a08b/contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7", size = 326246, upload-time = "2025-04-15T17:36:18.329Z" }, + { url = "https://files.pythonhosted.org/packages/8c/e5/9dae809e7e0b2d9d70c52b3d24cba134dd3dad979eb3e5e71f5df22ed1f5/contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83", size = 1308728, upload-time = "2025-04-15T17:36:33.878Z" }, + { url = "https://files.pythonhosted.org/packages/e2/4a/0058ba34aeea35c0b442ae61a4f4d4ca84d6df8f91309bc2d43bb8dd248f/contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd", size = 1375762, upload-time = "2025-04-15T17:36:51.295Z" }, + { url = "https://files.pythonhosted.org/packages/09/33/7174bdfc8b7767ef2c08ed81244762d93d5c579336fc0b51ca57b33d1b80/contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f", size = 178196, upload-time = "2025-04-15T17:36:55.002Z" }, + { url = "https://files.pythonhosted.org/packages/5e/fe/4029038b4e1c4485cef18e480b0e2cd2d755448bb071eb9977caac80b77b/contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878", size = 222017, upload-time = "2025-04-15T17:36:58.576Z" }, + { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580, upload-time = "2025-04-15T17:37:03.105Z" }, + { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530, upload-time = "2025-04-15T17:37:07.026Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688, upload-time = "2025-04-15T17:37:11.481Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331, upload-time = "2025-04-15T17:37:18.212Z" }, + { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963, upload-time = "2025-04-15T17:37:22.76Z" }, + { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681, upload-time = "2025-04-15T17:37:33.001Z" }, + { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674, upload-time = "2025-04-15T17:37:48.64Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480, upload-time = "2025-04-15T17:38:06.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489, upload-time = "2025-04-15T17:38:10.338Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042, upload-time = "2025-04-15T17:38:14.239Z" }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c0/91f1215d0d9f9f343e4773ba6c9b89e8c0cc7a64a6263f21139da639d848/contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0", size = 266807, upload-time = "2025-04-15T17:45:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729, upload-time = "2025-04-15T17:45:20.166Z" }, + { url = "https://files.pythonhosted.org/packages/87/68/7f46fb537958e87427d98a4074bcde4b67a70b04900cfc5ce29bc2f556c1/contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5", size = 221791, upload-time = "2025-04-15T17:45:24.794Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "fonttools" +version = "4.63.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/84/69/c97f2c18e0db87d2c7b15da1974dace76ae938f1cfa22e2727a648b7ed43/fonttools-4.63.0.tar.gz", hash = "sha256:caeb583deeb5168e694b65cda8b4ee62abedfa66cf88488734466f2366b9c4e0", size = 3597189, upload-time = "2026-05-14T12:04:30.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/c9/4141c90a90db20f807c7e10bfd689fe53eb8f7f4caff58ee4d4dfe46919f/fonttools-4.63.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e3297a6a4059b4acc3a1e9a8b04741f240a80044eef08ebd32e8b5bcdddce75b", size = 2884632, upload-time = "2026-05-14T12:02:38.56Z" }, + { url = "https://files.pythonhosted.org/packages/b8/46/ad12b5c10eae602d7ef814b02afa08aacbf89da917fed5b071282b7eadc2/fonttools-4.63.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1cd75a03ad8cb5bc40c90bfde68c0c47de423aa19e5c0f362b43520645eea94", size = 2429441, upload-time = "2026-05-14T12:02:41.162Z" }, + { url = "https://files.pythonhosted.org/packages/90/8f/bdca24a84c81d56fffed052229cdcff368f6e05882e526f4558891481f65/fonttools-4.63.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0425b277a59cff3d80ca42162a8de360f318438a2ac83570842a678d826d579", size = 4946346, upload-time = "2026-05-14T12:02:43.41Z" }, + { url = "https://files.pythonhosted.org/packages/04/59/a639c0e136441ee91a65b56fdf89e5d075927e7a09c559d1b0f5276577db/fonttools-4.63.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d7e5c9973aa04c95650c96e5f5ad865fbf42d62079163ecfab1e01cbc2504c22", size = 4903184, upload-time = "2026-05-14T12:02:45.742Z" }, + { url = "https://files.pythonhosted.org/packages/e6/53/91b7e0cb45b536f3da1b29ba8cbab89f27e8b986809e0b1982303a3f4eca/fonttools-4.63.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cb014d58140a38135f16064c74c652ed57aa0b75cbf8bb59cac821f7edb5334e", size = 4922967, upload-time = "2026-05-14T12:02:48.386Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b7/87439bf44e6b97c5538cd29d0b7e366a5b8ce2cc132a4134fb67fa3f2fa2/fonttools-4.63.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:032038247a96c1690f9f31e377c389383c902531b085aa4e4dabd6f57f870e69", size = 5042799, upload-time = "2026-05-14T12:02:50.424Z" }, + { url = "https://files.pythonhosted.org/packages/ad/7c/8b96c3263b89ef99cded544c0f0636686f85dbd3c211c4dceef0231fca23/fonttools-4.63.0-cp310-cp310-win32.whl", hash = "sha256:a8b33a82979e0a6a34ff435cc81317be1f95ec1ebb7a3a2d1c8a6a54f02ae44e", size = 1519704, upload-time = "2026-05-14T12:02:52.523Z" }, + { url = "https://files.pythonhosted.org/packages/e5/4d/2c2f0069970b6907de8fb5b05c5c0193cc22f717df151d1c7aef1c738f58/fonttools-4.63.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c18358a155d75034911c5ee397a5b44cd19dd325dbb8b35fb60bf421d6a72ac", size = 1568666, upload-time = "2026-05-14T12:02:54.917Z" }, + { url = "https://files.pythonhosted.org/packages/75/2b/a7f1545bdf5da69c4bda0cea2a5781f0ad2a6623e0277267672db43c5fe6/fonttools-4.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b8ae05d9eacf6081414d759c0a352769ac28ce31280d6bb8e77b03f9e3c449f", size = 2881793, upload-time = "2026-05-14T12:02:56.645Z" }, + { url = "https://files.pythonhosted.org/packages/49/50/965308c703f085f225db2886813b27e015b8b3438c350b22dd65b52c2a2c/fonttools-4.63.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79cdc9f567aec74a72918fd060283911406750cbc9fd28c1316023deb6ce31a9", size = 2428130, upload-time = "2026-05-14T12:02:58.891Z" }, + { url = "https://files.pythonhosted.org/packages/d8/38/6937fbd7f2dc3a6b48725851bc2c15ec949b9af14d9bbcb5fe83cdf9bdf9/fonttools-4.63.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c14b4fd138c4bafcca294765c547914e1aa431ae1ca94ab99d8db08c958bd3b", size = 5111952, upload-time = "2026-05-14T12:03:01.263Z" }, + { url = "https://files.pythonhosted.org/packages/0b/43/a81f20050a3115b57d62c8e781446949512eac36690dc384ccea65ff4cc1/fonttools-4.63.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d76ac49f929aecaf82d83250b8347e099d7aecba0f4726c1d9b6df3b8bb5fe18", size = 5082308, upload-time = "2026-05-14T12:03:03.211Z" }, + { url = "https://files.pythonhosted.org/packages/67/00/cdd9d4944ca6ae280d01e69cc37bde3bf663630b837a6fc6d2cd65d80e0e/fonttools-4.63.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dcf076a4474fe0d7367e5bbf5b052c7284fa1feca729c04176ce513521afd8a0", size = 5087932, upload-time = "2026-05-14T12:03:05.147Z" }, + { url = "https://files.pythonhosted.org/packages/f5/f1/0aa0dbea778c75adbef223c42019fd47d22262b905974d62d829545d485f/fonttools-4.63.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7dd683fef0663e9f0f45cf541d788d24caa3ec9db50796b588e1757d8b3bc007", size = 5213271, upload-time = "2026-05-14T12:03:07.238Z" }, + { url = "https://files.pythonhosted.org/packages/a8/99/253e4056e1f0e67b9390125a154b73b5eb73ad521bece95c004858fdeec2/fonttools-4.63.0-cp311-cp311-win32.whl", hash = "sha256:afefc1ed0a59785a7fb06ea7e1678e849c193e1e387db783579bc7b3056fcfcb", size = 2304473, upload-time = "2026-05-14T12:03:09.271Z" }, + { url = "https://files.pythonhosted.org/packages/08/60/defa5e69641db890a63be281f41345f4c33b157824eaf0b9fad3e08b0dcb/fonttools-4.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:063e08bd17bd5a90127a14123de0d6a952dbc847695fd98b63c043d58057f90c", size = 2356389, upload-time = "2026-05-14T12:03:11.53Z" }, + { url = "https://files.pythonhosted.org/packages/08/ef/b3c6b9b5be2f82416d73fe2ed2e96e2793cd80e7510bd6a17ca79cdd88ec/fonttools-4.63.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:37dd23e621e3b0aef1baa70a303b80aaf38449632cfc8fd2a55fb285bbccfc02", size = 2881131, upload-time = "2026-05-14T12:03:13.386Z" }, + { url = "https://files.pythonhosted.org/packages/44/a0/c815bea63117fa63e4e1c01f8a1110d2112fa003f838e6467094ec2432ce/fonttools-4.63.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a9faff9e0c1f76f9fd55899d2ce785832efebab37eb8ae13995853aef178bef0", size = 2426704, upload-time = "2026-05-14T12:03:15.801Z" }, + { url = "https://files.pythonhosted.org/packages/44/04/0b91d8e916e92ad1fac9e4624760baf0fd5ff2ead614c2f68fb21373f03f/fonttools-4.63.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ef3048ef05dbb552b89817713d9cac912e00d0fde4a3105c00d29e52e10c89af", size = 5044298, upload-time = "2026-05-14T12:03:18.085Z" }, + { url = "https://files.pythonhosted.org/packages/77/c7/2342da9830e3e9d4870305ca5d2091d2a83284f2953079b7bdd3b5e029d8/fonttools-4.63.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:58dc6bb86a78d782f00f9190ca02c119cf5bbe2807536e361e18d42019f877d8", size = 4999800, upload-time = "2026-05-14T12:03:20.161Z" }, + { url = "https://files.pythonhosted.org/packages/e6/6d/67fe16c48d7ce050979b33f47e0d28a318f02da030602e944c34f7a16ef3/fonttools-4.63.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ee08ebfa58f6e1aeff5697ab9582105bb620008c1caafb681e4c557e7483027b", size = 4982666, upload-time = "2026-05-14T12:03:22.87Z" }, + { url = "https://files.pythonhosted.org/packages/f2/00/3bbab338c07c71fa56269953845e92c951a61457bbbb0f1022551ea266d9/fonttools-4.63.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:27fdc65af8da6f88b9c6121c47a464cbe359fcfff7ff6fc2d37a1f395d755b78", size = 5133598, upload-time = "2026-05-14T12:03:25.168Z" }, + { url = "https://files.pythonhosted.org/packages/62/f2/aa27c7f98db5b064883dadcc5283947e81e034de42e22a33675878d98b54/fonttools-4.63.0-cp312-cp312-win32.whl", hash = "sha256:af2fd1664d00a397d75f806985ddb36282091c2131a73a6485c23b4a34722263", size = 2292575, upload-time = "2026-05-14T12:03:27.496Z" }, + { url = "https://files.pythonhosted.org/packages/87/36/cccb9bc2a6ab63d1b2980374f0dca72ce95ae267c9b4cfe77455bb70d0d4/fonttools-4.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:59ac449f8cca9b4ffa08d2e7bbadad87ce710d69d1eda5c3c1ce579baa987272", size = 2343211, upload-time = "2026-05-14T12:03:30.057Z" }, + { url = "https://files.pythonhosted.org/packages/2c/47/c99d5268f354002ce80f8d029cd9d7d872969da1de8b93d32de4dc56d6f4/fonttools-4.63.0-py3-none-any.whl", hash = "sha256:445af2eab030a16b9171ea8bdda7ebf7d96bda2df88ee182a464252f6e05e20d", size = 1164562, upload-time = "2026-05-14T12:04:29.092Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hpn-issue5-kvbreak" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "httpx" }, + { name = "matplotlib", version = "3.10.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "matplotlib", version = "3.11.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "pyyaml" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "httpx", specifier = ">=0.27,<1" }, + { name = "matplotlib", specifier = ">=3.8,<4" }, + { name = "numpy", specifier = ">=1.26,<3" }, + { name = "pytest", marker = "extra == 'dev'", specifier = ">=8,<9" }, + { name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.24,<1" }, + { name = "pyyaml", specifier = ">=6,<7" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.8,<1" }, +] +provides-extras = ["dev"] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.18" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/f8/06549565caa026e540b7e7bab5c5a90eb7ca986015f4c48dace243cd24d9/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32cc0a5365239a6ea0c6ed461e8838d053b57e397443c0ca894dcc8e388d4374", size = 122802, upload-time = "2026-03-09T13:12:37.515Z" }, + { url = "https://files.pythonhosted.org/packages/84/eb/8476a0818850c563ff343ea7c9c05dcdcbd689a38e01aa31657df01f91fa/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc0b66c1eec9021353a4b4483afb12dfd50e3669ffbb9152d6842eb34c7e29fd", size = 66216, upload-time = "2026-03-09T13:12:38.812Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/f9c8a6b4c21aed4198566e45923512986d6cef530e7263b3a5f823546561/kiwisolver-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86e0287879f75621ae85197b0877ed2f8b7aa57b511c7331dce2eb6f4de7d476", size = 63917, upload-time = "2026-03-09T13:12:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/f1/0e/ba4ae25d03722f64de8b2c13e80d82ab537a06b30fc7065183c6439357e3/kiwisolver-1.5.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62f59da443c4f4849f73a51a193b1d9d258dcad0c41bc4d1b8fb2bcc04bfeb22", size = 1628776, upload-time = "2026-03-09T13:12:41.976Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e4/3f43a011bc8a0860d1c96f84d32fa87439d3feedf66e672fef03bf5e8bac/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9190426b7aa26c5229501fa297b8d0653cfd3f5a36f7990c264e157cbf886b3b", size = 1228164, upload-time = "2026-03-09T13:12:44.002Z" }, + { url = "https://files.pythonhosted.org/packages/4b/34/3a901559a1e0c218404f9a61a93be82d45cb8f44453ba43088644980f033/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8277104ded0a51e699c8c3aff63ce2c56d4ed5519a5f73e0fd7057f959a2b9e", size = 1246656, upload-time = "2026-03-09T13:12:45.557Z" }, + { url = "https://files.pythonhosted.org/packages/87/9e/f78c466ea20527822b95ad38f141f2de1dcd7f23fb8716b002b0d91bbe59/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8f9baf6f0a6e7571c45c8863010b45e837c3ee1c2c77fcd6ef423be91b21fedb", size = 1295562, upload-time = "2026-03-09T13:12:47.562Z" }, + { url = "https://files.pythonhosted.org/packages/0a/66/fd0e4a612e3a286c24e6d6f3a5428d11258ed1909bc530ba3b59807fd980/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cff8e5383db4989311f99e814feeb90c4723eb4edca425b9d5d9c3fefcdd9537", size = 2178473, upload-time = "2026-03-09T13:12:50.254Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8e/6cac929e0049539e5ee25c1ee937556f379ba5204840d03008363ced662d/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ebae99ed6764f2b5771c522477b311be313e8841d2e0376db2b10922daebbba4", size = 2274035, upload-time = "2026-03-09T13:12:51.785Z" }, + { url = "https://files.pythonhosted.org/packages/ca/d3/9d0c18f1b52ea8074b792452cf17f1f5a56bd0302a85191f405cfbf9da16/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d5cd5189fc2b6a538b75ae45433140c4823463918f7b1617c31e68b085c0022c", size = 2443217, upload-time = "2026-03-09T13:12:53.329Z" }, + { url = "https://files.pythonhosted.org/packages/45/2a/6e19368803a038b2a90857bf4ee9e3c7b667216d045866bf22d3439fd75e/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f42c23db5d1521218a3276bb08666dcb662896a0be7347cba864eca45ff64ede", size = 2249196, upload-time = "2026-03-09T13:12:55.057Z" }, + { url = "https://files.pythonhosted.org/packages/75/2b/3f641dfcbe72e222175d626bacf2f72c3b34312afec949dd1c50afa400f5/kiwisolver-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:94eff26096eb5395136634622515b234ecb6c9979824c1f5004c6e3c3c85ccd2", size = 73389, upload-time = "2026-03-09T13:12:56.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/88/299b137b9e0025d8982e03d2d52c123b0a2b159e84b0ef1501ef446339cf/kiwisolver-1.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:dd952e03bfbb096cfe2dd35cd9e00f269969b67536cb4370994afc20ff2d0875", size = 64782, upload-time = "2026-03-09T13:12:57.609Z" }, + { url = "https://files.pythonhosted.org/packages/12/dd/a495a9c104be1c476f0386e714252caf2b7eca883915422a64c50b88c6f5/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9eed0f7edbb274413b6ee781cca50541c8c0facd3d6fd289779e494340a2b85c", size = 122798, upload-time = "2026-03-09T13:12:58.963Z" }, + { url = "https://files.pythonhosted.org/packages/11/60/37b4047a2af0cf5ef6d8b4b26e91829ae6fc6a2d1f74524bcb0e7cd28a32/kiwisolver-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c4923e404d6bcd91b6779c009542e5647fef32e4a5d75e115e3bbac6f2335eb", size = 66216, upload-time = "2026-03-09T13:13:00.155Z" }, + { url = "https://files.pythonhosted.org/packages/0a/aa/510dc933d87767584abfe03efa445889996c70c2990f6f87c3ebaa0a18c5/kiwisolver-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0df54df7e686afa55e6f21fb86195224a6d9beb71d637e8d7920c95cf0f89aac", size = 63911, upload-time = "2026-03-09T13:13:01.671Z" }, + { url = "https://files.pythonhosted.org/packages/80/46/bddc13df6c2a40741e0cc7865bb1c9ed4796b6760bd04ce5fae3928ef917/kiwisolver-1.5.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2517e24d7315eb51c10664cdb865195df38ab74456c677df67bb47f12d088a27", size = 1438209, upload-time = "2026-03-09T13:13:03.385Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d6/76621246f5165e5372f02f5e6f3f48ea336a8f9e96e43997d45b240ed8cd/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff710414307fefa903e0d9bdf300972f892c23477829f49504e59834f4195398", size = 1248888, upload-time = "2026-03-09T13:13:05.231Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c1/31559ec6fb39a5b48035ce29bb63ade628f321785f38c384dee3e2c08bc1/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6176c1811d9d5a04fa391c490cc44f451e240697a16977f11c6f722efb9041db", size = 1266304, upload-time = "2026-03-09T13:13:06.743Z" }, + { url = "https://files.pythonhosted.org/packages/5e/ef/1cb8276f2d29cc6a41e0a042f27946ca347d3a4a75acf85d0a16aa6dcc82/kiwisolver-1.5.0-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50847dca5d197fcbd389c805aa1a1cf32f25d2e7273dc47ab181a517666b68cc", size = 1319650, upload-time = "2026-03-09T13:13:08.607Z" }, + { url = "https://files.pythonhosted.org/packages/4c/e4/5ba3cecd7ce6236ae4a80f67e5d5531287337d0e1f076ca87a5abe4cd5d0/kiwisolver-1.5.0-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:01808c6d15f4c3e8559595d6d1fe6411c68e4a3822b4b9972b44473b24f4e679", size = 970949, upload-time = "2026-03-09T13:13:10.299Z" }, + { url = "https://files.pythonhosted.org/packages/5a/69/dc61f7ae9a2f071f26004ced87f078235b5507ab6e5acd78f40365655034/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f9f4121ec58628c96baa3de1a55a4e3a333c5102c8e94b64e23bf7b2083309", size = 2199125, upload-time = "2026-03-09T13:13:11.841Z" }, + { url = "https://files.pythonhosted.org/packages/e5/7b/abbe0f1b5afa85f8d084b73e90e5f801c0939eba16ac2e49af7c61a6c28d/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b7d335370ae48a780c6e6a6bbfa97342f563744c39c35562f3f367665f5c1de2", size = 2293783, upload-time = "2026-03-09T13:13:14.399Z" }, + { url = "https://files.pythonhosted.org/packages/8a/80/5908ae149d96d81580d604c7f8aefd0e98f4fd728cf172f477e9f2a81744/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:800ee55980c18545af444d93fdd60c56b580db5cc54867d8cbf8a1dc0829938c", size = 1960726, upload-time = "2026-03-09T13:13:16.047Z" }, + { url = "https://files.pythonhosted.org/packages/84/08/a78cb776f8c085b7143142ce479859cfec086bd09ee638a317040b6ef420/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c438f6ca858697c9ab67eb28246c92508af972e114cac34e57a6d4ba17a3ac08", size = 2464738, upload-time = "2026-03-09T13:13:17.897Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e1/65584da5356ed6cb12c63791a10b208860ac40a83de165cb6a6751a686e3/kiwisolver-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c63c91f95173f9c2a67c7c526b2cea976828a0e7fced9cdcead2802dc10f8a4", size = 2270718, upload-time = "2026-03-09T13:13:19.421Z" }, + { url = "https://files.pythonhosted.org/packages/be/6c/28f17390b62b8f2f520e2915095b3c94d88681ecf0041e75389d9667f202/kiwisolver-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:beb7f344487cdcb9e1efe4b7a29681b74d34c08f0043a327a74da852a6749e7b", size = 73480, upload-time = "2026-03-09T13:13:20.818Z" }, + { url = "https://files.pythonhosted.org/packages/d8/0e/2ee5debc4f77a625778fec5501ff3e8036fe361b7ee28ae402a485bb9694/kiwisolver-1.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:ad4ae4ffd1ee9cd11357b4c66b612da9888f4f4daf2f36995eda64bd45370cac", size = 64930, upload-time = "2026-03-09T13:13:21.997Z" }, + { url = "https://files.pythonhosted.org/packages/4d/b2/818b74ebea34dabe6d0c51cb1c572e046730e64844da6ed646d5298c40ce/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4e9750bc21b886308024f8a54ccb9a2cc38ac9fa813bf4348434e3d54f337ff9", size = 123158, upload-time = "2026-03-09T13:13:23.127Z" }, + { url = "https://files.pythonhosted.org/packages/bf/d9/405320f8077e8e1c5c4bd6adc45e1e6edf6d727b6da7f2e2533cf58bff71/kiwisolver-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:72ec46b7eba5b395e0a7b63025490d3214c11013f4aacb4f5e8d6c3041829588", size = 66388, upload-time = "2026-03-09T13:13:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/99/9f/795fedf35634f746151ca8839d05681ceb6287fbed6cc1c9bf235f7887c2/kiwisolver-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ed3a984b31da7481b103f68776f7128a89ef26ed40f4dc41a2223cda7fb24819", size = 64068, upload-time = "2026-03-09T13:13:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/c4/13/680c54afe3e65767bed7ec1a15571e1a2f1257128733851ade24abcefbcc/kiwisolver-1.5.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb5136fb5352d3f422df33f0c879a1b0c204004324150cc3b5e3c4f310c9049f", size = 1477934, upload-time = "2026-03-09T13:13:27.166Z" }, + { url = "https://files.pythonhosted.org/packages/c8/2f/cebfcdb60fd6a9b0f6b47a9337198bcbad6fbe15e68189b7011fd914911f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2af221f268f5af85e776a73d62b0845fc8baf8ef0abfae79d29c77d0e776aaf", size = 1278537, upload-time = "2026-03-09T13:13:28.707Z" }, + { url = "https://files.pythonhosted.org/packages/f2/0d/9b782923aada3fafb1d6b84e13121954515c669b18af0c26e7d21f579855/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b0f172dc8ffaccb8522d7c5d899de00133f2f1ca7b0a49b7da98e901de87bf2d", size = 1296685, upload-time = "2026-03-09T13:13:30.528Z" }, + { url = "https://files.pythonhosted.org/packages/27/70/83241b6634b04fe44e892688d5208332bde130f38e610c0418f9ede47ded/kiwisolver-1.5.0-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ab8ba9152203feec73758dad83af9a0bbe05001eb4639e547207c40cfb52083", size = 1346024, upload-time = "2026-03-09T13:13:32.818Z" }, + { url = "https://files.pythonhosted.org/packages/e4/db/30ed226fb271ae1a6431fc0fe0edffb2efe23cadb01e798caeb9f2ceae8f/kiwisolver-1.5.0-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:cdee07c4d7f6d72008d3f73b9bf027f4e11550224c7c50d8df1ae4a37c1402a6", size = 987241, upload-time = "2026-03-09T13:13:34.435Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bd/c314595208e4c9587652d50959ead9e461995389664e490f4dce7ff0f782/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c60d3c9b06fb23bd9c6139281ccbdc384297579ae037f08ae90c69f6845c0b1", size = 2227742, upload-time = "2026-03-09T13:13:36.4Z" }, + { url = "https://files.pythonhosted.org/packages/c1/43/0499cec932d935229b5543d073c2b87c9c22846aab48881e9d8d6e742a2d/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e315e5ec90d88e140f57696ff85b484ff68bb311e36f2c414aa4286293e6dee0", size = 2323966, upload-time = "2026-03-09T13:13:38.204Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/79b0d760907965acfd9d61826a3d41f8f093c538f55cd2633d3f0db269f6/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:1465387ac63576c3e125e5337a6892b9e99e0627d52317f3ca79e6930d889d15", size = 1977417, upload-time = "2026-03-09T13:13:39.966Z" }, + { url = "https://files.pythonhosted.org/packages/ab/31/01d0537c41cb75a551a438c3c7a80d0c60d60b81f694dac83dd436aec0d0/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:530a3fd64c87cffa844d4b6b9768774763d9caa299e9b75d8eca6a4423b31314", size = 2491238, upload-time = "2026-03-09T13:13:41.698Z" }, + { url = "https://files.pythonhosted.org/packages/e4/34/8aefdd0be9cfd00a44509251ba864f5caf2991e36772e61c408007e7f417/kiwisolver-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1d9daea4ea6b9be74fe2f01f7fbade8d6ffab263e781274cffca0dba9be9eec9", size = 2294947, upload-time = "2026-03-09T13:13:43.343Z" }, + { url = "https://files.pythonhosted.org/packages/ad/cf/0348374369ca588f8fe9c338fae49fa4e16eeb10ffb3d012f23a54578a9e/kiwisolver-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:f18c2d9782259a6dc132fdc7a63c168cbc74b35284b6d75c673958982a378384", size = 73569, upload-time = "2026-03-09T13:13:45.792Z" }, + { url = "https://files.pythonhosted.org/packages/28/26/192b26196e2316e2bd29deef67e37cdf9870d9af8e085e521afff0fed526/kiwisolver-1.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7c7553b13f69c1b29a5bde08ddc6d9d0c8bfb84f9ed01c30db25944aeb852a7", size = 64997, upload-time = "2026-03-09T13:13:46.878Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fa/2910df836372d8761bb6eff7d8bdcb1613b5c2e03f260efe7abe34d388a7/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_10_13_x86_64.whl", hash = "sha256:5ae8e62c147495b01a0f4765c878e9bfdf843412446a247e28df59936e99e797", size = 130262, upload-time = "2026-03-09T13:15:35.629Z" }, + { url = "https://files.pythonhosted.org/packages/0f/41/c5f71f9f00aabcc71fee8b7475e3f64747282580c2fe748961ba29b18385/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:f6764a4ccab3078db14a632420930f6186058750df066b8ea2a7106df91d3203", size = 138036, upload-time = "2026-03-09T13:15:36.894Z" }, + { url = "https://files.pythonhosted.org/packages/fa/06/7399a607f434119c6e1fdc8ec89a8d51ccccadf3341dee4ead6bd14caaf5/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c31c13da98624f957b0fb1b5bae5383b2333c2c3f6793d9825dd5ce79b525cb7", size = 194295, upload-time = "2026-03-09T13:15:38.22Z" }, + { url = "https://files.pythonhosted.org/packages/b5/91/53255615acd2a1eaca307ede3c90eb550bae9c94581f8c00081b6b1c8f44/kiwisolver-1.5.0-graalpy312-graalpy250_312_native-win_amd64.whl", hash = "sha256:1f1489f769582498610e015a8ef2d36f28f505ab3096d0e16b4858a9ec214f57", size = 75987, upload-time = "2026-03-09T13:15:39.65Z" }, + { url = "https://files.pythonhosted.org/packages/17/6f/6fd4f690a40c2582fa34b97d2678f718acf3706b91d270c65ecb455d0a06/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:295d9ffe712caa9f8a3081de8d32fc60191b4b51c76f02f951fd8407253528f4", size = 59606, upload-time = "2026-03-09T13:15:40.81Z" }, + { url = "https://files.pythonhosted.org/packages/82/a0/2355d5e3b338f13ce63f361abb181e3b6ea5fffdb73f739b3e80efa76159/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:51e8c4084897de9f05898c2c2a39af6318044ae969d46ff7a34ed3f96274adca", size = 57537, upload-time = "2026-03-09T13:15:42.071Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b9/1d50e610ecadebe205b71d6728fd224ce0e0ca6aba7b9cbe1da049203ac5/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b83af57bdddef03c01a9138034c6ff03181a3028d9a1003b301eb1a55e161a3f", size = 79888, upload-time = "2026-03-09T13:15:43.317Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ee/b85ffcd75afed0357d74f0e6fc02a4507da441165de1ca4760b9f496390d/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf4679a3d71012a7c2bf360e5cd878fbd5e4fcac0896b56393dec239d81529ed", size = 77584, upload-time = "2026-03-09T13:15:44.605Z" }, + { url = "https://files.pythonhosted.org/packages/6b/dd/644d0dde6010a8583b4cd66dd41c5f83f5325464d15c4f490b3340ab73b4/kiwisolver-1.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:41024ed50e44ab1a60d3fe0a9d15a4ccc9f5f2b1d814ff283c8d01134d5b81bc", size = 73390, upload-time = "2026-03-09T13:15:45.832Z" }, + { url = "https://files.pythonhosted.org/packages/e9/eb/5fcbbbf9a0e2c3a35effb88831a483345326bbc3a030a3b5b69aee647f84/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ec4c85dc4b687c7f7f15f553ff26a98bfe8c58f5f7f0ac8905f0ba4c7be60232", size = 59532, upload-time = "2026-03-09T13:15:47.047Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9b/e17104555bb4db148fd52327feea1e96be4b88e8e008b029002c281a21ab/kiwisolver-1.5.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:12e91c215a96e39f57989c8912ae761286ac5a9584d04030ceb3368a357f017a", size = 57420, upload-time = "2026-03-09T13:15:48.199Z" }, + { url = "https://files.pythonhosted.org/packages/48/44/2b5b95b7aa39fb2d8d9d956e0f3d5d45aef2ae1d942d4c3ffac2f9cfed1a/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:be4a51a55833dc29ab5d7503e7bcb3b3af3402d266018137127450005cdfe737", size = 79892, upload-time = "2026-03-09T13:15:49.694Z" }, + { url = "https://files.pythonhosted.org/packages/52/7d/7157f9bba6b455cfb4632ed411e199fc8b8977642c2b12082e1bd9e6d173/kiwisolver-1.5.0-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daae526907e262de627d8f70058a0f64acc9e2641c164c99c8f594b34a799a16", size = 77603, upload-time = "2026-03-09T13:15:50.945Z" }, + { url = "https://files.pythonhosted.org/packages/0a/dd/8050c947d435c8d4bc94e3252f4d8bb8a76cfb424f043a8680be637a57f1/kiwisolver-1.5.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:59cd8683f575d96df5bb48f6add94afc055012c29e28124fcae2b63661b9efb1", size = 73558, upload-time = "2026-03-09T13:15:52.112Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.9" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +dependencies = [ + { name = "contourpy", version = "1.3.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "cycler", marker = "python_full_version < '3.11'" }, + { name = "fonttools", marker = "python_full_version < '3.11'" }, + { name = "kiwisolver", marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "packaging", marker = "python_full_version < '3.11'" }, + { name = "pillow", marker = "python_full_version < '3.11'" }, + { name = "pyparsing", marker = "python_full_version < '3.11'" }, + { name = "python-dateutil", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/1b/4be5be87d43d327a0cf4de1a56e86f7f84c89312452406cf122efe2839e6/matplotlib-3.10.9.tar.gz", hash = "sha256:fd66508e8c6877d98e586654b608a0456db8d7e8a546eb1e2600efd957302358", size = 34811233, upload-time = "2026-04-24T00:14:13.539Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/6f/340b04986e67aac6f66c5145ce68bf72c64bed30f92c8913499a6e6b8f99/matplotlib-3.10.9-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77210dce9cb8153dffc967efaae990543392563d5a376d4dd8539bebcb0ed217", size = 8296625, upload-time = "2026-04-24T00:11:43.376Z" }, + { url = "https://files.pythonhosted.org/packages/bb/2f/127081eb83162053ebb9678ceac64220b93a663e0167432566e9c7c82aab/matplotlib-3.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1e7698ac9868428e84d2c967424803b2472ff7167d9d6590d4204ed775343c3b", size = 8188790, upload-time = "2026-04-24T00:11:46.556Z" }, + { url = "https://files.pythonhosted.org/packages/fc/b7/d8bcec2626c35f96972bff656299fef4578113ea6193c8fdad324710410c/matplotlib-3.10.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aa972116abb4c9d201bf245620b433726cb6856f3bef6a78f776a00f5c92d37", size = 8769389, upload-time = "2026-04-24T00:11:48.959Z" }, + { url = "https://files.pythonhosted.org/packages/12/49/b78e214a527ea732033b7f4d37f7afb504d74ba9d134bd47938230dfb8b1/matplotlib-3.10.9-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae2f11957b27ce53497dd4d7b235c4d4f1faf383dfb39d0c5beb833bff883294", size = 9589657, upload-time = "2026-04-24T00:11:51.915Z" }, + { url = "https://files.pythonhosted.org/packages/5f/15/5246f7b43beae19c74dfee651d58d6cc8112e06f77adb4e88cc04f2e3a23/matplotlib-3.10.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b049278ddce116aaa1c1377ebf58adea909132dfce0281cf7e3a1ea9fc2e2c65", size = 9651983, upload-time = "2026-04-24T00:11:54.766Z" }, + { url = "https://files.pythonhosted.org/packages/75/77/5acecfe672ba0fa1b8c0454f69ce155d1e6fc5852fa7206bf9afaf767121/matplotlib-3.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:82834c3c292d24d3a8aae77cd2d20019de69d692a34a970e4fdb8d33e2ea3dda", size = 8199701, upload-time = "2026-04-24T00:11:58.389Z" }, + { url = "https://files.pythonhosted.org/packages/4c/8c/290f021104741fea63769c31494f5324c0cd249bf536a65a4350767b1f22/matplotlib-3.10.9-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:68cfdcede415f7c8f5577b03303dd94526cdb6d11036cecdc205e08733b2d2bb", size = 8306860, upload-time = "2026-04-24T00:12:01.207Z" }, + { url = "https://files.pythonhosted.org/packages/51/18/325cd32ece1120d1da51cc4e4294c6580190699490183fc2fe8cb6d61ec5/matplotlib-3.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfca0129678bd56379db26c52b5d77ed7de314c047492fbdc763aa7501710cfb", size = 8199254, upload-time = "2026-04-24T00:12:04.239Z" }, + { url = "https://files.pythonhosted.org/packages/79/db/e28c1b83e3680740aa78925f5fb2ae4d16207207419ad75ea9fe604f8676/matplotlib-3.10.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e436d155fa8a3399dc62683f8f5d0e2e50d25d0144a73edd73f82eec8f4abfb", size = 8777092, upload-time = "2026-04-24T00:12:06.793Z" }, + { url = "https://files.pythonhosted.org/packages/55/fa/3ce7adfe9ba101748f465211660d9c6374c876b671bdb8c2bb6d347e8b94/matplotlib-3.10.9-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56fc0bd271b00025c6edfdc7c2dcd247372c8e1544971d62e1dc7c17367e8bf9", size = 9595691, upload-time = "2026-04-24T00:12:09.706Z" }, + { url = "https://files.pythonhosted.org/packages/36/c4/6960a76686ed668f2c60f84e9799ba4c0d56abdb36b1577b60c1d061d1ec/matplotlib-3.10.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5a6104ed666402ba5106d7f36e0e0cdca4e8d7fa4d39708ca88019e2835a2eb", size = 9659771, upload-time = "2026-04-24T00:12:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0d/271aace3342157c64700c9ff4c59c7b392f3dbab393692e8db6fbe7ab96c/matplotlib-3.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:d730e984eddf56974c3e72b6129c7ca462ac38dc624338f4b0b23eb23ecba00f", size = 8205112, upload-time = "2026-04-24T00:12:15.773Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ee/cb57ad4754f3e7b9174ce6ce66d9205fb827067e48a9f58ac09d7e7d6b77/matplotlib-3.10.9-cp311-cp311-win_arm64.whl", hash = "sha256:51bf0ddbdc598e060d46c16b5590708f81a1624cefbaaf62f6a81bf9285b8c80", size = 8132310, upload-time = "2026-04-24T00:12:18.645Z" }, + { url = "https://files.pythonhosted.org/packages/35/c6/5581e26c72233ebb2a2a6fed2d24fb7c66b4700120b813f51b0555acf0b6/matplotlib-3.10.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f0c3c28d9fbcc1fe7a03be236d73430cf6409c41fb2383a7ac52fe932b072cb1", size = 8319908, upload-time = "2026-04-24T00:12:21.323Z" }, + { url = "https://files.pythonhosted.org/packages/b7/18/4880dd762e40cd360c1bf06e890c5a97b997e91cb324602b1a19950ad5ce/matplotlib-3.10.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41cb28c2bd769aa3e98322c6ab09854cbcc52ab69d2759d681bba3e327b2b320", size = 8216016, upload-time = "2026-04-24T00:12:23.4Z" }, + { url = "https://files.pythonhosted.org/packages/32/91/d024616abdba99e83120e07a20658976f6a343646710760c4a51df126029/matplotlib-3.10.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae20801130378b82d647ff5047c07316295b68dc054ca6b3c13519d0ea624285", size = 8789336, upload-time = "2026-04-24T00:12:26.096Z" }, + { url = "https://files.pythonhosted.org/packages/5c/04/030a2f61ef2158f5e4c259487a92ac877732499fb33d871585d89e03c42d/matplotlib-3.10.9-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c63ebcd8b4b169eb2f5c200552ae6b8be8999a005b6b507ed76fb8d7d674fe2", size = 9604602, upload-time = "2026-04-24T00:12:29.052Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c2/541e4d09d87bb6b5830fc28b4c887a9a8cf4e1c6cee698a8c05552ae2003/matplotlib-3.10.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d75d11c949914165976c621b2324f9ef162af7ebf4b057ddf95dd1dba7e5edcf", size = 9670966, upload-time = "2026-04-24T00:12:32.131Z" }, + { url = "https://files.pythonhosted.org/packages/04/a1/4571fc46e7702de8d0c2dc54ad1b2f8e29328dea3ee90831181f7353d93c/matplotlib-3.10.9-cp312-cp312-win_amd64.whl", hash = "sha256:d091f9d758b34aaaaa6331d13574bf01891d903b3dec59bfff458ef7551de5d6", size = 8217462, upload-time = "2026-04-24T00:12:35.226Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d0/2269edb12aa30c13c8bcc9382892e39943ce1d28aab4ec296e0381798e81/matplotlib-3.10.9-cp312-cp312-win_arm64.whl", hash = "sha256:10cc5ce06d10231c36f40e875f3c7e8050362a4ee8f0ee5d29a6b3277d57bb42", size = 8136688, upload-time = "2026-04-24T00:12:37.442Z" }, + { url = "https://files.pythonhosted.org/packages/2c/2b/0e92ad0ac446633f928a1563db4aa8add407e1924faf0ded5b95b35afb27/matplotlib-3.10.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1872fb212a05b729e649754a72d5da61d03e0554d76e80303b6f83d1d2c0552b", size = 8293058, upload-time = "2026-04-24T00:13:56.339Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/74682fd369f5299ceda438fea2a0662e6383b85c9383fb9cdfcf04713e07/matplotlib-3.10.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:985f2238880e2e69093f588f5fe2e46771747febf0649f3cf7f7b7480875317f", size = 8186627, upload-time = "2026-04-24T00:13:58.623Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e8/368aab88f3c4cd8992800f31abfe0670c3e47540ba20a97e9fdbcde594b3/matplotlib-3.10.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6640f75af2c6148293caa0a2b39dd806a492dd66c8a8b04035813e33d0fd2585", size = 8764117, upload-time = "2026-04-24T00:14:01.684Z" }, + { url = "https://files.pythonhosted.org/packages/63/e2/9f66ca6a651a52abfe0d4964ce01439ed34f3f1e119de10ff3a07f403043/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:42fb814efabe95c06c1994d8ab5a8385f43a249e23badd3ba931d4308e5bca20", size = 8304420, upload-time = "2026-04-24T00:14:04.57Z" }, + { url = "https://files.pythonhosted.org/packages/e8/e8/467c03568218792906aa87b5e7bb379b605e056ed0c74fe00c051786d925/matplotlib-3.10.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:f76e640a5268850bfda54b5131b1b1941cc685e42c5fa98ed9f2d64038308cba", size = 8197981, upload-time = "2026-04-24T00:14:07.233Z" }, + { url = "https://files.pythonhosted.org/packages/6f/87/afead29192170917537934c6aff4b008c805fff7b1ccea0c79120d96beda/matplotlib-3.10.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3fc0364dfbe1d07f6d15c5ebd0c5bf89e126916e5a8667dd4a7a6e84c36653d4", size = 8774002, upload-time = "2026-04-24T00:14:09.816Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.11.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version == '3.11.*'", +] +dependencies = [ + { name = "contourpy", version = "1.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "cycler", marker = "python_full_version >= '3.11'" }, + { name = "fonttools", marker = "python_full_version >= '3.11'" }, + { name = "kiwisolver", marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "packaging", marker = "python_full_version >= '3.11'" }, + { name = "pillow", marker = "python_full_version >= '3.11'" }, + { name = "pyparsing", marker = "python_full_version >= '3.11'" }, + { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/64/f9a391af28f518b11ad45a8a712353c94a0aefce09d3703200e5c54b610a/matplotlib-3.11.1.tar.gz", hash = "sha256:69647db5746941c793d6e445a4cd349323ffb87d9cc958c2ad84a659b4832d30", size = 32612045, upload-time = "2026-07-18T03:39:46.63Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/d0/791aa183dd88491555cf7d4be0b52b0bcf6c3c2a2c22c815a2e819bf53e2/matplotlib-3.11.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b7cf158e7add54a8d51ac9b5a84abd6d4e13ed4951b4f25f1c5139f41c2addb2", size = 9440302, upload-time = "2026-07-18T03:38:03.844Z" }, + { url = "https://files.pythonhosted.org/packages/35/74/82bbdf683a301f4478384c8aaba6903631a2ca18294b2d7655c9a542bffb/matplotlib-3.11.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d2ace7273b9a5061a3b420918a16fae1f2dc5dfee1abcc13aba71b5d94b1820c", size = 9268549, upload-time = "2026-07-18T03:38:06.144Z" }, + { url = "https://files.pythonhosted.org/packages/f0/f0/9b4298911303f74e6d83e64a81d996c0616405ec95046fac7f17e4258b9e/matplotlib-3.11.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee55e9041211bf84302ab55ec3965df18dd90ae19f8b58332a7feaf208bfe83", size = 10024922, upload-time = "2026-07-18T03:38:08.236Z" }, + { url = "https://files.pythonhosted.org/packages/84/6f/0bc3c3d05b021db44c14bc379a7c0df7d57302aa15380c16fd4e63fd6a9b/matplotlib-3.11.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f4bdeea33a8d15a071dbfe6d119451b1d719c733ac666d65357082901a9099", size = 10832170, upload-time = "2026-07-18T03:38:10.276Z" }, + { url = "https://files.pythonhosted.org/packages/db/4d/e375f39acdb2af5a9342730618608e39790ec842e6f1b392863028781459/matplotlib-3.11.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b4c78ceb2f11bcac7389d305cda17aeb1f4586a857854ab5780bd3dd8dbfc407", size = 10916701, upload-time = "2026-07-18T03:38:12.512Z" }, + { url = "https://files.pythonhosted.org/packages/bc/be/fa26ed085b41298f64a8f9b7592c671bbf1acc8b0df124c1c5de96b859f8/matplotlib-3.11.1-cp311-cp311-win_amd64.whl", hash = "sha256:7f33a781e12b1e53b278deb2f5373c2e55ec4f10727be3440c0cfb5cda9f944f", size = 9315331, upload-time = "2026-07-18T03:38:14.949Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f3/eb5bdf3b6e191b200db298b08bbc1638b7f3c82cdc8680f9d88bf72559ae/matplotlib-3.11.1-cp311-cp311-win_arm64.whl", hash = "sha256:67e4c3cd578c65ebd81bdc09a1b6592ceafee6dfafe116dc85dfcb647b5bbb18", size = 9003475, upload-time = "2026-07-18T03:38:17.205Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6c/7ef7ebcb2bd9739b2b66b18b076e077f44bb46fdbe28ca0506edb3c62c79/matplotlib-3.11.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e15ef41507f3d525f46154ac9e3ae785dacde9f20e593a25de8986267892ef74", size = 9453849, upload-time = "2026-07-18T03:38:19.593Z" }, + { url = "https://files.pythonhosted.org/packages/eb/f8/6d0c312c8d9738e7d9677f09fe5c986b3239e651a7b73a2deb38b65e4a71/matplotlib-3.11.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:21a67b961a6d597bca54fae826cd20695ba4a6e4d05424a08da6e13e3176fd6b", size = 9283113, upload-time = "2026-07-18T03:38:21.95Z" }, + { url = "https://files.pythonhosted.org/packages/c9/cf/b4ad2cc81b6672ea29ea04e64e350a9f9b493b0908ccd884c67eeff8f7b2/matplotlib-3.11.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ba8f811b8ddfac493734d6af0b2dff96919d0c28ca0d641858dab4262777c6ea", size = 10035615, upload-time = "2026-07-18T03:38:24.315Z" }, + { url = "https://files.pythonhosted.org/packages/88/90/4e10e033d9b66589d8ed98b84c95cdbb57033d57c1f41339d7393dbd2f2e/matplotlib-3.11.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c52f7ad20ef476806ed212380b1d54d20310c8b86bdc2c9a68b51f0024a44472", size = 10842559, upload-time = "2026-07-18T03:38:26.285Z" }, + { url = "https://files.pythonhosted.org/packages/88/eb/799612d0f8cd3e816a10fec59329fca52cd2353264df80378dfc541ae855/matplotlib-3.11.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8b14eb22961fe865efb0e4ff167e333e428908b00115a8d800ccb65ee108e481", size = 10927532, upload-time = "2026-07-18T03:38:28.532Z" }, + { url = "https://files.pythonhosted.org/packages/88/89/56649bbaa2fd12e20f3be03dbcc135b0c8676d88bac17977599e3eb442a0/matplotlib-3.11.1-cp312-cp312-win_amd64.whl", hash = "sha256:88a2a27dd9691ae448dfae4b26f59036be90c3c28757edd3553a29559d00859f", size = 9333886, upload-time = "2026-07-18T03:38:30.477Z" }, + { url = "https://files.pythonhosted.org/packages/c1/11/4d124efbbad677b7b7552f6f85a3bd432d4232f95400cea98fcd2ae36ef3/matplotlib-3.11.1-cp312-cp312-win_arm64.whl", hash = "sha256:480194afceca4df2f137c2721227d3cba67121fbf4397b69cee7f83714b0a58a", size = 9007545, upload-time = "2026-07-18T03:38:32.833Z" }, + { url = "https://files.pythonhosted.org/packages/ee/38/ceb1d637c4db6d06141f3739e93af3321e7caaabe69b57ae48ffe3ee95b1/matplotlib-3.11.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:427258425f9a3fc4ed79a91f9e9b9aaf5a82cb6571e85dc14063cc6fbb993741", size = 9438045, upload-time = "2026-07-18T03:39:39.491Z" }, + { url = "https://files.pythonhosted.org/packages/89/25/72ad8b58602d3a6ef1dfc4b65ecd01634ab65a2bdf494c9fe0e966dbf081/matplotlib-3.11.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:1ac697e591c11b6ad04679a73c2d2f9980fe9d9f0311fb414a2e329706343dfb", size = 9266127, upload-time = "2026-07-18T03:39:41.597Z" }, + { url = "https://files.pythonhosted.org/packages/8a/6d/69552382fcc8e93d1f2763ef2665980a900a48b7f3a4c57ed290726d1cbc/matplotlib-3.11.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e4b9ac2f1f607ecda2af90a5232beee2af7582fce1cc30c4b6a1b012dc21ee99", size = 10019439, upload-time = "2026-07-18T03:39:43.78Z" }, +] + +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11'", +] +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, + { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, + { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, + { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, + { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, + { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, + { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.11.*'", +] +sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, + { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, + { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, + { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, + { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, + { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, + { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, + { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, + { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, + { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, + { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, + { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, + { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, + { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, + { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, + { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, + { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, +] + +[[package]] +name = "numpy" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12'", +] +sdist = { url = "https://files.pythonhosted.org/packages/22/fd/89965aa4ac08c74998539fcbf24fa3540f3e15237fbeb6bcf9c908f4aade/numpy-2.5.1.tar.gz", hash = "sha256:a48a113e6afea91f5608793bafa7ef2ad481fefbda87ec5069f483de61cb9fa3", size = 20755553, upload-time = "2026-07-04T17:08:00.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/7b/14687aa674250e5e546f616f486b0d56d3631cd5b2415739141ce40bdcea/numpy-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c889b56fe48b1018f764b0eec8df59ab654e9148aa91faa12596043500de277", size = 16801574, upload-time = "2026-07-04T17:06:12.423Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/cc5bb2a3f2913d27d6dbb2c78d25921fabaedc6741d4a5a615a11f3c5bf3/numpy-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab451b59c5643c570974c43aef780703ef1d3b4965d2be07afd530615a9358d1", size = 11772250, upload-time = "2026-07-04T17:06:15.726Z" }, + { url = "https://files.pythonhosted.org/packages/42/77/fdf34a71dd30f54979b18603bee915e0aaf825b07afe79acd60b04b691e2/numpy-2.5.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:78798bd5b9ad744056af8efa90e3b9ddaa53272a0848a483084a1cc0a13b2dc0", size = 5331516, upload-time = "2026-07-04T17:06:17.913Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e2/eb7efa015b4cce41e2517bf182a7fce0d7d5b9d9ed76a29bfa0f4fe4505c/numpy-2.5.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2ae0ca40bcb22d6ba59c1dfd5446f49940b0f2d821fde133f10dda11f816b84e", size = 6664863, upload-time = "2026-07-04T17:06:20.02Z" }, + { url = "https://files.pythonhosted.org/packages/a9/4b/a2b32dd94ee9ffbeecb28152240042a3949db33b1c834d44090b80e1b3b8/numpy-2.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61ac47e772e6b8ea489e1d2f441a34c5c3ac17327e7ce294cbdf535795ad4e75", size = 15167977, upload-time = "2026-07-04T17:06:21.621Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/6e73d68500f80773f65f0654ea932019d6694329a0eb0ed0533de38df376/numpy-2.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59fda5e192b570217ec2580c96f00e9a7e12ef6866a900eb089b62c1a32545ca", size = 16672469, upload-time = "2026-07-04T17:06:24.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/7d/ad3e59015135f5261c95fd4cafeff159c955febd83a99a1d9250c4233815/numpy-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7119ebff1a9829e9f431a4f9d28e703023bb6b9fe7c8f724467dbfc27c94ab3", size = 16527531, upload-time = "2026-07-04T17:06:26.69Z" }, + { url = "https://files.pythonhosted.org/packages/83/d0/a39b2fbcde9cb17a1dac678f254b33a6336298af9df338824c685425d5e8/numpy-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e824c2acf8862052246be5a44c15da1777940c60d010dd2aab897824d9c430f9", size = 18431940, upload-time = "2026-07-04T17:06:29.521Z" }, + { url = "https://files.pythonhosted.org/packages/04/12/cff070947791c1ed425ff76413189adbdc2fbe215eba7ce7fa454a03c7f8/numpy-2.5.1-cp312-cp312-win32.whl", hash = "sha256:08d60c810432eb83360958dea0999ac4cfb94531ea8efcbf0b7f277c2068aeb2", size = 6066764, upload-time = "2026-07-04T17:06:32.571Z" }, + { url = "https://files.pythonhosted.org/packages/65/66/53f31807a48a750f9d748da273bc3fcedd12b27ff1f3e373bfec55ef2dc0/numpy-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7d60026c0bdb1380e83bfa7a0419c4577ee4b9a08880afcb6dadeb74c649fa2", size = 12430966, upload-time = "2026-07-04T17:06:34.926Z" }, + { url = "https://files.pythonhosted.org/packages/2b/2a/d1a88066b1c14186f5d3c0d18c94f17b064511982bab0578d49ee9d43c29/numpy-2.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:17a25e09640602e10bc8de0e6fa2b3fd68eedd84ba6d7842dc8f32f9ab87bd0b", size = 10350488, upload-time = "2026-07-04T17:06:37.785Z" }, +] + +[[package]] +name = "packaging" +version = "26.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, +] + +[[package]] +name = "pillow" +version = "12.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/3d/bb7fca845737cf9d7dbde16ed1843984665ff2e0a518f5db43e77ec540b9/pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce", size = 47025035, upload-time = "2026-07-01T11:56:38.965Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/c2/669d88644cddb1485bd9534e63e8cf476c8e51cb3c3a1297677023505c0e/pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a", size = 5392418, upload-time = "2026-07-01T11:53:27.808Z" }, + { url = "https://files.pythonhosted.org/packages/6b/ba/3762f376a2948e3036488d773a146e0ae6ecc2ca03ac20e2615bd0b2ba02/pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7", size = 4785287, upload-time = "2026-07-01T11:53:29.761Z" }, + { url = "https://files.pythonhosted.org/packages/07/50/b5d688cc9c52d4482f3d5bcab6ce20bc2a74a85d2343841c907444a3be2c/pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f", size = 6253754, upload-time = "2026-07-01T11:53:32.298Z" }, + { url = "https://files.pythonhosted.org/packages/4e/89/36f4cd76cf4baf05c50ababb976249153f18c959171c7f6ba09a6f217260/pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec", size = 6925605, upload-time = "2026-07-01T11:53:34.487Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c0/4de58cf6633b9e3a6061ef4be6fb91fc3c90b812ece886f531e3c523d777/pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468", size = 6327788, upload-time = "2026-07-01T11:53:36.433Z" }, + { url = "https://files.pythonhosted.org/packages/87/3c/14d53682a19550dbbaf3b598f807d5457646c510805a44c7d7891cd1cd1a/pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed", size = 7036288, upload-time = "2026-07-01T11:53:38.712Z" }, + { url = "https://files.pythonhosted.org/packages/38/1d/36279e3c77efe034e4cc2b0393ee74ffdb5a62391dacbf9b916154f5f0b8/pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1", size = 6472396, upload-time = "2026-07-01T11:53:40.781Z" }, + { url = "https://files.pythonhosted.org/packages/48/7c/8fa0039574c476d7c6fa57dd7c32a130436877c6ec1e5ce1cc8ec44878c1/pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb", size = 7226887, upload-time = "2026-07-01T11:53:42.764Z" }, + { url = "https://files.pythonhosted.org/packages/fa/17/e324be141d173c1c919428066c3259f21c1b8982e564e01a4a81e96dbdcf/pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f", size = 2568039, upload-time = "2026-07-01T11:53:45.372Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c8/0a78b0e02d7ac54bc03e5321c9220da52f0c2ea83b21f7c40e7f3169c502/pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756", size = 5392415, upload-time = "2026-07-01T11:53:47.162Z" }, + { url = "https://files.pythonhosted.org/packages/b2/5b/a02d30018abd97ced9f5a6c63d28597694a00d066516b9c1c6de45859fc9/pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6", size = 4785266, upload-time = "2026-07-01T11:53:49.079Z" }, + { url = "https://files.pythonhosted.org/packages/c8/98/766667a4be768150a202836acd9fad19c06824ca86c4286d3cf6b274964e/pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd", size = 6263814, upload-time = "2026-07-01T11:53:51.32Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2d/ede717bc1144f63886c21fd349bb95860b0d1a21149ff16f2bb362b612b6/pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd", size = 6934408, upload-time = "2026-07-01T11:53:53.487Z" }, + { url = "https://files.pythonhosted.org/packages/a3/48/9c58b685e69d49c31af6c8eb9012055fab7e665785165c84796e2c73ce72/pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c", size = 6337160, upload-time = "2026-07-01T11:53:55.457Z" }, + { url = "https://files.pythonhosted.org/packages/ff/fa/dc2a5c0ba6df93f67c31d34b808b7ce440b40cdbf96f0b81cde1d1e6fa93/pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5", size = 7045172, upload-time = "2026-07-01T11:53:57.736Z" }, + { url = "https://files.pythonhosted.org/packages/86/a5/444817a4d4c4c2417df00513086ca196f388d8f9ef40c2e4ccd1ad1af54b/pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b", size = 6472232, upload-time = "2026-07-01T11:53:59.767Z" }, + { url = "https://files.pythonhosted.org/packages/63/c6/4bad1b18d132a50b27e1365e1ab163616f7a5bb56d330f66f9d1d9d4f9d4/pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a", size = 7233653, upload-time = "2026-07-01T11:54:02.066Z" }, + { url = "https://files.pythonhosted.org/packages/fd/16/00f91ab7760dc842f5aad55217e80fc4a7067a0604535249bc8a2d6d9870/pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26", size = 2568195, upload-time = "2026-07-01T11:54:04.622Z" }, + { url = "https://files.pythonhosted.org/packages/37/bf/fb3ebff8ddcb76aac5a01389251bbbb9519922a9b520d8247c1ca864a25d/pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965", size = 5345969, upload-time = "2026-07-01T11:54:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/d8/66/9a386a92561f402389a4fc70c18838bf6d35eb5eb5c6850b4b2dc64f5048/pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7", size = 4780323, upload-time = "2026-07-01T11:54:09.351Z" }, + { url = "https://files.pythonhosted.org/packages/25/27/ac8f99618ffd3dde21db0f4d4b1d2ab00c0880595bfd17df103f7f39fd0c/pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9", size = 6266838, upload-time = "2026-07-01T11:54:11.71Z" }, + { url = "https://files.pythonhosted.org/packages/84/21/a35af28dcc61f37ed850a2d64c65c701321dfbf25085e469d5559360cbbf/pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91", size = 6940830, upload-time = "2026-07-01T11:54:13.732Z" }, + { url = "https://files.pythonhosted.org/packages/eb/51/8b08617af3ad95e33ce6d7dd2c99ed6c8298f7fb131636303956be022e25/pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c", size = 6344383, upload-time = "2026-07-01T11:54:15.756Z" }, + { url = "https://files.pythonhosted.org/packages/1d/72/cf78ac9780bb93c28328f408973845a309d4d145041665f734572ced1b52/pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df", size = 7052934, upload-time = "2026-07-01T11:54:17.721Z" }, + { url = "https://files.pythonhosted.org/packages/20/20/25e0f4dc178a6bc0696793720055519a0de89e7661dae886992decbd2f81/pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f", size = 6472684, upload-time = "2026-07-01T11:54:19.839Z" }, + { url = "https://files.pythonhosted.org/packages/45/89/da2f7971a317f83d807fdd4065c0af40208e59e692cc43d315a71a0e96d1/pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09", size = 7227137, upload-time = "2026-07-01T11:54:22.025Z" }, + { url = "https://files.pythonhosted.org/packages/de/47/4845a0a6c0dbf1db8456bd9fc791f13c5ced7ced20606d08a0aacfd25b49/pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510", size = 2568267, upload-time = "2026-07-01T11:54:24.051Z" }, + { url = "https://files.pythonhosted.org/packages/75/18/2e8b40223153ccbc60df07f9e8928dc0c76202aa4e55ae9f53962b6510d6/pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468", size = 5302510, upload-time = "2026-07-01T11:56:25.736Z" }, + { url = "https://files.pythonhosted.org/packages/46/3e/51fabf59d5ab801ceab709453d3ab6b180083496579549de4c45ced6528a/pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94", size = 4736058, upload-time = "2026-07-01T11:56:28.041Z" }, + { url = "https://files.pythonhosted.org/packages/bf/20/22fe9384b7949e25fb1293bcfc84fb82590ff4ea6b37c95b24d26d793d86/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e", size = 5237776, upload-time = "2026-07-01T11:56:30.263Z" }, + { url = "https://files.pythonhosted.org/packages/08/14/f6ba68107680ffa74b39985f3f30884e41318fbc4250caa423c79b4788bb/pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3", size = 5860358, upload-time = "2026-07-01T11:56:32.68Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0169bc772ec491108b62f644f8ecf1fe5d8ae5ebafde2ee2142210166903/pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a", size = 7231786, upload-time = "2026-07-01T11:56:35.046Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.26.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/c4/453c52c659521066969523e87d85d54139bbd17b78f09532fb8eb8cdb58e/pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f", size = 54156, upload-time = "2025-03-25T06:22:28.883Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/7f/338843f449ace853647ace35870874f69a764d251872ed1b4de9f234822c/pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0", size = 19694, upload-time = "2025-03-25T06:22:27.807Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, + { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, + { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, + { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, + { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, + { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, + { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, + { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, + { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, + { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, +] + +[[package]] +name = "ruff" +version = "0.16.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/70/25/7113f6d5498888c5fb7db34081cba7d5971c4cb1bfb26819966eee68f003/ruff-0.16.1.tar.gz", hash = "sha256:fedad7c801dabd3fb9741d76aca39246e6ddd9ca446a015875207bf19f1e6bc7", size = 4877500, upload-time = "2026-07-30T19:37:01.379Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/bd/694da69368e0973de65df2ddc73ab18d43c469d5963d9b150911de6bc513/ruff-0.16.1-py3-none-linux_armv6l.whl", hash = "sha256:58edb313b88f0c5460a26adf5f39a37a3be789494a15e3e411e35fa78b89f9a0", size = 10839126, upload-time = "2026-07-30T19:36:13.697Z" }, + { url = "https://files.pythonhosted.org/packages/3f/f0/b626e5d5bd0dd9576263658ef12885e2288afd1029a48e26ffed65ec1ac1/ruff-0.16.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:fde5a99e2f97479af66edd6622c6d5a2a7592c77cf4153d9e4428f5eeb55b60c", size = 11070253, upload-time = "2026-07-30T19:36:17.14Z" }, + { url = "https://files.pythonhosted.org/packages/83/63/f40acfb6b35b88623e71684942b552c3edd96035f5d98f313815f7b277de/ruff-0.16.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e0d4c20532fca4f7fa609369161d968dd28f65d83dabbd61d8e9c7edbf7001f6", size = 10561425, upload-time = "2026-07-30T19:36:20.04Z" }, + { url = "https://files.pythonhosted.org/packages/aa/dd/14ec0e9c2b4d315547dd38765004b4863e354e1b52cb308272215d9f6f6d/ruff-0.16.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30affbcedf59ad5703d9c91f82266e02b47739f797e1a7b6e158e5526a6dae38", size = 10948879, upload-time = "2026-07-30T19:36:22.476Z" }, + { url = "https://files.pythonhosted.org/packages/33/e9/9d870cbae575030fdef595f04b4b97573c525b5497cce4f4498cf2f85446/ruff-0.16.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24e9c631573cbca9d20f1283f8f479b2afa4a8503504822bd71a293889f16743", size = 10643691, upload-time = "2026-07-30T19:36:24.914Z" }, + { url = "https://files.pythonhosted.org/packages/c4/09/12743d544e2173f53ecd27217c65f90d2bc0f8424a66a60339e56bbc0457/ruff-0.16.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b41bdd48fb420987a9b5212e4957c26ad4abce401fa9ea9d4d85843727945f4f", size = 11435354, upload-time = "2026-07-30T19:36:28.447Z" }, + { url = "https://files.pythonhosted.org/packages/7f/89/a1652b2daee52083c9554a6333b678a8b01d0400f976827bb87857f9449a/ruff-0.16.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b0d1e1393b7648079e13669de1c1f4fde06d4583e84d8fd5c1551e0a77a2aa75", size = 12259033, upload-time = "2026-07-30T19:36:31.326Z" }, + { url = "https://files.pythonhosted.org/packages/16/96/ecdcb8c54ee7b123b487f807eb014e6e019155a0b81dfb669acd52f28ce3/ruff-0.16.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:07bf434b1c95f4e093be4532068ef4fcf00924eb2ade8796075980902d6fd54a", size = 11667981, upload-time = "2026-07-30T19:36:34.394Z" }, + { url = "https://files.pythonhosted.org/packages/cd/90/c52e12e0d862e9572f2a33aa227409143520abe53111e9a6babbac7b4af8/ruff-0.16.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39897739f112253ee4fdd2e8aa9a4f9ded99fb2be367d5f31dfa4ded6025584c", size = 11468183, upload-time = "2026-07-30T19:36:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/2c/6b/4ffb7ad1d83eb16cf8cbb3c8815d3f11c88460fd162d4b372a2059be1c2a/ruff-0.16.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:82ae3c0c0d74daf17b968a10b7b3bb3ef297ab7de0c1f749646b25e690ccb150", size = 11470071, upload-time = "2026-07-30T19:36:39.91Z" }, + { url = "https://files.pythonhosted.org/packages/9c/72/32ae7db4c0b5e32ab611787caa19d1546800676d79f7483b7100a3561bf4/ruff-0.16.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4d5f2ed10f8242d83fc08d521301089364e3375375705356f20c0e31606ef3ef", size = 10919503, upload-time = "2026-07-30T19:36:42.65Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ca/3d901ba6ad6fc38da39c3448fc6c59ac945679293a17c3ceb6d6c1cba13e/ruff-0.16.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a4665b309891f83f3e3c25447935f1213e9abbd4b5640af7a1f2def9f8d413c1", size = 10649861, upload-time = "2026-07-30T19:36:45.18Z" }, + { url = "https://files.pythonhosted.org/packages/92/79/894ef1ced26552d5f8c9cf6d85b0687840e1128c55aeab7b9c2d54a0d880/ruff-0.16.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:26e9ca5c9bc3971f20d3cf18a957f52ffd6a5f6564ff15c4912a144dcac22494", size = 11148137, upload-time = "2026-07-30T19:36:47.936Z" }, + { url = "https://files.pythonhosted.org/packages/2d/69/3609a09fa1cb46cc28b762363e440a354204e5dff01bd0c8d7437874d6b9/ruff-0.16.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:67e1e1e3fa4f0c82f0e36d4cd61e661f6e7a6196cb1aa92fe0828fa7b8f257cd", size = 11559211, upload-time = "2026-07-30T19:36:50.448Z" }, + { url = "https://files.pythonhosted.org/packages/fc/8a/fb22af2fd78a736e241fabf67e30ce1799a64244026377a49e133af90762/ruff-0.16.1-py3-none-win32.whl", hash = "sha256:d31765e131295b8445caf301e3e8a85b34d1b9b211b4109b7ba457888b051806", size = 10838258, upload-time = "2026-07-30T19:36:53.298Z" }, + { url = "https://files.pythonhosted.org/packages/d4/35/e57fd9fb5d423961df087a00b12d42c0a830288dc2f3b45ecca299158b4f/ruff-0.16.1-py3-none-win_amd64.whl", hash = "sha256:09b05e8b90c2cb06ad63464350e7a45e8e44a2dfe52072ebfba6666ca8d3f596", size = 11961111, upload-time = "2026-07-30T19:36:56.107Z" }, + { url = "https://files.pythonhosted.org/packages/cb/46/240ea004bf6dc4feb40e9832f2205a476a47dd5b8a3f8211a5fc5f95e20e/ruff-0.16.1-py3-none-win_arm64.whl", hash = "sha256:dbaadaac38c70239f056d306b7476f246b0bf000fa6b3876402acbf5b227eaf8", size = 11309414, upload-time = "2026-07-30T19:36:58.79Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "tomli" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/22/de/48c59722572767841493b26183a0d1cc411d54fd759c5607c4590b6563a6/tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f", size = 17543, upload-time = "2026-03-25T20:22:03.828Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/11/db3d5885d8528263d8adc260bb2d28ebf1270b96e98f0e0268d32b8d9900/tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30", size = 154704, upload-time = "2026-03-25T20:21:10.473Z" }, + { url = "https://files.pythonhosted.org/packages/6d/f7/675db52c7e46064a9aa928885a9b20f4124ecb9bc2e1ce74c9106648d202/tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a", size = 149454, upload-time = "2026-03-25T20:21:12.036Z" }, + { url = "https://files.pythonhosted.org/packages/61/71/81c50943cf953efa35bce7646caab3cf457a7d8c030b27cfb40d7235f9ee/tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076", size = 237561, upload-time = "2026-03-25T20:21:13.098Z" }, + { url = "https://files.pythonhosted.org/packages/48/c1/f41d9cb618acccca7df82aaf682f9b49013c9397212cb9f53219e3abac37/tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9", size = 243824, upload-time = "2026-03-25T20:21:14.569Z" }, + { url = "https://files.pythonhosted.org/packages/22/e4/5a816ecdd1f8ca51fb756ef684b90f2780afc52fc67f987e3c61d800a46d/tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c", size = 242227, upload-time = "2026-03-25T20:21:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/6b/49/2b2a0ef529aa6eec245d25f0c703e020a73955ad7edf73e7f54ddc608aa5/tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc", size = 247859, upload-time = "2026-03-25T20:21:17.001Z" }, + { url = "https://files.pythonhosted.org/packages/83/bd/6c1a630eaca337e1e78c5903104f831bda934c426f9231429396ce3c3467/tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049", size = 97204, upload-time = "2026-03-25T20:21:18.079Z" }, + { url = "https://files.pythonhosted.org/packages/42/59/71461df1a885647e10b6bb7802d0b8e66480c61f3f43079e0dcd315b3954/tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e", size = 108084, upload-time = "2026-03-25T20:21:18.978Z" }, + { url = "https://files.pythonhosted.org/packages/b8/83/dceca96142499c069475b790e7913b1044c1a4337e700751f48ed723f883/tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece", size = 95285, upload-time = "2026-03-25T20:21:20.309Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ba/42f134a3fe2b370f555f44b1d72feebb94debcab01676bf918d0cb70e9aa/tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a", size = 155924, upload-time = "2026-03-25T20:21:21.626Z" }, + { url = "https://files.pythonhosted.org/packages/dc/c7/62d7a17c26487ade21c5422b646110f2162f1fcc95980ef7f63e73c68f14/tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085", size = 150018, upload-time = "2026-03-25T20:21:23.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/05/79d13d7c15f13bdef410bdd49a6485b1c37d28968314eabee452c22a7fda/tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9", size = 244948, upload-time = "2026-03-25T20:21:24.04Z" }, + { url = "https://files.pythonhosted.org/packages/10/90/d62ce007a1c80d0b2c93e02cab211224756240884751b94ca72df8a875ca/tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5", size = 253341, upload-time = "2026-03-25T20:21:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/1a/7e/caf6496d60152ad4ed09282c1885cca4eea150bfd007da84aea07bcc0a3e/tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585", size = 248159, upload-time = "2026-03-25T20:21:26.364Z" }, + { url = "https://files.pythonhosted.org/packages/99/e7/c6f69c3120de34bbd882c6fba7975f3d7a746e9218e56ab46a1bc4b42552/tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1", size = 253290, upload-time = "2026-03-25T20:21:27.46Z" }, + { url = "https://files.pythonhosted.org/packages/d6/2f/4a3c322f22c5c66c4b836ec58211641a4067364f5dcdd7b974b4c5da300c/tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917", size = 98141, upload-time = "2026-03-25T20:21:28.492Z" }, + { url = "https://files.pythonhosted.org/packages/24/22/4daacd05391b92c55759d55eaee21e1dfaea86ce5c571f10083360adf534/tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9", size = 108847, upload-time = "2026-03-25T20:21:29.386Z" }, + { url = "https://files.pythonhosted.org/packages/68/fd/70e768887666ddd9e9f5d85129e84910f2db2796f9096aa02b721a53098d/tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257", size = 95088, upload-time = "2026-03-25T20:21:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/7b/61/cceae43728b7de99d9b847560c262873a1f6c98202171fd5ed62640b494b/tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe", size = 14583, upload-time = "2026-03-25T20:22:03.012Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +]