From 10c14a34c870d9d4a6562e1dcf7ca787a716730f Mon Sep 17 00:00:00 2001 From: linear3735 Date: Mon, 5 Oct 2026 10:16:07 +0800 Subject: [PATCH 1/4] Add the complete Laya CUDA worker and batch-1 kernel optimizations --- Cargo.lock | 82 +- Cargo.toml | 2 +- README.md | 14 +- docs/supported-models.md | 9 +- mkdocs.yml | 2 + recipe/README.md | 2 + recipe/laya/README.md | 1 + recipe/laya/native/README.md | 105 + recipe/laya/native/VALIDATION.md | 54 + recipe/laya/native/benchmark.py | 155 + recipe/laya/native/measurements.json | 12647 +++++++++++++++++++ recipe/laya/native/optimized-export.patch | 105 + src/backends/cuda/Cargo.toml | 9 + src/backends/cuda/README.md | 11 + src/backends/cuda/THIRD_PARTY.md | 5 + src/backends/cuda/build.sh | 84 + src/backends/cuda/kernels/laya_tilelang.py | 227 + src/backends/cuda/kernels/model_ops.cu | 258 + src/backends/cuda/kernels/rope_selected.py | 130 + src/backends/cuda/kernels/runtime.cu | 83 + src/backends/cuda/laya.backend.json | 22 + src/backends/cuda/licenses/Laya.txt | 176 + src/backends/cuda/licenses/PyTorch.txt | 84 + src/backends/cuda/src/lib.rs | 247 + src/backends/cuda/tools/build.py | 75 + src/backends/cuda/tools/export.py | 317 + src/backends/cuda/tools/export_tables.py | 65 + src/models/laya/Cargo.toml | 29 +- src/models/laya/README.md | 44 +- src/models/laya/src/artifacts.rs | 78 + src/models/laya/src/bin/laya-pack.rs | 16 + src/models/laya/src/bin/laya-run.rs | 63 + src/models/laya/src/bin/omni-laya.rs | 34 + src/models/laya/src/decision.rs | 154 + src/models/laya/src/executor.rs | 126 + src/models/laya/src/lib.rs | 12 + src/models/laya/src/model.rs | 591 + src/models/laya/src/packing.rs | 65 + src/models/laya/src/preprocess.rs | 415 + src/models/laya/src/processing.rs | 60 + src/models/laya/src/serve.rs | 96 + src/models/qwen3_5/native/Cargo.toml | 2 +- src/models/qwen3_5/native/src/json.rs | 125 +- src/runtime/README.md | 3 +- tests/cuda/test_laya_build.py | 115 + tests/laya/artifacts.rs | 156 + tests/laya/batch.rs | 65 + tests/laya/data/decisions.json | 18 + tests/laya/data/requests.json | 1 + tests/laya/decision.rs | 207 + tests/laya/model.rs | 29 + tests/laya/packing.rs | 62 + tests/laya/preprocess.rs | 318 + tests/laya/unit/decision.rs | 8 + tests/qwen3_5/json.rs | 11 + 55 files changed, 17783 insertions(+), 91 deletions(-) create mode 100644 recipe/laya/native/README.md create mode 100644 recipe/laya/native/VALIDATION.md create mode 100644 recipe/laya/native/benchmark.py create mode 100644 recipe/laya/native/measurements.json create mode 100644 recipe/laya/native/optimized-export.patch create mode 100644 src/backends/cuda/Cargo.toml create mode 100644 src/backends/cuda/THIRD_PARTY.md create mode 100755 src/backends/cuda/build.sh create mode 100644 src/backends/cuda/kernels/laya_tilelang.py create mode 100644 src/backends/cuda/kernels/model_ops.cu create mode 100644 src/backends/cuda/kernels/rope_selected.py create mode 100644 src/backends/cuda/kernels/runtime.cu create mode 100644 src/backends/cuda/laya.backend.json create mode 100644 src/backends/cuda/licenses/Laya.txt create mode 100644 src/backends/cuda/licenses/PyTorch.txt create mode 100644 src/backends/cuda/src/lib.rs create mode 100644 src/backends/cuda/tools/build.py create mode 100644 src/backends/cuda/tools/export.py create mode 100644 src/backends/cuda/tools/export_tables.py create mode 100644 src/models/laya/src/artifacts.rs create mode 100644 src/models/laya/src/bin/laya-pack.rs create mode 100644 src/models/laya/src/bin/laya-run.rs create mode 100644 src/models/laya/src/bin/omni-laya.rs create mode 100644 src/models/laya/src/decision.rs create mode 100644 src/models/laya/src/executor.rs create mode 100644 src/models/laya/src/model.rs create mode 100644 src/models/laya/src/packing.rs create mode 100644 src/models/laya/src/preprocess.rs create mode 100644 src/models/laya/src/processing.rs create mode 100644 src/models/laya/src/serve.rs create mode 100644 tests/cuda/test_laya_build.py create mode 100644 tests/laya/artifacts.rs create mode 100644 tests/laya/batch.rs create mode 100644 tests/laya/data/decisions.json create mode 100644 tests/laya/data/requests.json create mode 100644 tests/laya/decision.rs create mode 100644 tests/laya/model.rs create mode 100644 tests/laya/packing.rs create mode 100644 tests/laya/preprocess.rs create mode 100644 tests/laya/unit/decision.rs diff --git a/Cargo.lock b/Cargo.lock index 354a6120..11b8ba25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,21 @@ version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "2.13.2" @@ -256,6 +271,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "daachorse" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5614204febbc33cc07a2806aa6440b904ac012b68eecc37f4493ea4a76455a3d" + [[package]] name = "darling" version = "0.20.11" @@ -380,6 +401,17 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d817e038c30374a4bcb22f94d0a8a0e216958d4c3dcde369b1439fec4bdda6e6" +[[package]] +name = "fancy-regex" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + [[package]] name = "fastrand" version = "2.5.0" @@ -954,10 +986,18 @@ dependencies = [ "omni-runtime", "safetensors 0.8.0", "serde_json", - "tokenizers", + "tokenizers 0.22.2", "tokio", ] +[[package]] +name = "omni-cuda" +version = "0.1.0" +dependencies = [ + "anyhow", + "libloading", +] + [[package]] name = "omni-jev" version = "0.1.0" @@ -973,13 +1013,18 @@ name = "omni-laya" version = "0.1.0" dependencies = [ "anyhow", + "axum", "half", "memmap2", + "omni-cuda", + "omni-runtime", "safetensors 0.6.2", "serde", "serde_json", "sha2", "tempfile", + "tokenizers 0.23.2", + "tokio", ] [[package]] @@ -991,7 +1036,7 @@ dependencies = [ "omni-qwen3-5-native", "omni-runtime", "serde_json", - "tokenizers", + "tokenizers 0.22.2", "tokio", ] @@ -1713,6 +1758,39 @@ dependencies = [ "unicode_categories", ] +[[package]] +name = "tokenizers" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7afbf6e88718afcc138bad01d6ccc3051dbbc3b2ce9793d8b8a3aeb610969cfc" +dependencies = [ + "ahash", + "compact_str", + "daachorse", + "dary_heap", + "derive_builder", + "esaxx-rs", + "fancy-regex", + "getrandom 0.3.4", + "itertools", + "log", + "macro_rules_attribute", + "monostate", + "paste", + "rand 0.9.5", + "rayon", + "rayon-cond", + "regex", + "regex-syntax", + "serde", + "serde_json", + "spm_precompiled", + "thiserror", + "unicode-normalization-alignments", + "unicode-segmentation", + "unicode_categories", +] + [[package]] name = "tokio" version = "1.53.1" diff --git a/Cargo.toml b/Cargo.toml index de28591e..d5abbe60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["src/frontend", "src/runtime", "src/models/cua_s1/native", "src/models/qwen3_5/native", "src/models/open_jev/native", "src/models/laya"] +members = ["src/frontend", "src/runtime", "src/models/cua_s1/native", "src/models/qwen3_5/native", "src/models/open_jev/native", "src/models/laya", "src/backends/cuda"] resolver = "3" diff --git a/README.md b/README.md index 006179de..c1ed012f 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ Share processing and scheduling; let each model own its execution. The diagram shows the **target architecture**. Today the frontend forwards HTTP requests to separately running workers, whose handlers coordinate independent -processors and executors. Both native workers use shared FIFO admission and +processors and executors. Native workers use shared FIFO admission and blocking dispatch per loaded executor. Processing orchestration, batch budgets, compatibility grouping and dynamic batching remain planned. @@ -118,8 +118,8 @@ repository root. | [`recipe/`](recipe/) | Model setup instructions, launch commands, configuration examples, and example requests. | | [`docs/`](docs/) | Project documentation and architecture assets. | -The frontend, native runtime, both native workers, their shared Qwen3.5/3.8 -prefill implementation and the Laya checkpoint reader are Cargo workspace members. +The frontend, native runtime, the native workers, their shared Qwen3.5/3.8 +prefill implementation and the Laya CUDA backend are Cargo workspace members. The other model and backend directories currently document planned work; they do not prescribe process boundaries. @@ -141,14 +141,14 @@ for a CPU text worker and response checks, or the Cua-S1 recipes for the ## Supported Models -LAYA can run as an external Python worker for text requests; its -in-repository model engine is still planned. The Cua-S1 4B 0.2 `text` adapter +LAYA runs as an external Python worker or a native Rust/CUDA text worker on +Hopper. The Cua-S1 4B 0.2 `text` adapter runs as a Python worker or as a native worker on CUDA. Open-Jev-27B-v1.1 runs as a native Rust/CUDA worker: | Model | Status | | --- | --- | -| LAYA | [External worker](recipe/laya/README.md); [Python worker on Apple Silicon (MPS) and CPU](recipe/laya/apple-silicon.md); [CPU checkpoint reader](src/models/laya/README.md); model execution planned | +| LAYA | [External worker](recipe/laya/README.md); [Python worker on Apple Silicon (MPS) and CPU](recipe/laya/apple-silicon.md); [native Rust/CUDA worker on Hopper](recipe/laya/native/README.md) | | Cua-S1 4B 0.2 (`text` adapter) | [Python worker](recipe/cua_s1/text.md); [native worker](recipe/cua_s1/native.md), CUDA, run on sm_89 | | Open-Jev-27B-v1.1 | [Native Rust/CUDA worker](recipe/open_jev/native.md); eager independent text candidates; [H200 validation](recipe/open_jev/validation.md) | @@ -168,7 +168,7 @@ The current focus is the native Cua-S1 and Open-Jev CUDA workers and the serving benchmark harness. Planned work extends the shared runtime with processing orchestration, admission budgets, compatibility grouping and bounded dynamic batching with batch-capable executors, -the in-repository LAYA model engine, additional model engines and GPU backends +additional model engines and GPU backends including Metal, and per-model performance measurements as implementations are added and validated. diff --git a/docs/supported-models.md b/docs/supported-models.md index 3ec48cad..3c848f72 100644 --- a/docs/supported-models.md +++ b/docs/supported-models.md @@ -5,7 +5,7 @@ This page covers what runs from `main`. Models that are being added are tracked | Model | Worker | CPU | NVIDIA CUDA | Apple Metal | Requirements | | --- | --- | --- | --- | --- | --- | | LAYA, English checkpoint | [External worker](../recipe/laya/README.md) running the upstream Laya runtime, for text requests | Validated ([#2](https://github.com/ThinkFlowLab/system1-omni/pull/2)) | Unverified ([#39](https://github.com/ThinkFlowLab/system1-omni/issues/39)) | Unverified ([#3](https://github.com/ThinkFlowLab/system1-omni/issues/3)) | Python 3.12, `laya[serve]==0.3.20` | -| LAYA | In-repository model engine | Planned ([#14](https://github.com/ThinkFlowLab/system1-omni/issues/14)) | Planned ([#14](https://github.com/ThinkFlowLab/system1-omni/issues/14)) | Planned ([#3](https://github.com/ThinkFlowLab/system1-omni/issues/3)) | | +| LAYA, English checkpoint | [Native Rust worker](../recipe/laya/native/README.md) | Processing/checkpoint checks; no CPU inference | Hopper `sm_90a`; [validation scope](../recipe/laya/native/VALIDATION.md) | Not supported | CUDA toolkit, TileLang for AOT generation, pinned checkpoint and rotary tables | | Cua-S1 4B 0.2, `text` adapter | [Reference worker](../recipe/cua_s1/text.md) on Transformers and PEFT | Unverified | Validated ([#13](https://github.com/ThinkFlowLab/system1-omni/pull/13)) | Unverified | Python 3.12, the versions in `requirements-text.txt` | | Cua-S1 4B 0.2, `text` adapter | [Native Rust worker](../recipe/cua_s1/native.md) on the [Qwen3.5 CUDA kernels](../src/backends/cuda/qwen3_5/README.md) | Not supported | Validated on compute capability 8.9 ([#19](https://github.com/ThinkFlowLab/system1-omni/pull/19), [#52](https://github.com/ThinkFlowLab/system1-omni/pull/52)) | Not supported | Compute capability 8.0 or newer, the CUDA toolkit to build, weights merged with `export_text_merged.py` | | Cua-S1 4B 0.2, `multimodal` adapter | Reference worker on Transformers and PEFT, [`src/frontend/cua_s1.py`](../src/frontend/cua_s1.py); no recipe yet | Not supported | Validated ([#17](https://github.com/ThinkFlowLab/system1-omni/pull/17), [#18](https://github.com/ThinkFlowLab/system1-omni/pull/18)) | Not supported | The state is one PNG or JPEG image; upstream's `weights.lock.json` next to the base weights | @@ -19,7 +19,8 @@ The Cua-S1 workers answer `choice` questions only. Open-Jev supports `choice`, `score`, and `noul` text questions. The [architecture contracts](architecture.md) describe the native target. -Shared processing orchestration, scheduling, dynamic batching, and GPU decision -heads are planned; the existing native workers run independent single-prompt -prefills and compute their heads on the CPU. These target layers do not expand +Shared processing orchestration and dynamic batching remain planned. Native +workers reuse serial admission. Qwen workers run independent single-prompt +prefills with CPU heads; Laya packs questions within one request and runs its +scorer/action head on CUDA. These target layers do not expand the validated model or hardware coverage above. diff --git a/mkdocs.yml b/mkdocs.yml index f4632ee2..2aa3d936 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -54,6 +54,8 @@ nav: - Recipes: - recipe/README.md - Laya text worker: recipe/laya/README.md + - Laya native CUDA worker: recipe/laya/native/README.md + - Laya CUDA validation: recipe/laya/native/VALIDATION.md - Cua-S1 text worker: recipe/cua_s1/text.md - Cua-S1 native text worker: recipe/cua_s1/native.md - Contributing: CONTRIBUTING.md diff --git a/recipe/README.md b/recipe/README.md index 869909ef..c5f7b1a7 100644 --- a/recipe/README.md +++ b/recipe/README.md @@ -2,6 +2,8 @@ - [Laya text worker](laya/README.md): start the external Python worker, connect the Rust frontend and compare direct and proxied responses. +- [Laya native CUDA worker](laya/native/README.md): build the Hopper bundle and + serve English text decisions with Rust and CUDA. - [Laya on Apple Silicon](laya/apple-silicon.md): serve Laya on the Mac GPU with the Laya worker, put the frontend in front of it and run the benchmarks. - [Cua-S1 4B 0.2 text worker](cua_s1/text.md): download the pinned weights, start diff --git a/recipe/laya/README.md b/recipe/laya/README.md index be587eee..1aef7bad 100644 --- a/recipe/laya/README.md +++ b/recipe/laya/README.md @@ -1,6 +1,7 @@ # Laya text worker This recipe runs the external Laya Python package behind the Rust frontend. +For the Rust/CUDA worker on Hopper, see [native CUDA setup](native/README.md). It validates text decisions; image, audio and video inference are not covered. Run all commands from the repository root. To serve on the GPU of an Apple Silicon Mac, see diff --git a/recipe/laya/native/README.md b/recipe/laya/native/README.md new file mode 100644 index 00000000..d337f94c --- /dev/null +++ b/recipe/laya/native/README.md @@ -0,0 +1,105 @@ +# Laya native CUDA worker + +Run commands from the repository root on Linux with an allocated Hopper GPU. +This implements English Laya 0.3.20 text decisions. CUDA targets `sm_90a` only; +CPU/Metal inference, automatic language routing and multimodal inputs are not supported. + +## Prepare the checkpoint and bundle + +The recorded build uses Rust 1.98.1, CUDA 13.0, PyTorch 2.11.0 (`cu128`), +Laya 0.3.20 and TileLang 0.1.14. TileLang's host-stub ABI is checked +by the exporter: incompatible generated layouts fail instead of guessing. +Python is used for build/table export and measurement, not by native inference. + +```sh +hf download convaiinnovations/laya \ + --revision 55cf4c4ebb4ebe31b2550e8bdf3bd21b99753851 --local-dir weights/laya +export LAYA_CHECKPOINT="$PWD/weights/laya" +export LAYA_CUDA_BUNDLE="$PWD/weights/laya-cuda" +PYTHON=python3 src/backends/cuda/build.sh "$LAYA_CUDA_BUNDLE" 90 +python3 src/backends/cuda/tools/export_tables.py "$LAYA_CHECKPOINT" "$LAYA_CUDA_BUNDLE" +cargo build --release --locked -p omni-laya --features serve +cargo build --release --locked -p omni-jev +``` + +Table export uses an allocated GPU to reproduce official BF16 rotary-table +rounding. Keep the five checkpoint artifacts immutable after export. Startup +checks their hashes, four tables and library before loading CUDA. The executor +owns resident weights and bounded shape workspaces; allow several GiB of device +memory for the checkpoint, workspace and CUDA/cuBLAS context. + +## Start and check + +```sh +LAYA_HOST=127.0.0.1 LAYA_PORT=8000 target/release/omni-laya +``` + +The listener opens after a real warmup. In another terminal: + +```sh +OMNI_JEV_BACKEND_URL=http://127.0.0.1:8000 \ + OMNI_JEV_BIND=127.0.0.1:8080 target/release/omni-jev +``` + +Check the frontend from a third terminal: + +```sh +curl http://127.0.0.1:8080/health +curl http://127.0.0.1:8080/v1/systemone -H 'Content-Type: application/json' \ + -d '{"model":"english","state":"Please refund the duplicate charge.","questions":{"refund":{"type":"noul","instructions":"Does the customer ask for a refund?"}}}' +python3 recipe/compare_with_backend.py --model english \ + --backend http://127.0.0.1:8000 --frontend http://127.0.0.1:8080 +``` + +The worker admits one complete request with `SerialScheduler`. Questions within +that request retain their order; this is not cross-request or continuous batching. +Inputs are limited to 16 questions, 512 tokens per sequence and 2048 markers. +Invalid inputs return 422; unsupported content types return 415. Native failure +returns 500 and stops this executor, making health return 503. The unchanged +frontend retains its documented timeout/forwarding limits. + +For direct CLI execution, send one JSON request per line: + +```sh +printf '%s\n' '{"model":"english","state":"Refund it.","questions":{"q":{"type":"noul","instructions":"Refund?"}}}' \ + | target/release/laya-run "$LAYA_CHECKPOINT" "$LAYA_CUDA_BUNDLE" +``` + +`--eager` disables Graph. `--original-rope` selects the original RoPE for a +controlled comparison; neither changes checkpoint precision. Graph caches only +Encoder/Decision; scorer/action head and readback remain outside capture. + +## Verify and measure + +```sh +cargo fmt --all --check +cargo clippy --workspace --locked --all-targets --features omni-laya/serve -- -D warnings +cargo test --workspace --locked --features omni-laya/serve +python3 -m unittest discover -s tests/cuda -p 'test_*.py' +python3 recipe/laya/native/benchmark.py --checkpoint "$LAYA_CHECKPOINT" \ + --bundle "$LAYA_CUDA_BUNDLE" --output /tmp/laya-optimized-1 +``` + +The benchmark uses five B=1 inputs, 20 warmups and 100 samples per input. +It stores every measured engine time, startup/request logs, binary/library/input +hashes and actual loaded mappings. Run without Nsight; use profiler captures +only to explain bottlenecks. Startup, first Graph construction and HTTP are +outside its timing boundary. Response stability is not reference-model parity. + +To reconstruct the original GEMM configuration, copy the backend to an isolated +directory and reverse the supplied exporter patch; keep the current checkout intact: + +```sh +baseline_source=$(mktemp -d) +mkdir -p "$baseline_source/src/backends" +cp -R src/backends/cuda "$baseline_source/src/backends/cuda" +git -C "$baseline_source" apply -R "$PWD/recipe/laya/native/optimized-export.patch" +PYTHON=python3 "$baseline_source/src/backends/cuda/build.sh" "$PWD/weights/laya-cuda-original" 90 +cp "$LAYA_CUDA_BUNDLE"/rope_*.f32 "$LAYA_CUDA_BUNDLE/tables.json" weights/laya-cuda-original/ +python3 recipe/laya/native/benchmark.py --checkpoint "$LAYA_CHECKPOINT" \ + --bundle weights/laya-cuda-original --original-rope --output /tmp/laya-original-1 +``` + +Measure original→optimized→optimized→original, with unique output directories, +the same CLI and inputs. Repeat in eager mode separately. Do not sum historical +kernel gains or mix HTTP and CLI measurements. See [validation](VALIDATION.md). diff --git a/recipe/laya/native/VALIDATION.md b/recipe/laya/native/VALIDATION.md new file mode 100644 index 00000000..39e30939 --- /dev/null +++ b/recipe/laya/native/VALIDATION.md @@ -0,0 +1,54 @@ +# Laya CUDA validation + +The combination contains the selected RoPE tile, short QKV/output dispatch, +down N64, short GEGLU selection and long GEGLU BN32/static registers. It preserves +the original arithmetic and checkpoint precision. Failed/HOLD candidates are +excluded; this does not claim zero GPU bubbles or maximum occupancy. + +## Frozen native engine comparison + +These measurements precede the current-main integration. They used one frozen +Rust CLI with the original and optimized CUDA configurations, on one shared +H800, concurrency 1, FP16 token embeddings, BF16 projection matrices/activations and FP32 residuals/norms. Clocks +were not locked. JSON parsing, tokenization, padding/upload, forward/heads, +readback, decoding and response JSON write are included. HTTP, process/model +startup and warmup/cold Graph construction are excluded. + +| Graph input | Original p50 | Combined p50 | Latency reduction | Speedup | +| --- | ---: | ---: | ---: | ---: | +| choice, L48 | 2.5426 ms | 1.5957 ms | 37.24% | 1.59× | +| score, L64 | 2.5819 ms | 1.6101 ms | 37.64% | 1.60× | +| short, L48 | 2.5419 ms | 1.5959 ms | 37.22% | 1.59× | +| medium, L176 | 2.8666 ms | 1.9207 ms | 33.00% | 1.49× | +| long, L512 | 3.9926 ms | 3.0001 ms | 24.86% | 1.33× | + +Each entry pools two 100-sample passes. The 12 processes measured 6000 requests +across original/retained/combined variants, Graph/eager, in forward/reverse order. +All raw engine/client timings and original file hashes are in +[measurements.json](measurements.json); private host paths are omitted. +The original uses `--original-rope` and the reverse-patched exporter; both sides +share the same runtime and Graph setting. There is no single workload-weighted +percentage. The full pipeline was measured directly, not by adding kernel gains. + +The frozen CLI binary SHA256 is +`4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85`; +the combined library is +`eeb94478354b5b6f0b26c756263261dd61908a0aafd82f10b04b907c3d46cc36`. +Source kernels/runtime and exported library identity are retained in the evidence. +The earlier three-way numeric check covered 210 responses, 36 hidden-state +comparisons and six 17-request reuse sequences, bitwise equal to the original +native configuration. This tests implementation equivalence for fixed inputs, +not general model quality or all-input agreement with official PyTorch. + +## Integration checks + +The current-main integration retains checkpoint inventory checks and imports the +reviewed CPU parsing/decoding fixes. Its processor/packing and worker scheduling +are new consumers of the same device code. Normal CPU tests do not establish +full-checkpoint CUDA or HTTP parity. Integration-specific Linux/GPU/worker and +frontend checks must bind the actual new build; the table above is historical +engine evidence, not a measurement of the newly integrated HTTP service. + +Build and reproduction commands are in the [recipe](README.md). Full model +weight/tokenizer oracle checks remain explicit opt-in tests, with their pinned +artifact hashes; see the [model contract](../../../src/models/laya/README.md). diff --git a/recipe/laya/native/benchmark.py b/recipe/laya/native/benchmark.py new file mode 100644 index 00000000..43103b82 --- /dev/null +++ b/recipe/laya/native/benchmark.py @@ -0,0 +1,155 @@ +"""Measure warmed native CLI requests; run bundles in forward/reverse order.""" +import argparse +import hashlib +import json +import math +import os +from pathlib import Path +import selectors +import subprocess +import time + + +def sha(path): + with path.open("rb") as stream: + digest = hashlib.sha256() + for chunk in iter(lambda: stream.read(1 << 20), b""): + digest.update(chunk) + return digest.hexdigest() + + +def percentile(values, q): + values = sorted(values) + p = (len(values) - 1) * q + lo = int(p) + return values[lo] + (values[min(lo + 1, len(values) - 1)] - values[lo]) * (p - lo) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--binary", type=Path, default=Path("target/release/laya-run")) + parser.add_argument("--checkpoint", type=Path, required=True) + parser.add_argument("--bundle", type=Path, required=True) + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--eager", action="store_true") + parser.add_argument("--original-rope", action="store_true") + parser.add_argument("--warmup", type=int, default=20) + parser.add_argument("--samples", type=int, default=100) + args = parser.parse_args() + if args.warmup < 1 or args.samples < 1: + parser.error("warmup and samples must be positive") + fixtures = Path(__file__).resolve().parents[3] / "tests/laya/data/requests.json" + cases = [c for c in json.loads(fixtures.read_text()) + if c["name"] in ["choice", "score", "short_1", "medium_1", "long_1"]] + command = [str(args.binary.resolve()), str(args.checkpoint.resolve()), str(args.bundle.resolve())] + command += [flag for flag, enabled in [("--eager", args.eager), ("--original-rope", args.original_rope)] if enabled] + args.output.mkdir(parents=True, exist_ok=False) + env = dict(os.environ) + for key in ["LAYA_RAW_LOGITS", "LAYA_DUMP_DIR", "LAYA_DUMP_HIDDEN", "LAYA_VERIFY_WEIGHTS"]: + env.pop(key, None) + result = {"command": command, "binary_sha256": sha(args.binary), + "library_sha256": sha(args.bundle / "liblaya_cuda.so"), + "fixtures_sha256": sha(fixtures), "warmup": args.warmup, "samples": args.samples, + "boundary": "CLI parse/pack/upload/forward/heads/readback/decode/JSON write; startup and HTTP excluded", + "cases": {}} + selector = None + logs = {} + proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, env=env, bufsize=0) + try: + selector = selectors.DefaultSelector() + selector.register(proc.stdout, selectors.EVENT_READ, "stdout") + selector.register(proc.stderr, selectors.EVENT_READ, "stderr") + buffers = {"stdout": bytearray(), "stderr": bytearray()} + pending = [] + for kind in buffers: + logs[kind] = (args.output / f"{kind}.log").open("w") + + def event(deadline): + while not pending: + remaining = deadline - time.monotonic() + if remaining <= 0: + raise TimeoutError("native response deadline expired") + if not selector.get_map(): + raise RuntimeError(f"native exited: {proc.poll()}") + for key, _ in selector.select(remaining): + data = os.read(key.fd, 65536) + if not data: + selector.unregister(key.fileobj) + continue + buffer = buffers[key.data] + buffer.extend(data) + while b"\n" in buffer: + line, _, rest = buffer.partition(b"\n") + buffer[:] = rest + pending.append((key.data, line.decode())) + kind, line = pending.pop(0) + logs[kind].write(line + "\n") + return kind, line + + def infer(request): + payload = memoryview((json.dumps(request, ensure_ascii=False) + "\n").encode()) + while payload: + written = proc.stdin.write(payload) + if not written: + raise BrokenPipeError("native stdin stopped accepting input") + payload = payload[written:] + deadline = time.monotonic() + 10 + response, elapsed = None, None + while response is None or elapsed is None: + kind, line = event(deadline) + if kind == "stdout": + if response is not None: + raise RuntimeError("extra response") + response = json.loads(line) + if "error" in response: + raise RuntimeError(response) + elif line.startswith("engine_wall_ms="): + elapsed = float(line.split("=", 1)[1]) + if not math.isfinite(elapsed) or elapsed <= 0: + raise ValueError("invalid engine timing") + return response, elapsed + + deadline = time.monotonic() + 120 + while event(deadline) != ("stderr", "READY native Laya (Rust + CUDA)"): + pass + maps = Path(f"/proc/{proc.pid}/maps").read_text() + (args.output / "native.maps").write_text(maps) + loaded = {line.split(maxsplit=5)[-1] for line in maps.splitlines() if len(line.split(maxsplit=5)) == 6} + if str((args.bundle / "liblaya_cuda.so").resolve()) not in loaded: + raise RuntimeError("requested CUDA bundle is not loaded") + if "libpython" in maps or "libtorch" in maps: + raise RuntimeError("unexpected Python/Torch runtime mapping") + for case in cases: + for _ in range(args.warmup): + expected, _ = infer(case["request"]) + timings = [] + for _ in range(args.samples): + response, ms = infer(case["request"]) + if response != expected: + raise ValueError("response changed between repetitions") + timings.append(ms) + result["cases"][case["name"]] = { + "engine_wall_ms": timings, "p50_ms": percentile(timings, .5), + "p95_ms": percentile(timings, .95), "response": expected, + } + proc.stdin.close() + if proc.wait(timeout=10) != 0: + raise RuntimeError("native exited unsuccessfully") + (args.output / "benchmark.json").write_text(json.dumps(result, indent=2) + "\n") + finally: + if proc.poll() is None: + proc.terminate() + try: + proc.wait(timeout=10) + except subprocess.TimeoutExpired: + proc.kill() + proc.wait() + if selector is not None: + selector.close() + for stream in logs.values(): + stream.close() + + +if __name__ == "__main__": + main() diff --git a/recipe/laya/native/measurements.json b/recipe/laya/native/measurements.json new file mode 100644 index 00000000..109cf35d --- /dev/null +++ b/recipe/laya/native/measurements.json @@ -0,0 +1,12647 @@ +{ + "scope": "Historical frozen native CLI; original vs combined CUDA; not integration-branch or HTTP measurements", + "source_cli_sha256": "060b930b66c5d6475840bbddc2cb1c1d16b2f8b67a6c5539a5e2138d5d57dbff", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "checkpoint_revision": "55cf4c4ebb4ebe31b2550e8bdf3bd21b99753851", + "conditions": { + "GPU": "H800 sm_90a", + "precision": "BF16 activations/matrices, FP32 residual/norm", + "concurrency": 1, + "shared_GPU": true, + "locked_clocks": false, + "warmup_per_input": 20, + "measured_per_input_process": 100 + }, + "graph_total": { + "choice": { + "initial_p50_ms": 2.5425815, + "final_p50_ms": 1.5957219999999999, + "reduction_pct": 37.24008453612991, + "speedup": 1.5933737204851472, + "initial_p95_ms": 2.5579710999999996, + "final_p95_ms": 1.6334561 + }, + "score": { + "initial_p50_ms": 2.581856, + "final_p50_ms": 1.610148, + "reduction_pct": 37.63602617651799, + "speedup": 1.6034898655278895, + "initial_p95_ms": 2.59631785, + "final_p95_ms": 1.62487075 + }, + "short_1": { + "initial_p50_ms": 2.5419150000000004, + "final_p50_ms": 1.5958705, + "reduction_pct": 37.217786590031544, + "speedup": 1.592807812413351, + "initial_p95_ms": 2.55008585, + "final_p95_ms": 1.6025575 + }, + "medium_1": { + "initial_p50_ms": 2.8666485, + "final_p50_ms": 1.920663, + "reduction_pct": 32.999703312073315, + "speedup": 1.4925307042411917, + "initial_p95_ms": 2.88836035, + "final_p95_ms": 1.94167755 + }, + "long_1": { + "initial_p50_ms": 3.992647, + "final_p50_ms": 3.0001395, + "reduction_pct": 24.858383423327936, + "speedup": 1.3308204501824, + "initial_p95_ms": 4.0897625, + "final_p95_ms": 3.0332212 + } + }, + "runs": [ + { + "label": "round1-final-eager", + "raw_file_sha256": "a37be6553dd50556c8e1f05284a2ba3e6d52361733e440a2f21e451453e22e0c", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "eeb94478354b5b6f0b26c756263261dd61908a0aafd82f10b04b907c3d46cc36", + "mode": "eager", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.919435, + 1.904321, + 1.908758, + 1.905998, + 1.911174, + 1.906293, + 1.906806, + 1.918842, + 1.915827, + 1.909007, + 1.910656, + 1.907501, + 1.923505, + 1.90699, + 1.918911, + 1.905901, + 1.913025, + 1.908966, + 1.912392, + 1.904738, + 1.911366, + 1.904689, + 1.901113, + 1.904916, + 1.909653, + 1.905143, + 1.900436, + 1.899611, + 1.914642, + 1.909061, + 1.904098, + 1.899497, + 1.918734, + 1.900743, + 1.900799, + 1.896855, + 1.910221, + 1.897284, + 1.910397, + 1.901612, + 1.919908, + 1.897859, + 1.903701, + 1.904136, + 1.921249, + 1.894661, + 1.891863, + 1.894565, + 1.909225, + 1.888604, + 1.89268, + 1.891815, + 1.904602, + 1.888591, + 1.894317, + 1.889344, + 1.90184, + 1.897279, + 1.885914, + 1.898472, + 1.908659, + 1.888306, + 1.890093, + 1.89542, + 1.911863, + 1.895588, + 1.902865, + 1.894171, + 1.905773, + 1.888638, + 1.902492, + 1.893694, + 1.895618, + 1.899603, + 1.891324, + 1.890526, + 1.907107, + 1.893009, + 1.891992, + 1.891607, + 1.903733, + 1.903707, + 1.894762, + 1.899491, + 1.90372, + 1.893438, + 1.896181, + 1.893396, + 1.902217, + 1.894795, + 1.895112, + 1.888878, + 1.898781, + 1.891521, + 1.897182, + 1.890889, + 1.897868, + 1.888285, + 1.897226, + 1.889066 + ], + "client_rtt_ms": [ + 1.951468, + 1.929661, + 1.93831, + 1.941672, + 1.948597, + 1.932602, + 1.932326, + 1.944281, + 1.942754, + 1.935665, + 1.936052, + 1.935864, + 1.950634, + 1.942234, + 1.945706, + 1.932802, + 1.940424, + 1.934452, + 1.938116, + 1.933255, + 1.9394, + 1.93374, + 1.925717, + 1.935497, + 1.947197, + 1.931037, + 1.925262, + 1.930009, + 1.939826, + 1.937358, + 1.930573, + 1.925259, + 1.94488, + 1.927015, + 1.933971, + 1.926004, + 1.935525, + 1.926028, + 1.935601, + 1.933452, + 1.947284, + 1.926684, + 1.929649, + 1.933848, + 1.953212, + 1.919447, + 1.917971, + 1.920077, + 1.9363, + 1.913205, + 1.92199, + 1.91697, + 1.93196, + 1.91304, + 1.920585, + 1.922543, + 1.928309, + 1.923832, + 1.916197, + 1.923525, + 1.937801, + 1.913266, + 1.917434, + 1.921128, + 1.94009, + 1.929642, + 1.93025, + 1.918464, + 1.93142, + 1.914467, + 1.930086, + 1.918451, + 1.923476, + 1.92531, + 1.918406, + 1.922226, + 1.933613, + 1.920195, + 1.918703, + 1.918675, + 1.92905, + 1.931001, + 1.920329, + 1.924913, + 1.928996, + 1.927883, + 1.922568, + 1.920263, + 1.928339, + 1.925786, + 1.921685, + 1.91809, + 1.923864, + 1.921576, + 1.923377, + 1.918809, + 1.936088, + 1.916457, + 1.925129, + 1.917167 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.931379, + 1.926666, + 1.923522, + 1.926531, + 1.932038, + 1.917161, + 1.922095, + 1.918205, + 1.920951, + 1.920693, + 1.918607, + 1.916593, + 1.935966, + 1.916215, + 1.917961, + 1.923709, + 1.934343, + 1.917211, + 1.922389, + 1.917368, + 1.932682, + 1.916653, + 1.919767, + 1.929033, + 1.931639, + 1.921087, + 1.919342, + 1.941521, + 1.913354, + 1.901348, + 1.915317, + 1.912851, + 1.915134, + 1.908198, + 1.910723, + 1.905526, + 1.91664, + 1.900412, + 1.909422, + 1.917761, + 1.915169, + 1.914135, + 1.910841, + 1.900471, + 1.919065, + 1.906008, + 1.914647, + 1.915901, + 1.917966, + 1.906233, + 1.912106, + 1.910491, + 1.920087, + 1.897506, + 1.920599, + 1.908592, + 1.920579, + 1.905892, + 1.912808, + 1.911895, + 1.914506, + 1.904143, + 1.910545, + 1.918782, + 1.922198, + 1.914728, + 1.90585, + 1.905311, + 1.910749, + 1.908643, + 1.903204, + 1.901175, + 1.917422, + 1.913869, + 1.917099, + 1.902818, + 1.920923, + 1.903006, + 1.909624, + 1.908247, + 1.927395, + 1.908573, + 1.918719, + 1.907032, + 1.920794, + 1.901194, + 1.91416, + 1.916267, + 1.915924, + 1.924475, + 1.914587, + 1.923667, + 1.939242, + 1.919062, + 1.924036, + 1.927408, + 1.934087, + 1.923373, + 1.913826, + 1.91459 + ], + "client_rtt_ms": [ + 1.957542, + 1.953366, + 1.958526, + 1.955678, + 1.957157, + 1.94478, + 1.949078, + 1.949437, + 1.947665, + 1.949788, + 1.946857, + 1.951715, + 1.963635, + 1.944748, + 1.945303, + 1.951784, + 1.960971, + 1.944716, + 1.949157, + 1.954742, + 1.961132, + 1.946682, + 1.946362, + 1.960389, + 1.960456, + 1.949929, + 1.94734, + 1.967743, + 1.946413, + 1.930422, + 1.94449, + 1.9412, + 1.941786, + 1.938147, + 1.936005, + 1.932766, + 1.951201, + 1.92643, + 1.936177, + 1.95068, + 1.943083, + 1.94349, + 1.936845, + 1.930725, + 1.94442, + 1.939629, + 1.940606, + 1.945239, + 1.945125, + 1.935908, + 1.937449, + 1.937395, + 1.946186, + 1.928965, + 1.957302, + 1.934771, + 1.948092, + 1.932608, + 1.94059, + 1.939699, + 1.941187, + 1.929742, + 1.946134, + 1.945634, + 1.949522, + 1.942475, + 1.933734, + 1.929911, + 1.935751, + 1.937598, + 1.93181, + 1.935337, + 1.950086, + 1.940302, + 1.94618, + 1.929473, + 1.949813, + 1.930502, + 1.938901, + 1.945253, + 1.95679, + 1.935044, + 1.950552, + 1.933257, + 1.95016, + 1.927609, + 1.94319, + 1.942015, + 1.951157, + 1.953953, + 1.944109, + 1.950287, + 1.979805, + 1.945791, + 1.950114, + 1.955509, + 1.969371, + 1.94995, + 1.942494, + 1.943053 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.899944, + 1.90039, + 1.895695, + 1.892696, + 1.899771, + 1.895907, + 1.892875, + 1.88561, + 1.903552, + 1.896341, + 1.8927, + 1.889347, + 1.90122, + 1.889514, + 1.884142, + 1.892459, + 1.903845, + 1.902879, + 1.892709, + 1.891714, + 1.909915, + 1.88419, + 1.89641, + 1.887136, + 1.895591, + 1.883768, + 1.887103, + 1.88978, + 1.89869, + 1.883948, + 1.888834, + 1.888776, + 1.893312, + 1.890387, + 1.894099, + 1.893337, + 1.888214, + 1.879477, + 1.892673, + 1.885485, + 1.900531, + 1.887853, + 1.887787, + 1.888522, + 1.898249, + 1.877957, + 1.897325, + 1.885565, + 1.900732, + 1.898846, + 1.900352, + 1.894179, + 1.908879, + 1.891087, + 1.892691, + 1.893233, + 1.901039, + 1.897623, + 1.887333, + 1.895945, + 1.90602, + 1.885884, + 1.889364, + 1.89, + 1.905458, + 1.888946, + 1.894269, + 1.89624, + 1.899783, + 1.885493, + 1.891631, + 1.889682, + 1.894722, + 1.897697, + 1.891433, + 1.885541, + 1.898409, + 1.887051, + 1.899089, + 1.892971, + 1.90018, + 1.882617, + 1.899407, + 1.891487, + 1.904005, + 1.884809, + 1.898284, + 1.889801, + 1.906804, + 1.890135, + 1.890628, + 1.892028, + 1.914786, + 1.88782, + 1.899936, + 1.893502, + 1.897354, + 1.893282, + 1.886855, + 1.893424 + ], + "client_rtt_ms": [ + 1.932708, + 1.928298, + 1.919625, + 1.921236, + 1.925123, + 1.924522, + 1.918409, + 1.914999, + 1.9288, + 1.92321, + 1.917235, + 1.916617, + 1.9334, + 1.917203, + 1.90839, + 1.919717, + 1.92837, + 1.931258, + 1.916451, + 1.916439, + 1.93551, + 1.909291, + 1.923715, + 1.910987, + 1.92783, + 1.907612, + 1.911722, + 1.914293, + 1.922443, + 1.907761, + 1.913693, + 1.912705, + 1.919417, + 1.913852, + 1.918817, + 1.91989, + 1.921159, + 1.903586, + 1.918251, + 1.908921, + 1.925382, + 1.910721, + 1.911919, + 1.913585, + 1.922536, + 1.901982, + 1.921191, + 1.914553, + 1.925875, + 1.932318, + 1.924839, + 1.91962, + 1.934499, + 1.916561, + 1.9159, + 1.92011, + 1.924987, + 1.922806, + 1.910968, + 1.921345, + 1.928484, + 1.917874, + 1.912818, + 1.915889, + 1.929393, + 1.9143, + 1.91919, + 1.923034, + 1.924974, + 1.91158, + 1.916208, + 1.913163, + 1.918844, + 1.931359, + 1.916577, + 1.912361, + 1.923676, + 1.911478, + 1.924648, + 1.91605, + 1.923987, + 1.908255, + 1.927427, + 1.917012, + 1.929333, + 1.909846, + 1.931066, + 1.915219, + 1.932217, + 1.915349, + 1.916501, + 1.917478, + 1.942118, + 1.912759, + 1.924408, + 1.917517, + 1.922405, + 1.916644, + 1.91913, + 1.918491 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 2.235586, + 2.242021, + 2.218957, + 2.231959, + 2.225742, + 2.218305, + 2.224752, + 2.218196, + 2.240116, + 2.220008, + 2.223647, + 2.226447, + 2.235575, + 2.219169, + 2.208318, + 2.221195, + 2.235263, + 2.219567, + 2.211649, + 2.229967, + 2.251985, + 2.247282, + 2.23555, + 2.224187, + 2.22965, + 2.223234, + 2.221403, + 2.208762, + 2.231112, + 2.212108, + 2.230451, + 2.21258, + 2.230428, + 2.217833, + 2.222136, + 2.20439, + 2.222444, + 2.22029, + 2.219361, + 2.215088, + 2.237777, + 2.229325, + 2.219362, + 2.212415, + 2.22782, + 2.218033, + 2.233617, + 2.218721, + 2.233023, + 2.228537, + 2.217443, + 2.212714, + 2.225011, + 2.207081, + 2.214348, + 2.218266, + 2.22384, + 2.225667, + 2.214631, + 2.208356, + 2.216417, + 2.204714, + 2.208744, + 2.198444, + 2.211651, + 2.219316, + 2.220382, + 2.217897, + 2.223123, + 2.195115, + 2.20686, + 2.202329, + 2.223702, + 2.215566, + 2.208671, + 2.216911, + 2.224268, + 2.235572, + 2.225678, + 2.207641, + 2.234313, + 2.215267, + 2.216099, + 2.233916, + 2.256774, + 2.226738, + 2.218056, + 2.207712, + 2.211888, + 2.216685, + 2.215237, + 2.233195, + 2.229085, + 2.211134, + 2.222154, + 2.211245, + 2.225951, + 2.23016, + 2.222713, + 2.223217 + ], + "client_rtt_ms": [ + 2.264722, + 2.271647, + 2.254028, + 2.259018, + 2.25188, + 2.244841, + 2.252391, + 2.244302, + 2.268226, + 2.247116, + 2.250476, + 2.254168, + 2.262276, + 2.248204, + 2.244071, + 2.248848, + 2.262805, + 2.247374, + 2.23993, + 2.255747, + 2.278514, + 2.274366, + 2.262735, + 2.252868, + 2.257865, + 2.250875, + 2.248662, + 2.244924, + 2.257945, + 2.239221, + 2.262856, + 2.23938, + 2.258831, + 2.245491, + 2.249043, + 2.229471, + 2.249248, + 2.245746, + 2.248056, + 2.250912, + 2.265171, + 2.259152, + 2.246598, + 2.240624, + 2.255018, + 2.246678, + 2.263411, + 2.245803, + 2.26373, + 2.257013, + 2.246486, + 2.246798, + 2.254045, + 2.233555, + 2.240727, + 2.245258, + 2.250606, + 2.253617, + 2.241559, + 2.234884, + 2.241389, + 2.230815, + 2.235102, + 2.232874, + 2.238981, + 2.246987, + 2.247355, + 2.244776, + 2.250239, + 2.221721, + 2.232037, + 2.232459, + 2.250414, + 2.244439, + 2.235556, + 2.245413, + 2.258256, + 2.264391, + 2.257047, + 2.234918, + 2.261979, + 2.241874, + 2.243764, + 2.260388, + 2.285038, + 2.253957, + 2.24305, + 2.234031, + 2.246368, + 2.244037, + 2.241619, + 2.259909, + 2.255844, + 2.240443, + 2.250073, + 2.238054, + 2.260691, + 2.257108, + 2.25024, + 2.252007 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.324099, + 3.271673, + 3.311392, + 3.320579, + 3.31872, + 3.316567, + 3.282808, + 3.270053, + 3.339122, + 3.320093, + 3.280764, + 3.316692, + 3.30496, + 3.303795, + 3.287782, + 3.308858, + 3.313881, + 3.304978, + 3.316437, + 3.308135, + 3.296501, + 3.334761, + 3.324934, + 3.314235, + 3.318173, + 3.310772, + 3.289006, + 3.313191, + 3.312761, + 3.308905, + 3.300408, + 3.299673, + 3.321696, + 3.32896, + 3.31595, + 3.310432, + 3.314766, + 3.264509, + 3.281611, + 3.309076, + 3.317757, + 3.303355, + 3.306485, + 3.305024, + 3.288313, + 3.359666, + 3.347287, + 3.331063, + 3.327109, + 3.293466, + 3.283571, + 3.308554, + 3.322618, + 3.317072, + 3.316594, + 3.302345, + 3.3106, + 3.2686, + 3.294692, + 3.313579, + 3.321882, + 3.291187, + 3.313338, + 3.30814, + 3.327147, + 3.300492, + 3.311625, + 3.287056, + 3.351178, + 3.347674, + 3.329324, + 3.304309, + 3.316127, + 3.315349, + 3.289688, + 3.275306, + 3.335963, + 3.317426, + 3.324223, + 3.311087, + 3.293843, + 3.284321, + 3.300547, + 3.308458, + 3.322256, + 3.303098, + 3.305009, + 3.31021, + 3.291613, + 3.297672, + 3.306463, + 3.309476, + 3.347089, + 3.336759, + 3.314408, + 3.303518, + 3.304531, + 3.293995, + 3.301987, + 3.303389 + ], + "client_rtt_ms": [ + 3.363261, + 3.304772, + 3.344546, + 3.354456, + 3.352548, + 3.356422, + 3.314665, + 3.302228, + 3.37191, + 3.353574, + 3.313793, + 3.349729, + 3.339488, + 3.335432, + 3.319956, + 3.343067, + 3.348041, + 3.347513, + 3.351212, + 3.342489, + 3.329505, + 3.368177, + 3.358758, + 3.346926, + 3.35155, + 3.345477, + 3.321434, + 3.34576, + 3.345138, + 3.349808, + 3.333743, + 3.335756, + 3.355, + 3.363283, + 3.348838, + 3.342444, + 3.350773, + 3.301066, + 3.312896, + 3.343139, + 3.351564, + 3.343525, + 3.339987, + 3.339231, + 3.320872, + 3.39611, + 3.380369, + 3.365044, + 3.361883, + 3.328425, + 3.319534, + 3.34082, + 3.357528, + 3.35873, + 3.351007, + 3.336982, + 3.345216, + 3.301666, + 3.328831, + 3.347248, + 3.354582, + 3.324076, + 3.347745, + 3.341803, + 3.360704, + 3.333843, + 3.352841, + 3.320953, + 3.384785, + 3.380293, + 3.362458, + 3.33897, + 3.349171, + 3.348827, + 3.322666, + 3.30703, + 3.369145, + 3.352721, + 3.366083, + 3.345787, + 3.325771, + 3.31729, + 3.33451, + 3.343341, + 3.369259, + 3.336818, + 3.339891, + 3.344773, + 3.322831, + 3.333424, + 3.349035, + 3.343159, + 3.381892, + 3.371402, + 3.353632, + 3.337853, + 3.338363, + 3.325862, + 3.334578, + 3.33542 + ] + } + } + }, + { + "label": "round1-final-graph", + "raw_file_sha256": "2496b92693c968745cc6453779a044eb37584949343bb6ebf591e80b5fd956f3", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "eeb94478354b5b6f0b26c756263261dd61908a0aafd82f10b04b907c3d46cc36", + "mode": "graph", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.603869, + 1.601749, + 1.603082, + 1.605291, + 1.597608, + 1.598175, + 1.599258, + 1.59948, + 1.595585, + 1.600288, + 1.608152, + 1.603936, + 1.606129, + 1.599369, + 1.604897, + 1.603676, + 1.602173, + 1.608673, + 1.603183, + 1.604278, + 1.610614, + 1.606646, + 1.597962, + 1.59825, + 1.604533, + 1.602566, + 2.018847, + 1.649318, + 1.629689, + 1.615151, + 1.614248, + 1.611687, + 1.608909, + 1.613281, + 1.608686, + 1.605644, + 1.599809, + 1.596135, + 1.602023, + 1.599517, + 1.601628, + 1.601733, + 1.600918, + 1.592324, + 1.594718, + 1.595895, + 1.597258, + 1.599885, + 1.600982, + 1.596859, + 1.593628, + 1.59622, + 1.593916, + 1.598902, + 1.591046, + 1.597654, + 1.597669, + 1.601102, + 1.596776, + 1.588943, + 1.59276, + 1.586937, + 1.591675, + 1.586734, + 1.589024, + 1.583623, + 1.581723, + 1.590856, + 1.583071, + 1.588378, + 1.581639, + 1.593659, + 1.591873, + 1.595823, + 1.595483, + 1.595232, + 1.592438, + 1.590638, + 1.588076, + 1.583163, + 1.587169, + 1.583427, + 1.586122, + 1.584692, + 1.585572, + 1.590911, + 1.588224, + 1.592932, + 1.590673, + 1.598681, + 1.587507, + 1.590849, + 1.584925, + 1.588964, + 1.586518, + 1.581581, + 1.58654, + 1.590121, + 1.589222, + 1.586426 + ], + "client_rtt_ms": [ + 1.630116, + 1.630619, + 1.628784, + 1.64044, + 1.628976, + 1.623301, + 1.624677, + 1.624651, + 1.624383, + 1.628787, + 1.634235, + 1.632836, + 1.633182, + 1.632814, + 1.631691, + 1.629667, + 1.633732, + 1.633791, + 1.631912, + 1.628801, + 1.637605, + 1.633293, + 1.62193, + 1.627507, + 1.640624, + 1.628084, + 2.170401, + 1.67488, + 1.656326, + 1.637839, + 1.637556, + 1.640974, + 1.63626, + 1.641017, + 1.644231, + 1.63381, + 1.624577, + 1.623609, + 1.628202, + 1.625605, + 1.6272, + 1.62928, + 1.63003, + 1.618432, + 1.625814, + 1.626986, + 1.621719, + 1.629388, + 1.629386, + 1.624208, + 1.619418, + 1.620147, + 1.620624, + 1.622775, + 1.619535, + 1.629099, + 1.622398, + 1.628002, + 1.623184, + 1.616479, + 1.618591, + 1.611058, + 1.621653, + 1.610915, + 1.617113, + 1.615053, + 1.606873, + 1.616969, + 1.606103, + 1.615244, + 1.608703, + 1.620817, + 1.616992, + 1.622106, + 1.628603, + 1.629936, + 1.619099, + 1.617588, + 1.612819, + 1.610204, + 1.611401, + 1.611896, + 1.610813, + 1.608145, + 1.610395, + 1.624668, + 1.617961, + 1.618419, + 1.616223, + 1.628268, + 1.612472, + 1.618847, + 1.60853, + 1.616254, + 1.611732, + 1.604986, + 1.624566, + 1.616819, + 1.618473, + 1.611287 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.614324, + 1.613581, + 1.606513, + 1.613507, + 1.617269, + 1.60986, + 1.612658, + 1.615306, + 1.61059, + 1.622061, + 1.616071, + 1.650342, + 1.620877, + 1.619231, + 1.613249, + 1.617387, + 1.612925, + 1.608988, + 1.608727, + 1.60621, + 1.601287, + 1.60701, + 1.605488, + 1.607934, + 1.616255, + 1.612468, + 1.610655, + 1.619982, + 1.61709, + 1.607553, + 1.60851, + 1.615614, + 1.606785, + 1.613749, + 1.609412, + 1.618099, + 1.61377, + 1.613516, + 1.610051, + 1.611708, + 1.611856, + 1.611385, + 1.619487, + 1.610353, + 1.611118, + 1.614653, + 1.611244, + 1.613119, + 1.612881, + 1.604749, + 1.621762, + 1.610367, + 1.611699, + 1.614199, + 1.613008, + 1.612955, + 1.607142, + 1.617899, + 1.611011, + 1.608016, + 1.61132, + 1.605472, + 1.612816, + 1.615504, + 1.613029, + 1.613987, + 1.612145, + 1.606046, + 1.611003, + 1.611473, + 1.610544, + 1.606293, + 1.605084, + 1.600338, + 1.608656, + 1.601196, + 1.604501, + 1.604778, + 1.610908, + 1.607632, + 1.60864, + 1.613556, + 1.609064, + 1.616778, + 1.607261, + 1.612353, + 1.609572, + 1.61137, + 1.605237, + 1.616159, + 1.628678, + 1.624422, + 1.625214, + 1.624961, + 1.627131, + 1.625616, + 1.625322, + 1.618723, + 1.624866, + 1.622267 + ], + "client_rtt_ms": [ + 1.640364, + 1.640848, + 1.643084, + 1.642704, + 1.645628, + 1.636257, + 1.643478, + 1.644289, + 1.637326, + 1.651451, + 1.643865, + 1.683541, + 1.64782, + 1.650435, + 1.639958, + 1.643164, + 1.642906, + 1.63388, + 1.633431, + 1.637605, + 1.627505, + 1.634831, + 1.630555, + 1.63794, + 1.641947, + 1.638717, + 1.638534, + 1.644898, + 1.650658, + 1.633879, + 1.635917, + 1.641833, + 1.633744, + 1.642742, + 1.634821, + 1.644225, + 1.652456, + 1.640417, + 1.635748, + 1.639885, + 1.639914, + 1.638443, + 1.644554, + 1.636722, + 1.636064, + 1.648275, + 1.637322, + 1.641395, + 1.638997, + 1.631222, + 1.648203, + 1.635574, + 1.640142, + 1.644349, + 1.648166, + 1.639638, + 1.634401, + 1.645616, + 1.636214, + 1.638119, + 1.636627, + 1.631319, + 1.654612, + 1.642219, + 1.640299, + 1.640859, + 1.642204, + 1.632474, + 1.636827, + 1.641821, + 1.636258, + 1.640473, + 1.633832, + 1.62512, + 1.63744, + 1.628281, + 1.630297, + 1.629947, + 1.635546, + 1.648157, + 1.636486, + 1.642911, + 1.637361, + 1.642893, + 1.63259, + 1.637989, + 1.638156, + 1.636248, + 1.637611, + 1.644736, + 1.654051, + 1.653267, + 1.652181, + 1.651681, + 1.653466, + 1.653175, + 1.658464, + 1.645205, + 1.652183, + 1.650821 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.60506, + 1.600424, + 1.602201, + 1.598484, + 1.593581, + 1.594499, + 1.596887, + 1.602086, + 1.596501, + 1.597429, + 1.595816, + 1.595727, + 1.595165, + 1.590488, + 1.591648, + 1.590524, + 1.588497, + 1.591251, + 1.600347, + 1.597484, + 1.592109, + 1.596511, + 1.60689, + 1.598869, + 1.598022, + 1.596565, + 1.595659, + 1.595481, + 1.6049, + 1.601504, + 1.59618, + 1.599327, + 1.600857, + 1.600107, + 1.601302, + 1.599814, + 1.596582, + 1.600397, + 1.599182, + 1.600379, + 1.593469, + 1.599799, + 1.595785, + 1.597658, + 1.602038, + 1.599608, + 1.598763, + 1.601635, + 1.60301, + 1.606004, + 1.596698, + 1.59895, + 1.599213, + 1.601332, + 1.596146, + 1.59647, + 1.603119, + 1.600895, + 1.598613, + 1.598301, + 1.598094, + 1.601517, + 1.594287, + 1.594995, + 1.591748, + 1.593302, + 1.588231, + 1.592112, + 1.595362, + 1.599769, + 1.607233, + 1.602402, + 1.59688, + 1.598722, + 1.595889, + 1.602795, + 1.587716, + 1.588235, + 1.590266, + 1.588971, + 1.589549, + 1.599085, + 1.596788, + 1.602043, + 1.59344, + 1.596841, + 1.60402, + 1.605688, + 1.599499, + 1.596142, + 1.593747, + 1.595279, + 1.598126, + 1.598402, + 1.601852, + 1.60075, + 1.596218, + 1.598859, + 1.597479, + 1.593183 + ], + "client_rtt_ms": [ + 1.643502, + 1.625451, + 1.626994, + 1.624501, + 1.620566, + 1.620194, + 1.621533, + 1.630904, + 1.620705, + 1.624882, + 1.621595, + 1.6217, + 1.629059, + 1.614737, + 1.618699, + 1.613952, + 1.611932, + 1.61511, + 1.623861, + 1.621535, + 1.615972, + 1.621566, + 1.634736, + 1.62224, + 1.635509, + 1.621638, + 1.621831, + 1.619947, + 1.628812, + 1.629435, + 1.621324, + 1.625349, + 1.627894, + 1.625389, + 1.625664, + 1.625361, + 1.631941, + 1.626133, + 1.622702, + 1.624893, + 1.617437, + 1.626362, + 1.621006, + 1.622377, + 1.626839, + 1.623745, + 1.625678, + 1.626015, + 1.633264, + 1.63837, + 1.62129, + 1.627881, + 1.623247, + 1.629083, + 1.620693, + 1.620828, + 1.631114, + 1.624928, + 1.624028, + 1.623101, + 1.622256, + 1.635969, + 1.618224, + 1.621612, + 1.616479, + 1.620747, + 1.613297, + 1.616283, + 1.621265, + 1.624594, + 1.63508, + 1.626834, + 1.621554, + 1.63393, + 1.621435, + 1.628742, + 1.611992, + 1.611786, + 1.616455, + 1.612234, + 1.614775, + 1.623938, + 1.624488, + 1.627615, + 1.619, + 1.623081, + 1.63848, + 1.633536, + 1.624436, + 1.620395, + 1.618861, + 1.6197, + 1.625952, + 1.623042, + 1.627046, + 1.626702, + 1.622237, + 1.62337, + 1.638601, + 1.615343 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 1.933768, + 1.928834, + 1.930538, + 1.940071, + 1.917067, + 1.924203, + 1.935404, + 1.928029, + 1.913472, + 1.928799, + 1.933686, + 1.93465, + 1.923687, + 1.918921, + 1.923118, + 1.929264, + 1.926423, + 1.935506, + 1.94043, + 1.973899, + 1.976064, + 1.963747, + 1.949884, + 1.937783, + 1.922311, + 1.932504, + 1.925575, + 1.924018, + 1.920702, + 1.923286, + 1.918994, + 1.918482, + 1.906896, + 1.916014, + 1.917612, + 1.906249, + 1.904134, + 1.906075, + 1.911152, + 1.919442, + 1.922374, + 1.913194, + 1.944834, + 1.926632, + 1.931432, + 1.917817, + 1.926839, + 1.902305, + 1.899535, + 1.904487, + 1.92594, + 1.914234, + 1.921777, + 1.921633, + 1.913504, + 1.914146, + 1.925722, + 1.922333, + 1.904501, + 1.909063, + 1.914085, + 1.905823, + 1.906448, + 1.927264, + 1.913887, + 1.904998, + 1.91951, + 1.917743, + 1.899512, + 1.900349, + 1.908889, + 1.913025, + 1.912051, + 1.917757, + 1.922887, + 1.920524, + 1.916286, + 1.900705, + 1.900938, + 1.905037, + 1.899873, + 1.904199, + 1.921333, + 1.941567, + 1.940356, + 1.937279, + 1.929907, + 1.908089, + 1.908071, + 1.904123, + 1.903888, + 1.905523, + 1.912222, + 1.918846, + 1.917164, + 1.923344, + 1.918682, + 1.910839, + 1.900606, + 1.912591 + ], + "client_rtt_ms": [ + 1.958846, + 1.954663, + 1.964557, + 1.969882, + 1.943477, + 1.953258, + 1.961302, + 1.957219, + 1.939669, + 1.95673, + 1.960886, + 1.963596, + 1.949245, + 1.946958, + 1.957535, + 1.95939, + 1.953421, + 1.963879, + 1.96904, + 2.005031, + 2.00404, + 1.992616, + 1.97653, + 1.965155, + 1.948429, + 1.961544, + 1.951915, + 1.957992, + 1.947116, + 1.952884, + 1.944914, + 1.945115, + 1.932961, + 1.947651, + 1.943904, + 1.934714, + 1.929434, + 1.933696, + 1.935997, + 1.95703, + 1.950768, + 1.939777, + 1.974113, + 1.952902, + 1.958103, + 1.944733, + 1.953629, + 1.927984, + 1.925519, + 1.931021, + 1.952079, + 1.947908, + 1.949666, + 1.949062, + 1.940443, + 1.939969, + 1.952576, + 1.948242, + 1.931855, + 1.934838, + 1.943931, + 1.931738, + 1.935135, + 1.960773, + 1.942501, + 1.93126, + 1.946135, + 1.944285, + 1.925383, + 1.925827, + 1.935463, + 1.939439, + 1.943884, + 1.944803, + 1.949303, + 1.946463, + 1.95086, + 1.926589, + 1.926845, + 1.930169, + 1.926212, + 1.930121, + 1.948519, + 1.970235, + 1.969072, + 1.963806, + 1.963972, + 1.934597, + 1.940297, + 1.932903, + 1.930181, + 1.934838, + 1.939327, + 1.949019, + 1.943351, + 1.949191, + 1.945568, + 1.938692, + 1.926978, + 1.938746 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.012018, + 2.977064, + 2.982657, + 2.991235, + 3.0132, + 3.007682, + 3.018364, + 3.002059, + 2.9742, + 3.005645, + 3.007732, + 3.030027, + 3.034571, + 3.018354, + 3.011071, + 3.016909, + 3.021971, + 3.019238, + 3.010748, + 3.003395, + 3.00492, + 3.069664, + 3.028007, + 3.007674, + 2.976171, + 2.983755, + 3.014105, + 3.003513, + 3.017981, + 3.020085, + 3.035329, + 3.004486, + 3.013325, + 2.984082, + 3.02041, + 3.025279, + 3.020324, + 3.033204, + 3.024014, + 3.024394, + 3.002636, + 3.008234, + 3.002766, + 3.010313, + 3.021625, + 3.062651, + 3.026196, + 3.01829, + 3.013959, + 3.022233, + 3.028216, + 3.020499, + 2.984367, + 2.991611, + 3.019447, + 3.020785, + 3.028654, + 3.026603, + 3.033548, + 3.018259, + 3.016531, + 3.017755, + 3.010276, + 3.01785, + 3.010475, + 2.989326, + 3.004544, + 3.002236, + 3.049696, + 3.046138, + 3.032048, + 2.983417, + 3.01431, + 2.98699, + 3.011622, + 3.014312, + 3.028925, + 3.020904, + 3.023939, + 3.010433, + 3.013436, + 3.026394, + 3.007926, + 3.007198, + 2.989177, + 3.000287, + 2.986253, + 3.001871, + 2.972963, + 3.00799, + 2.999871, + 3.00805, + 3.049694, + 3.045781, + 3.027057, + 3.008086, + 3.007846, + 2.98538, + 3.024934, + 3.015981 + ], + "client_rtt_ms": [ + 3.054322, + 3.013705, + 3.015617, + 3.023382, + 3.051245, + 3.054813, + 3.057083, + 3.035501, + 3.010252, + 3.041772, + 3.043629, + 3.066788, + 3.069867, + 3.055453, + 3.045349, + 3.052144, + 3.057005, + 3.061547, + 3.047082, + 3.036343, + 3.037417, + 3.103588, + 3.064496, + 3.045641, + 3.011085, + 3.018712, + 3.049522, + 3.037794, + 3.05148, + 3.063252, + 3.071528, + 3.038236, + 3.047466, + 3.015759, + 3.053495, + 3.058558, + 3.054438, + 3.065957, + 3.059721, + 3.058494, + 3.038615, + 3.050641, + 3.035127, + 3.045482, + 3.05648, + 3.098277, + 3.058849, + 3.052615, + 3.046654, + 3.057933, + 3.061255, + 3.054346, + 3.019065, + 3.034271, + 3.055024, + 3.055615, + 3.063052, + 3.064554, + 3.068855, + 3.051958, + 3.049297, + 3.050528, + 3.042956, + 3.052915, + 3.045119, + 3.02412, + 3.044459, + 3.034519, + 3.085277, + 3.079743, + 3.065476, + 3.017489, + 3.04768, + 3.017861, + 3.044748, + 3.048281, + 3.060684, + 3.054464, + 3.065714, + 3.047329, + 3.044757, + 3.059659, + 3.041731, + 3.039102, + 3.019913, + 3.032901, + 3.018171, + 3.035964, + 3.007305, + 3.04101, + 3.050207, + 3.044314, + 3.083462, + 3.07821, + 3.062243, + 3.041615, + 3.040904, + 3.017074, + 3.06013, + 3.049337 + ] + } + } + }, + { + "label": "round1-initial-eager", + "raw_file_sha256": "4c47480a7496c00c51ede9c276698094db136600c2ef4c7a75ac3cd58147e404", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "a95ee8e50065f2e39d8a6c8ced32e8ff434dd42903bd741040ea9205da79813e", + "mode": "eager", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.872342, + 2.866001, + 2.868461, + 2.870807, + 2.871598, + 2.863798, + 2.870736, + 2.868656, + 2.864685, + 2.866751, + 2.866659, + 2.858876, + 2.87485, + 2.865545, + 2.864506, + 2.8619, + 2.868305, + 2.869554, + 2.867216, + 2.873043, + 2.871757, + 2.878181, + 2.861778, + 2.870323, + 2.872612, + 2.88863, + 2.908707, + 2.883513, + 2.885985, + 2.873094, + 2.881734, + 2.870122, + 2.871441, + 2.864359, + 2.864336, + 2.866028, + 2.872211, + 2.877468, + 2.865674, + 2.862513, + 2.864879, + 2.859061, + 2.869238, + 2.86997, + 2.867701, + 2.864018, + 2.860297, + 2.860276, + 2.879994, + 2.858043, + 2.869605, + 2.863833, + 2.866674, + 2.86498, + 2.862249, + 2.860081, + 2.867608, + 2.859143, + 2.867033, + 2.860804, + 2.864456, + 2.858146, + 2.85599, + 2.861038, + 2.865621, + 2.857462, + 2.863727, + 2.86014, + 2.852912, + 2.862818, + 2.852675, + 2.852025, + 2.853981, + 2.853087, + 2.847597, + 2.850838, + 2.847422, + 2.846626, + 2.849318, + 2.844737, + 2.859085, + 2.85449, + 2.846632, + 2.849219, + 2.847518, + 2.852515, + 2.840655, + 2.84888, + 2.851062, + 2.849637, + 2.853323, + 2.854254, + 2.847044, + 2.839405, + 2.857925, + 2.840831, + 2.85433, + 2.852858, + 2.850552, + 2.845937 + ], + "client_rtt_ms": [ + 2.902631, + 2.897578, + 2.896459, + 2.905943, + 2.906233, + 2.892813, + 2.900624, + 2.895563, + 2.895713, + 2.895118, + 2.892331, + 2.882141, + 2.905431, + 2.902572, + 2.890148, + 2.891536, + 2.899015, + 2.90209, + 2.894124, + 2.898329, + 2.902594, + 2.911887, + 2.896642, + 2.901054, + 2.920858, + 2.915203, + 2.937819, + 2.912962, + 2.912306, + 2.898994, + 2.908267, + 2.898421, + 2.903036, + 2.892907, + 2.903545, + 2.895934, + 2.898039, + 2.904872, + 2.892338, + 2.891474, + 2.891818, + 2.887311, + 2.89655, + 2.900867, + 2.902393, + 2.898747, + 2.891164, + 2.891062, + 2.908407, + 2.887739, + 2.899278, + 2.891109, + 2.895453, + 2.892668, + 2.892548, + 2.897926, + 2.895915, + 2.889853, + 2.895745, + 2.888657, + 2.891415, + 2.884719, + 2.885228, + 2.889921, + 2.892474, + 2.894566, + 2.892696, + 2.888916, + 2.8807, + 2.8933, + 2.881829, + 2.879586, + 2.883806, + 2.879788, + 2.880027, + 2.895581, + 2.874961, + 2.873754, + 2.877121, + 2.872122, + 2.886696, + 2.883434, + 2.874787, + 2.876374, + 2.872986, + 2.891185, + 2.866921, + 2.875238, + 2.876994, + 2.880359, + 2.88085, + 2.880182, + 2.872489, + 2.867804, + 2.883414, + 2.8664, + 2.896093, + 2.880325, + 2.879229, + 2.872368 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 2.903093, + 2.887515, + 2.905913, + 2.911086, + 2.901214, + 2.901398, + 2.89296, + 2.896675, + 2.909795, + 2.898798, + 2.911891, + 2.899597, + 2.893966, + 2.90439, + 2.899028, + 2.896356, + 2.900575, + 2.88196, + 2.894699, + 2.90051, + 2.899474, + 2.895934, + 2.89443, + 2.900775, + 2.908151, + 2.89502, + 2.894435, + 2.899698, + 2.89792, + 2.893358, + 2.904459, + 2.893417, + 2.913196, + 2.899108, + 2.891978, + 2.907824, + 2.902645, + 2.89624, + 2.898909, + 2.894518, + 2.905507, + 2.889325, + 2.893187, + 2.895518, + 2.897272, + 2.895059, + 2.892173, + 2.886512, + 2.896684, + 2.887043, + 2.891459, + 2.894084, + 2.900187, + 2.906489, + 2.899736, + 2.90263, + 2.908222, + 2.899246, + 2.900418, + 2.893492, + 2.901754, + 2.895689, + 2.890218, + 2.902746, + 2.900217, + 2.889597, + 2.900294, + 2.913522, + 2.90422, + 2.899543, + 2.892661, + 2.891946, + 2.903127, + 2.888734, + 2.892821, + 2.904327, + 2.895809, + 2.889375, + 2.903164, + 2.901722, + 2.906359, + 2.883988, + 2.897833, + 2.903479, + 2.903317, + 2.898794, + 2.904504, + 2.89258, + 2.903974, + 2.889886, + 2.896521, + 2.908707, + 2.909284, + 2.907978, + 2.919953, + 2.906325, + 2.9224, + 2.899974, + 2.900512, + 2.904675 + ], + "client_rtt_ms": [ + 2.929289, + 2.915119, + 2.943291, + 2.939549, + 2.928802, + 2.929499, + 2.918987, + 2.923274, + 2.936976, + 2.927106, + 2.941443, + 2.934214, + 2.92132, + 2.93489, + 2.925959, + 2.921551, + 2.930364, + 2.907914, + 2.918625, + 2.934708, + 2.928993, + 2.923454, + 2.920754, + 2.928888, + 2.937642, + 2.921465, + 2.921859, + 2.925249, + 2.93049, + 2.919279, + 2.930901, + 2.921275, + 2.941289, + 2.926613, + 2.917286, + 2.934371, + 2.937492, + 2.921395, + 2.926337, + 2.922892, + 2.932325, + 2.915145, + 2.918214, + 2.923396, + 2.921523, + 2.926701, + 2.91845, + 2.912375, + 2.923219, + 2.914319, + 2.917422, + 2.932446, + 2.924639, + 2.938606, + 2.935221, + 2.927863, + 2.936406, + 2.926383, + 2.929199, + 2.922118, + 2.927874, + 2.922313, + 2.925779, + 2.931295, + 2.926808, + 2.916345, + 2.928615, + 2.941213, + 2.928937, + 2.930624, + 2.920553, + 2.926155, + 2.933293, + 2.915112, + 2.918658, + 2.931087, + 2.920736, + 2.913993, + 2.929163, + 2.937249, + 2.933084, + 2.914811, + 2.925809, + 2.928253, + 2.928724, + 2.928821, + 2.937005, + 2.919265, + 2.939096, + 2.919509, + 2.921589, + 2.934023, + 2.938982, + 2.936666, + 2.945439, + 2.936909, + 2.957429, + 2.928223, + 2.926001, + 2.932004 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.855239, + 2.858746, + 2.855793, + 2.855985, + 2.862753, + 2.848909, + 2.854287, + 2.848296, + 2.864294, + 2.846452, + 2.859535, + 2.854595, + 2.858664, + 2.853344, + 2.853224, + 2.860024, + 2.857369, + 2.849483, + 2.846035, + 2.85216, + 2.85837, + 2.853147, + 2.8591, + 2.847527, + 2.857357, + 2.848186, + 2.852411, + 2.845961, + 2.858743, + 2.850876, + 2.856714, + 2.846272, + 2.863823, + 2.840361, + 2.84673, + 2.852164, + 2.857977, + 2.857548, + 2.855802, + 2.847389, + 2.856211, + 2.846508, + 2.849059, + 2.848062, + 2.862274, + 2.857832, + 2.844489, + 2.846348, + 2.856825, + 2.862088, + 2.848077, + 2.854069, + 2.849305, + 2.852911, + 2.856079, + 2.857036, + 2.855533, + 2.845837, + 2.852801, + 2.847389, + 2.856878, + 2.851736, + 2.855981, + 2.849085, + 2.856806, + 2.850923, + 2.847456, + 2.852577, + 2.856256, + 2.847576, + 2.84983, + 2.847768, + 2.857496, + 2.845057, + 2.853829, + 2.858093, + 2.85608, + 2.857523, + 2.854557, + 2.853618, + 2.856254, + 2.845038, + 2.861159, + 2.850416, + 2.853871, + 2.848554, + 2.852316, + 2.845307, + 2.859551, + 2.843663, + 2.852142, + 2.847289, + 2.858729, + 2.858177, + 2.850025, + 2.851581, + 2.858038, + 2.851238, + 2.849477, + 2.841709 + ], + "client_rtt_ms": [ + 2.889095, + 2.883961, + 2.880505, + 2.882941, + 2.886632, + 2.87632, + 2.878049, + 2.873611, + 2.889546, + 2.872692, + 2.886129, + 2.880523, + 2.89433, + 2.878572, + 2.877424, + 2.886995, + 2.882974, + 2.875519, + 2.869717, + 2.878028, + 2.883502, + 2.878366, + 2.883531, + 2.871868, + 2.890073, + 2.872506, + 2.87566, + 2.869713, + 2.883628, + 2.87651, + 2.882393, + 2.872973, + 2.889636, + 2.865739, + 2.871357, + 2.880639, + 2.890646, + 2.882302, + 2.882153, + 2.873752, + 2.880914, + 2.872084, + 2.875147, + 2.873468, + 2.887277, + 2.882664, + 2.870441, + 2.870033, + 2.880548, + 2.898331, + 2.873895, + 2.879529, + 2.874592, + 2.877811, + 2.879776, + 2.88317, + 2.880125, + 2.871597, + 2.878374, + 2.872175, + 2.881308, + 2.885935, + 2.882156, + 2.873437, + 2.882051, + 2.875482, + 2.873006, + 2.878083, + 2.883388, + 2.873006, + 2.876009, + 2.872782, + 2.880675, + 2.876205, + 2.878469, + 2.884106, + 2.881162, + 2.883552, + 2.881209, + 2.877692, + 2.88144, + 2.872196, + 2.889738, + 2.875223, + 2.879746, + 2.875877, + 2.889661, + 2.869629, + 2.884781, + 2.868161, + 2.87869, + 2.871465, + 2.883588, + 2.882134, + 2.874351, + 2.875637, + 2.884326, + 2.875193, + 2.88533, + 2.867235 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 3.202191, + 3.198058, + 3.197444, + 3.179597, + 3.200758, + 3.195877, + 3.184763, + 3.173926, + 3.194463, + 3.196866, + 3.199375, + 3.187989, + 3.193435, + 3.187494, + 3.186878, + 3.202453, + 3.197794, + 3.188497, + 3.199322, + 3.221882, + 3.257117, + 3.257584, + 3.242916, + 3.216932, + 3.21541, + 3.204199, + 3.184799, + 3.201266, + 3.202422, + 3.195233, + 3.202019, + 3.18524, + 3.192988, + 3.188717, + 3.186949, + 3.191702, + 3.192027, + 3.203408, + 3.19005, + 3.179398, + 3.204883, + 3.195801, + 3.191195, + 3.174278, + 3.181552, + 3.174372, + 3.179301, + 3.192232, + 3.202051, + 3.181256, + 3.173445, + 3.176184, + 3.173583, + 3.202636, + 3.170572, + 3.188916, + 3.188438, + 3.186894, + 3.191714, + 3.179692, + 3.17096, + 3.191832, + 3.190586, + 3.154475, + 3.17549, + 3.16943, + 3.180563, + 3.161447, + 3.188898, + 3.189903, + 3.172041, + 3.178174, + 3.178769, + 3.192899, + 3.181151, + 3.176656, + 3.184277, + 3.188467, + 3.196905, + 3.157031, + 3.170138, + 3.162531, + 3.182222, + 3.186989, + 3.196641, + 3.191074, + 3.192832, + 3.174911, + 3.180608, + 3.177978, + 3.170501, + 3.157673, + 3.168334, + 3.174113, + 3.183121, + 3.171779, + 3.180429, + 3.186373, + 3.168834, + 3.157822 + ], + "client_rtt_ms": [ + 3.23112, + 3.226486, + 3.234085, + 3.20765, + 3.227597, + 3.220877, + 3.210328, + 3.199831, + 3.221003, + 3.224341, + 3.228774, + 3.216221, + 3.220729, + 3.21522, + 3.223134, + 3.230497, + 3.227106, + 3.216276, + 3.228811, + 3.274747, + 3.288222, + 3.285995, + 3.273647, + 3.245681, + 3.246613, + 3.232793, + 3.211599, + 3.239349, + 3.230987, + 3.223585, + 3.231038, + 3.211593, + 3.220626, + 3.215768, + 3.212383, + 3.218505, + 3.218214, + 3.230673, + 3.216265, + 3.214499, + 3.235127, + 3.22643, + 3.2188, + 3.201667, + 3.208471, + 3.201313, + 3.212342, + 3.219677, + 3.229283, + 3.208457, + 3.199167, + 3.212818, + 3.19991, + 3.230776, + 3.197219, + 3.216516, + 3.215408, + 3.21394, + 3.219798, + 3.206271, + 3.197438, + 3.222013, + 3.215988, + 3.189336, + 3.202191, + 3.19744, + 3.220369, + 3.187821, + 3.216114, + 3.216382, + 3.199475, + 3.206645, + 3.204877, + 3.22228, + 3.210258, + 3.20511, + 3.219531, + 3.215319, + 3.231015, + 3.183211, + 3.196624, + 3.190883, + 3.20873, + 3.214678, + 3.223875, + 3.219232, + 3.220821, + 3.202651, + 3.214661, + 3.203763, + 3.197768, + 3.185051, + 3.196478, + 3.19809, + 3.211289, + 3.19942, + 3.208221, + 3.213834, + 3.196509, + 3.184452 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 4.329492, + 4.311681, + 4.351222, + 4.337842, + 4.363154, + 4.352973, + 4.342924, + 4.304061, + 4.323222, + 4.310758, + 4.317764, + 4.332784, + 4.331908, + 4.315773, + 4.330391, + 4.310198, + 4.313045, + 4.32157, + 4.326868, + 4.324593, + 4.34421, + 4.354444, + 4.327893, + 4.300858, + 4.330619, + 4.313854, + 4.305531, + 4.303982, + 4.373275, + 4.332772, + 4.312653, + 4.330071, + 4.321231, + 4.501653, + 4.594019, + 4.373563, + 4.372248, + 4.387856, + 4.365016, + 4.332648, + 4.344995, + 4.39445, + 4.357025, + 4.356983, + 4.442047, + 4.466765, + 4.415129, + 4.378446, + 4.368725, + 4.369675, + 4.386997, + 4.373771, + 4.387098, + 4.381809, + 4.384135, + 4.366912, + 4.384158, + 4.354078, + 4.314597, + 4.335241, + 4.379161, + 4.35573, + 4.3145, + 4.304131, + 4.358607, + 4.36047, + 4.340781, + 4.30223, + 4.388512, + 4.41169, + 4.364925, + 4.310569, + 4.319666, + 4.361407, + 4.334646, + 4.357484, + 4.366165, + 4.356069, + 4.346407, + 4.352409, + 4.350777, + 4.325996, + 4.301658, + 4.342251, + 4.356943, + 4.315414, + 4.319969, + 4.339424, + 4.352521, + 4.338719, + 4.329804, + 4.352525, + 4.392627, + 4.379583, + 4.311694, + 4.312617, + 4.343657, + 4.377638, + 4.34256, + 4.333459 + ], + "client_rtt_ms": [ + 4.367268, + 4.345057, + 4.385621, + 4.371206, + 4.398221, + 4.396009, + 4.37695, + 4.338198, + 4.356034, + 4.342785, + 4.349956, + 4.367696, + 4.365844, + 4.350213, + 4.363778, + 4.353725, + 4.34661, + 4.363615, + 4.360981, + 4.356695, + 4.377799, + 4.387163, + 4.359009, + 4.333599, + 4.363533, + 4.348228, + 4.336318, + 4.33648, + 4.407454, + 4.37815, + 4.347318, + 4.363734, + 4.354712, + 4.535066, + 4.634013, + 4.407839, + 4.407023, + 4.422628, + 4.399514, + 4.366096, + 4.37857, + 4.437216, + 4.401543, + 4.392793, + 4.478791, + 4.502444, + 4.450631, + 4.419912, + 4.401377, + 4.40459, + 4.421888, + 4.408612, + 4.419896, + 4.423977, + 4.420146, + 4.408201, + 4.417957, + 4.389157, + 4.348724, + 4.369079, + 4.414216, + 4.388377, + 4.348065, + 4.336876, + 4.390719, + 4.396487, + 4.382207, + 4.3374, + 4.42308, + 4.447295, + 4.398874, + 4.344085, + 4.353229, + 4.39642, + 4.368533, + 4.391324, + 4.399232, + 4.392797, + 4.387502, + 4.388027, + 4.384457, + 4.359084, + 4.335244, + 4.375745, + 4.390271, + 4.347354, + 4.352717, + 4.375726, + 4.386933, + 4.372011, + 4.373024, + 4.389601, + 4.426132, + 4.413809, + 4.345168, + 4.345815, + 4.377048, + 4.412282, + 4.39215, + 4.369367 + ] + } + } + }, + { + "label": "round1-initial-graph", + "raw_file_sha256": "f2f9610255be811106cace5070132074bf412e4aa0407db7837117360c7ae3dd", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "a95ee8e50065f2e39d8a6c8ced32e8ff434dd42903bd741040ea9205da79813e", + "mode": "graph", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.561327, + 2.55036, + 2.553289, + 2.554803, + 2.550052, + 2.560564, + 2.551272, + 2.556195, + 2.558391, + 2.56221, + 2.55867, + 2.552928, + 2.557446, + 2.545875, + 2.556085, + 2.552717, + 2.557108, + 2.552445, + 2.554624, + 2.554138, + 2.553757, + 2.558536, + 2.550732, + 2.553799, + 2.544405, + 2.557949, + 2.549267, + 2.542192, + 2.542696, + 2.54012, + 2.539232, + 2.529519, + 2.537935, + 2.535272, + 2.534934, + 2.545365, + 2.542714, + 2.544557, + 2.539048, + 2.538284, + 2.534116, + 2.535915, + 2.529019, + 2.529016, + 2.535434, + 2.536013, + 2.542579, + 2.531552, + 2.543983, + 2.533077, + 2.539489, + 2.535276, + 2.53284, + 2.533387, + 2.5632, + 2.542744, + 2.534248, + 2.533708, + 2.53551, + 2.540555, + 2.536009, + 2.533693, + 2.531338, + 2.532067, + 2.529547, + 2.530246, + 2.537889, + 2.534612, + 2.546443, + 2.534348, + 2.536254, + 2.536951, + 2.532486, + 2.538723, + 2.53501, + 2.541199, + 2.534369, + 2.540087, + 2.540252, + 2.535576, + 2.535584, + 2.535698, + 2.535416, + 2.530085, + 2.537642, + 2.535192, + 2.536536, + 2.53817, + 2.536637, + 2.535828, + 2.536271, + 2.538993, + 2.533384, + 2.537422, + 2.538879, + 2.541892, + 2.535111, + 2.537316, + 2.53338, + 2.526964 + ], + "client_rtt_ms": [ + 2.588276, + 2.574321, + 2.577423, + 2.587141, + 2.587117, + 2.586336, + 2.577267, + 2.581652, + 2.586691, + 2.592693, + 2.584442, + 2.578733, + 2.584025, + 2.5793, + 2.580818, + 2.578979, + 2.583027, + 2.576915, + 2.579838, + 2.579412, + 2.581225, + 2.585476, + 2.574453, + 2.579716, + 2.580956, + 2.583494, + 2.573875, + 2.56769, + 2.569832, + 2.569342, + 2.564908, + 2.556046, + 2.56422, + 2.562056, + 2.574043, + 2.572386, + 2.568303, + 2.572485, + 2.567771, + 2.567082, + 2.557897, + 2.563561, + 2.553394, + 2.554734, + 2.568619, + 2.561153, + 2.569299, + 2.557556, + 2.569949, + 2.559617, + 2.565032, + 2.562247, + 2.556597, + 2.557204, + 2.589883, + 2.586708, + 2.561336, + 2.558931, + 2.562329, + 2.565437, + 2.563685, + 2.55763, + 2.558558, + 2.558279, + 2.554012, + 2.563596, + 2.564562, + 2.55961, + 2.570893, + 2.564989, + 2.562064, + 2.561205, + 2.559728, + 2.566085, + 2.566767, + 2.578582, + 2.56146, + 2.568949, + 2.565812, + 2.562068, + 2.564387, + 2.561741, + 2.561008, + 2.556548, + 2.562893, + 2.572492, + 2.569523, + 2.562751, + 2.561661, + 2.562734, + 2.564058, + 2.565663, + 2.558818, + 2.564278, + 2.565564, + 2.570378, + 2.573138, + 2.56981, + 2.561535, + 2.553023 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 2.580143, + 2.578846, + 2.587093, + 2.581763, + 2.576919, + 2.578246, + 2.587252, + 2.580979, + 2.580711, + 2.585415, + 2.578788, + 2.585414, + 2.583503, + 2.5851, + 2.581151, + 2.582272, + 2.587239, + 2.587276, + 2.592029, + 2.594391, + 2.580954, + 2.580951, + 2.58229, + 2.581934, + 2.583692, + 2.587233, + 2.588344, + 2.585128, + 2.589155, + 2.578004, + 2.580468, + 2.587599, + 2.58632, + 2.583397, + 2.589834, + 2.584118, + 2.578303, + 2.585092, + 2.583718, + 2.582908, + 2.587614, + 2.577191, + 2.587942, + 2.587063, + 2.584459, + 2.580785, + 2.579295, + 2.58396, + 2.587142, + 2.582931, + 2.585008, + 2.586552, + 2.585675, + 2.585649, + 2.586311, + 2.589835, + 2.580437, + 2.580762, + 2.587102, + 2.582549, + 2.581331, + 2.584161, + 2.583478, + 2.589742, + 2.586809, + 2.585317, + 2.591468, + 2.585398, + 2.58193, + 2.588955, + 2.584587, + 2.581467, + 2.588719, + 2.590652, + 2.579906, + 2.578233, + 2.583311, + 2.579523, + 2.581856, + 2.581956, + 2.577592, + 2.580524, + 2.580405, + 2.583407, + 2.584415, + 2.584971, + 2.582956, + 2.60033, + 2.595589, + 2.597836, + 2.605753, + 2.597759, + 2.599102, + 2.598114, + 2.608655, + 2.60387, + 2.60311, + 2.596242, + 2.603406, + 2.595897 + ], + "client_rtt_ms": [ + 2.607754, + 2.605705, + 2.62481, + 2.611443, + 2.604008, + 2.604695, + 2.614198, + 2.607166, + 2.608655, + 2.614516, + 2.606763, + 2.621091, + 2.611042, + 2.613705, + 2.609319, + 2.607185, + 2.612163, + 2.614335, + 2.624055, + 2.627246, + 2.610784, + 2.607121, + 2.606921, + 2.612663, + 2.608943, + 2.615668, + 2.619935, + 2.622021, + 2.625257, + 2.60596, + 2.609674, + 2.613754, + 2.614029, + 2.61142, + 2.618358, + 2.611679, + 2.614649, + 2.612945, + 2.611261, + 2.61219, + 2.6162, + 2.606008, + 2.613355, + 2.614916, + 2.610484, + 2.612581, + 2.605571, + 2.611261, + 2.613048, + 2.614185, + 2.612182, + 2.612262, + 2.611296, + 2.617495, + 2.621684, + 2.617209, + 2.611751, + 2.605652, + 2.612959, + 2.614352, + 2.605713, + 2.61271, + 2.619071, + 2.617016, + 2.615094, + 2.612288, + 2.624542, + 2.613465, + 2.60917, + 2.620187, + 2.612561, + 2.615211, + 2.618101, + 2.616633, + 2.603669, + 2.604981, + 2.609019, + 2.605759, + 2.608831, + 2.617896, + 2.603531, + 2.608309, + 2.607059, + 2.608912, + 2.61163, + 2.611986, + 2.608811, + 2.632064, + 2.63485, + 2.626237, + 2.632919, + 2.627937, + 2.626108, + 2.624791, + 2.636304, + 2.631103, + 2.637138, + 2.622628, + 2.630275, + 2.624612 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.548655, + 2.540916, + 2.543277, + 2.54276, + 2.539886, + 2.546475, + 2.546534, + 2.546088, + 2.546423, + 2.540125, + 2.544427, + 2.542888, + 2.540158, + 2.537133, + 2.537246, + 2.540625, + 2.537519, + 2.537452, + 2.543282, + 2.54278, + 2.545046, + 2.546372, + 2.544153, + 2.551849, + 2.546861, + 2.536228, + 2.543154, + 2.541412, + 2.544778, + 2.541288, + 2.546949, + 2.544627, + 2.545138, + 2.539528, + 2.544942, + 2.543744, + 2.533063, + 2.537046, + 2.539793, + 2.537623, + 2.541929, + 2.541773, + 2.545862, + 2.535444, + 2.539341, + 2.544855, + 2.545767, + 2.544187, + 2.542011, + 2.537204, + 2.552299, + 2.542329, + 2.556206, + 2.545095, + 2.543116, + 2.541086, + 2.550615, + 2.538353, + 2.546855, + 2.545863, + 2.539816, + 2.533223, + 2.541327, + 2.544501, + 2.544793, + 2.544308, + 2.546675, + 2.541238, + 2.543682, + 2.541951, + 2.54028, + 2.539535, + 2.541153, + 2.535585, + 2.543172, + 2.545708, + 2.537092, + 2.534134, + 2.541184, + 2.537413, + 2.540905, + 2.533681, + 2.539697, + 2.550986, + 2.545261, + 2.543418, + 2.546009, + 2.54012, + 2.538346, + 2.541144, + 2.539172, + 2.547513, + 2.541075, + 2.538529, + 2.540744, + 2.538228, + 2.539642, + 2.543753, + 2.548148, + 2.542516 + ], + "client_rtt_ms": [ + 2.583847, + 2.566061, + 2.566819, + 2.567455, + 2.571589, + 2.574928, + 2.570555, + 2.570744, + 2.570582, + 2.564926, + 2.56905, + 2.567428, + 2.575784, + 2.562264, + 2.561845, + 2.562879, + 2.561669, + 2.566337, + 2.567591, + 2.567535, + 2.571793, + 2.575523, + 2.569787, + 2.575632, + 2.579267, + 2.560619, + 2.566642, + 2.566217, + 2.568109, + 2.567521, + 2.571761, + 2.571146, + 2.572923, + 2.564521, + 2.569165, + 2.569928, + 2.566455, + 2.562187, + 2.562826, + 2.5616, + 2.566031, + 2.566459, + 2.570426, + 2.558432, + 2.564951, + 2.569595, + 2.569297, + 2.567909, + 2.572073, + 2.568017, + 2.577021, + 2.566046, + 2.580993, + 2.569803, + 2.568209, + 2.56503, + 2.578284, + 2.561817, + 2.571643, + 2.570706, + 2.56453, + 2.565013, + 2.572036, + 2.571194, + 2.572359, + 2.569944, + 2.571386, + 2.571535, + 2.567694, + 2.567606, + 2.566287, + 2.564078, + 2.56525, + 2.569568, + 2.569927, + 2.571552, + 2.560675, + 2.557376, + 2.564612, + 2.565489, + 2.56459, + 2.557717, + 2.56916, + 2.582134, + 2.570797, + 2.567298, + 2.578161, + 2.562956, + 2.561148, + 2.564557, + 2.56731, + 2.571395, + 2.56563, + 2.565457, + 2.564804, + 2.562715, + 2.567555, + 2.568754, + 2.580402, + 2.567824 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 2.875923, + 2.865176, + 2.882951, + 2.868467, + 2.864969, + 2.857811, + 2.85532, + 2.866615, + 2.841802, + 2.856643, + 2.861043, + 2.862935, + 2.878803, + 2.871389, + 2.866682, + 2.8752, + 2.869868, + 2.858123, + 2.854358, + 2.886291, + 2.889891, + 2.895872, + 2.884117, + 2.886844, + 2.869388, + 2.846636, + 2.844295, + 2.856988, + 2.851716, + 2.86843, + 2.86044, + 2.864629, + 2.864404, + 2.860313, + 2.861076, + 2.866184, + 2.851276, + 2.850599, + 2.857524, + 2.867821, + 2.873363, + 2.857479, + 2.858058, + 2.861387, + 2.865256, + 2.864062, + 2.855095, + 2.87132, + 2.860706, + 2.855297, + 2.840308, + 2.845244, + 2.848654, + 2.861405, + 2.855629, + 2.851865, + 2.852255, + 2.838831, + 2.838289, + 2.842758, + 2.836608, + 2.83488, + 2.846847, + 2.870246, + 2.860267, + 2.840694, + 2.850828, + 2.864107, + 2.864937, + 2.842351, + 2.853015, + 2.866861, + 2.854442, + 2.85138, + 2.846599, + 2.842176, + 2.836532, + 2.835404, + 2.836125, + 2.85251, + 2.854041, + 2.85436, + 2.858485, + 2.860071, + 2.859888, + 2.853138, + 2.847588, + 2.854568, + 2.846658, + 2.847363, + 2.844039, + 2.852415, + 2.833558, + 2.837583, + 2.859218, + 2.867344, + 2.855221, + 2.838621, + 2.842458, + 2.845886 + ], + "client_rtt_ms": [ + 2.903572, + 2.892668, + 2.917133, + 2.897578, + 2.895406, + 2.882713, + 2.880243, + 2.893475, + 2.87005, + 2.883573, + 2.888378, + 2.896085, + 2.905353, + 2.898191, + 2.903728, + 2.903661, + 2.896132, + 2.884182, + 2.881275, + 2.913187, + 2.916667, + 2.923947, + 2.912522, + 2.913753, + 2.896429, + 2.874658, + 2.869599, + 2.89025, + 2.881692, + 2.895599, + 2.88841, + 2.892162, + 2.891814, + 2.887927, + 2.890323, + 2.894536, + 2.877768, + 2.878628, + 2.883528, + 2.90389, + 2.900513, + 2.885191, + 2.887522, + 2.888267, + 2.891582, + 2.891977, + 2.881512, + 2.898448, + 2.88786, + 2.884165, + 2.866339, + 2.878008, + 2.886583, + 2.88833, + 2.882497, + 2.878466, + 2.879964, + 2.867981, + 2.863935, + 2.873463, + 2.861445, + 2.861295, + 2.873059, + 2.907733, + 2.887121, + 2.869421, + 2.881417, + 2.891001, + 2.89094, + 2.87127, + 2.879982, + 2.893432, + 2.881519, + 2.883834, + 2.872914, + 2.868064, + 2.873015, + 2.859921, + 2.861426, + 2.877694, + 2.883836, + 2.881004, + 2.888264, + 2.886434, + 2.885168, + 2.877859, + 2.873341, + 2.883978, + 2.881178, + 2.873614, + 2.87059, + 2.880926, + 2.859, + 2.863159, + 2.887318, + 2.894193, + 2.882423, + 2.865721, + 2.868314, + 2.872203 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.968298, + 3.968707, + 3.998303, + 3.995562, + 3.995128, + 3.955704, + 3.998454, + 3.963164, + 3.986992, + 3.979389, + 3.975993, + 4.014598, + 4.00884, + 3.994825, + 3.996506, + 3.975173, + 3.968356, + 4.023982, + 4.011775, + 3.984875, + 3.980843, + 4.050097, + 4.043751, + 4.030844, + 3.981723, + 3.965844, + 3.996399, + 3.999895, + 3.997818, + 3.978298, + 5.186177, + 4.306018, + 4.041261, + 4.026667, + 4.000944, + 4.034165, + 4.026085, + 4.005998, + 3.990192, + 3.99555, + 4.035405, + 4.013026, + 4.017303, + 3.986889, + 4.083477, + 4.069223, + 4.010489, + 4.006833, + 3.987596, + 4.025984, + 3.984326, + 4.016666, + 4.022282, + 4.014107, + 4.003992, + 3.972522, + 3.974721, + 3.977199, + 3.971259, + 3.971205, + 3.974441, + 3.964782, + 3.994015, + 4.011705, + 4.003635, + 3.986499, + 3.972436, + 4.00069, + 3.990755, + 4.000561, + 4.029097, + 4.010395, + 4.012167, + 3.999785, + 3.976084, + 3.976843, + 4.000386, + 4.007251, + 4.01424, + 3.999335, + 3.99108, + 4.040052, + 4.053881, + 4.093937, + 4.085158, + 4.082856, + 4.086643, + 4.083796, + 4.054964, + 4.083179, + 4.080754, + 4.093591, + 4.111162, + 4.120837, + 4.087946, + 4.088353, + 4.075258, + 4.115938, + 4.089561, + 4.086985 + ], + "client_rtt_ms": [ + 4.003309, + 4.002242, + 4.031022, + 4.029967, + 4.026993, + 3.998055, + 4.032232, + 3.994692, + 4.020808, + 4.010223, + 4.008362, + 4.049144, + 4.042338, + 4.029457, + 4.029391, + 4.006699, + 4.002194, + 4.064965, + 4.048603, + 4.015735, + 4.012653, + 4.086395, + 4.079024, + 4.067804, + 4.013224, + 4.002585, + 4.028573, + 4.032084, + 4.036165, + 4.023523, + 5.220496, + 4.340716, + 4.086071, + 4.062136, + 4.032891, + 4.068795, + 4.059529, + 4.040023, + 4.022585, + 4.027123, + 4.071149, + 4.054919, + 4.049649, + 4.019852, + 4.1162, + 4.103444, + 4.042527, + 4.040826, + 4.021099, + 4.057712, + 4.019341, + 4.052383, + 4.056394, + 4.055921, + 4.037121, + 4.006742, + 4.006311, + 4.011014, + 4.002807, + 4.002626, + 4.007334, + 3.99842, + 4.027736, + 4.04589, + 4.036836, + 4.019819, + 4.013137, + 4.035942, + 4.022749, + 4.033895, + 4.067172, + 4.046809, + 4.048173, + 4.037822, + 4.008121, + 4.011447, + 4.036396, + 4.045973, + 4.059519, + 4.0337, + 4.027366, + 4.076341, + 4.088823, + 4.128426, + 4.118845, + 4.115502, + 4.120894, + 4.116962, + 4.086916, + 4.115933, + 4.121979, + 4.126363, + 4.144183, + 4.154238, + 4.124398, + 4.121391, + 4.107394, + 4.151144, + 4.122416, + 4.120838 + ] + } + } + }, + { + "label": "round1-retained-eager", + "raw_file_sha256": "e266ba38b2f8c40cec72027c829da03f2f12e34cd3f157fbeea5932bbf3cb582", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "5fa7ccd47087a40822dcab78b2b80deea1bb42cb54463376e24aa7701b543078", + "mode": "eager", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.931126, + 1.902968, + 1.917728, + 1.908178, + 1.91519, + 1.907518, + 1.918138, + 1.909897, + 1.922974, + 1.91456, + 1.905573, + 1.906767, + 1.911118, + 1.900941, + 1.916852, + 1.902917, + 1.923591, + 1.910198, + 1.906848, + 1.903328, + 1.91504, + 1.913091, + 1.897569, + 1.908091, + 1.905306, + 1.895136, + 1.903851, + 1.907419, + 1.920033, + 1.90755, + 1.891771, + 1.905834, + 1.915222, + 1.897237, + 1.897405, + 1.903124, + 1.90848, + 1.898091, + 1.896498, + 1.906737, + 1.911075, + 1.905083, + 1.897118, + 1.902, + 1.905336, + 1.8966, + 1.901524, + 1.892745, + 1.915928, + 1.901298, + 1.902919, + 1.895861, + 1.914515, + 1.894731, + 1.899615, + 1.898571, + 1.901922, + 1.894587, + 1.894193, + 1.895817, + 1.905618, + 1.901806, + 1.901338, + 1.897967, + 1.909113, + 1.885713, + 1.901866, + 1.903402, + 1.917531, + 1.895492, + 1.900207, + 1.908621, + 1.905007, + 1.899136, + 1.896453, + 1.880916, + 1.891962, + 1.877109, + 1.880622, + 1.872832, + 1.885169, + 1.886389, + 1.896231, + 1.877041, + 1.889621, + 1.881566, + 1.886108, + 1.866254, + 1.881584, + 1.883436, + 1.871601, + 1.888494, + 1.882176, + 1.874193, + 1.881043, + 1.886056, + 1.886408, + 1.88917, + 1.879708, + 1.876536 + ], + "client_rtt_ms": [ + 1.959051, + 1.927217, + 1.943679, + 1.941577, + 1.948765, + 1.933377, + 1.945939, + 1.936449, + 1.952252, + 1.942156, + 1.934174, + 1.933129, + 1.939614, + 1.933702, + 1.943164, + 1.929287, + 1.951416, + 1.935266, + 1.933697, + 1.930233, + 1.943565, + 1.938108, + 1.924556, + 1.934894, + 1.94763, + 1.920792, + 1.930318, + 1.933857, + 1.946146, + 1.932051, + 1.917873, + 1.931281, + 1.940988, + 1.925528, + 1.930367, + 1.934186, + 1.932845, + 1.926823, + 1.920788, + 1.935853, + 1.936355, + 1.932613, + 1.923454, + 1.929125, + 1.938242, + 1.92302, + 1.926405, + 1.92219, + 1.942311, + 1.929744, + 1.931193, + 1.921524, + 1.940556, + 1.922289, + 1.926749, + 1.931959, + 1.926569, + 1.919196, + 1.921054, + 1.923494, + 1.932218, + 1.931701, + 1.928247, + 1.927071, + 1.933083, + 1.921154, + 1.930594, + 1.931491, + 1.944271, + 1.92141, + 1.928316, + 1.934376, + 1.933783, + 1.92466, + 1.923837, + 1.914989, + 1.918175, + 1.903291, + 1.906171, + 1.897689, + 1.911693, + 1.914249, + 1.924801, + 1.903779, + 1.917966, + 1.916881, + 1.912446, + 1.890716, + 1.908037, + 1.910921, + 1.898871, + 1.913582, + 1.909399, + 1.901124, + 1.906957, + 1.911598, + 1.923894, + 1.914316, + 1.908811, + 1.901149 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.911223, + 1.908415, + 1.9121, + 1.899352, + 1.926749, + 1.900232, + 1.905364, + 1.918324, + 1.912439, + 1.908985, + 1.918077, + 1.906737, + 1.920494, + 1.908356, + 1.905045, + 1.911989, + 1.918525, + 1.901907, + 1.908707, + 1.911759, + 1.916053, + 1.91243, + 1.914206, + 1.909717, + 1.914986, + 1.919736, + 1.911491, + 1.899395, + 1.915028, + 1.909412, + 1.908159, + 1.910041, + 1.920276, + 1.908934, + 1.916894, + 1.910085, + 1.92164, + 1.900846, + 1.900985, + 1.909018, + 1.9163, + 1.906522, + 1.91577, + 1.903059, + 1.913971, + 1.908231, + 1.910386, + 1.908273, + 1.91618, + 1.921572, + 1.90948, + 1.907144, + 1.931351, + 1.898653, + 1.907107, + 1.907833, + 1.914172, + 1.914328, + 1.91043, + 1.906146, + 1.911862, + 1.908133, + 1.907701, + 1.910939, + 1.914877, + 1.909553, + 1.915009, + 1.914979, + 1.913296, + 1.904776, + 1.911908, + 1.910845, + 1.913443, + 1.908876, + 1.899938, + 1.89462, + 1.909658, + 1.898713, + 1.903771, + 1.908504, + 1.91207, + 1.909382, + 1.908906, + 1.908771, + 1.920801, + 1.899402, + 1.902087, + 1.910637, + 1.918203, + 1.913046, + 1.918808, + 1.91665, + 1.929238, + 1.902925, + 1.924085, + 1.923554, + 1.921432, + 1.917471, + 1.919637, + 1.911877 + ], + "client_rtt_ms": [ + 1.938613, + 1.935605, + 1.948063, + 1.927252, + 1.953023, + 1.926002, + 1.934185, + 1.945793, + 1.941519, + 1.936826, + 1.948355, + 1.941461, + 1.946654, + 1.9357, + 1.931775, + 1.937457, + 1.945109, + 1.927764, + 1.937227, + 1.944505, + 1.945038, + 1.938505, + 1.941515, + 1.93902, + 1.944598, + 1.947151, + 1.941479, + 1.92565, + 1.952152, + 1.934747, + 1.937571, + 1.9364, + 1.948301, + 1.93762, + 1.94839, + 1.936115, + 1.958047, + 1.92677, + 1.928677, + 1.937615, + 1.945257, + 1.931842, + 1.944988, + 1.932487, + 1.940154, + 1.946048, + 1.93693, + 1.939454, + 1.94162, + 1.951112, + 1.935202, + 1.93566, + 1.958264, + 1.93072, + 1.941869, + 1.934067, + 1.941371, + 1.941297, + 1.940535, + 1.943759, + 1.937679, + 1.935296, + 1.947125, + 1.943267, + 1.940642, + 1.939698, + 1.942469, + 1.942554, + 1.939843, + 1.935375, + 1.93737, + 1.94602, + 1.940264, + 1.93537, + 1.924194, + 1.92451, + 1.93591, + 1.92719, + 1.930376, + 1.948003, + 1.939404, + 1.93959, + 1.935567, + 1.935144, + 1.946557, + 1.927171, + 1.92595, + 1.940039, + 1.952393, + 1.94088, + 1.948338, + 1.94267, + 1.958763, + 1.929323, + 1.951264, + 1.951072, + 1.956366, + 1.944685, + 1.947512, + 1.939895 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.8984, + 1.893261, + 1.881823, + 1.886511, + 1.902784, + 1.881245, + 1.892837, + 1.893259, + 1.89436, + 1.920409, + 1.884621, + 1.88594, + 1.898375, + 1.87856, + 1.886428, + 1.886698, + 1.893105, + 1.888292, + 1.881996, + 1.877958, + 1.891891, + 1.879198, + 1.890462, + 1.883354, + 1.899334, + 1.893125, + 1.915552, + 1.943049, + 1.904989, + 1.885837, + 1.884279, + 1.888894, + 1.897163, + 1.892013, + 1.888599, + 1.882353, + 1.895106, + 1.878255, + 1.901979, + 1.883994, + 1.896784, + 1.884999, + 1.883917, + 1.880223, + 1.889517, + 1.887291, + 1.894433, + 1.882434, + 1.891163, + 1.888929, + 1.889172, + 1.888916, + 1.89749, + 1.887884, + 1.891403, + 1.880298, + 1.887354, + 1.890126, + 1.886468, + 1.880129, + 1.896444, + 1.892562, + 1.887232, + 1.88176, + 1.902008, + 1.887386, + 1.890146, + 1.887507, + 1.897904, + 1.877112, + 1.886712, + 1.882594, + 1.897747, + 1.883553, + 1.886293, + 1.888359, + 1.901527, + 1.879367, + 1.881023, + 1.888465, + 1.893682, + 1.893401, + 1.882621, + 1.885046, + 1.898809, + 1.886262, + 1.881194, + 1.878184, + 1.893997, + 1.891177, + 1.887304, + 1.88785, + 1.898255, + 1.883037, + 1.885893, + 1.889895, + 1.889345, + 1.886038, + 1.8784, + 1.882341 + ], + "client_rtt_ms": [ + 1.93081, + 1.917528, + 1.911086, + 1.910903, + 1.927891, + 1.905351, + 1.917686, + 1.920407, + 1.917629, + 1.944875, + 1.908738, + 1.915789, + 1.931901, + 1.904486, + 1.910171, + 1.915669, + 1.917667, + 1.912228, + 1.906582, + 1.903945, + 1.916679, + 1.904167, + 1.91469, + 1.907052, + 1.93071, + 1.919182, + 1.940153, + 1.96761, + 1.92979, + 1.913829, + 1.910349, + 1.914583, + 1.923258, + 1.919637, + 1.91289, + 1.916752, + 1.931136, + 1.903041, + 1.929717, + 1.908211, + 1.922901, + 1.908347, + 1.908751, + 1.90373, + 1.914905, + 1.911683, + 1.918586, + 1.9062, + 1.916468, + 1.920612, + 1.91514, + 1.91284, + 1.923458, + 1.911178, + 1.924219, + 1.905166, + 1.91757, + 1.914068, + 1.913842, + 1.90486, + 1.925988, + 1.924667, + 1.914848, + 1.905665, + 1.927428, + 1.915978, + 1.915434, + 1.916357, + 1.922831, + 1.904721, + 1.910643, + 1.909092, + 1.921616, + 1.918043, + 1.911262, + 1.916676, + 1.927124, + 1.906464, + 1.908385, + 1.916297, + 1.917447, + 1.922029, + 1.90931, + 1.913343, + 1.923075, + 1.91074, + 1.910865, + 1.90305, + 1.917816, + 1.920193, + 1.91184, + 1.914851, + 1.923119, + 1.908148, + 1.911333, + 1.914984, + 1.916916, + 1.910413, + 1.913605, + 1.906368 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 2.243611, + 2.252638, + 2.243276, + 2.24779, + 2.277773, + 2.250892, + 2.244414, + 2.242031, + 2.257004, + 2.252066, + 2.248683, + 2.231664, + 2.23376, + 2.235491, + 2.250691, + 2.245477, + 2.256953, + 2.245298, + 2.246528, + 2.253934, + 2.26022, + 2.250603, + 2.23991, + 2.25006, + 2.25235, + 2.252034, + 2.240296, + 2.23701, + 2.229539, + 2.213563, + 2.22978, + 2.216301, + 2.242156, + 2.234157, + 2.233951, + 2.233262, + 2.240745, + 2.230858, + 2.236426, + 2.247388, + 2.250166, + 2.233368, + 2.233124, + 2.22084, + 2.240684, + 2.2312, + 2.23409, + 2.236855, + 2.249741, + 2.245114, + 2.2289, + 2.239202, + 2.239594, + 2.242428, + 2.225057, + 2.21861, + 2.235165, + 2.237965, + 2.235254, + 2.243663, + 2.249744, + 2.238135, + 2.244773, + 2.238024, + 2.249568, + 2.239485, + 2.23911, + 2.22865, + 2.244765, + 2.233372, + 2.227486, + 2.236465, + 2.240637, + 2.224854, + 2.223922, + 2.23957, + 2.246395, + 2.242906, + 2.2445, + 2.232792, + 2.247193, + 2.240338, + 2.228779, + 2.250854, + 2.261312, + 2.254785, + 2.248501, + 2.237154, + 2.244825, + 2.244925, + 2.219901, + 2.236051, + 2.239567, + 2.229131, + 2.234899, + 2.230817, + 2.251882, + 2.221372, + 2.225678, + 2.218365 + ], + "client_rtt_ms": [ + 2.272827, + 2.278528, + 2.279739, + 2.275064, + 2.306641, + 2.279379, + 2.270333, + 2.270023, + 2.281927, + 2.281733, + 2.277234, + 2.261599, + 2.260769, + 2.276487, + 2.284977, + 2.272458, + 2.285997, + 2.273576, + 2.273371, + 2.284209, + 2.286597, + 2.277809, + 2.265322, + 2.279769, + 2.27965, + 2.281112, + 2.270198, + 2.270979, + 2.256918, + 2.2393, + 2.258474, + 2.240849, + 2.268117, + 2.264989, + 2.260557, + 2.2603, + 2.267001, + 2.260609, + 2.262297, + 2.282195, + 2.279379, + 2.260385, + 2.261505, + 2.247948, + 2.268486, + 2.257397, + 2.260747, + 2.264972, + 2.276428, + 2.273472, + 2.255049, + 2.273065, + 2.265245, + 2.270998, + 2.254291, + 2.243119, + 2.265015, + 2.265166, + 2.264096, + 2.270196, + 2.279811, + 2.265924, + 2.272033, + 2.275074, + 2.276003, + 2.268912, + 2.265249, + 2.256957, + 2.277162, + 2.260016, + 2.254596, + 2.262505, + 2.267839, + 2.252194, + 2.253347, + 2.267571, + 2.282276, + 2.272628, + 2.272222, + 2.259291, + 2.273482, + 2.267603, + 2.256538, + 2.278799, + 2.289842, + 2.281747, + 2.279872, + 2.262936, + 2.280117, + 2.273074, + 2.246366, + 2.26405, + 2.265435, + 2.255936, + 2.260727, + 2.257452, + 2.277865, + 2.249857, + 2.252537, + 2.244017 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.350553, + 3.34448, + 3.354147, + 3.346238, + 3.339009, + 3.351013, + 3.325249, + 3.331901, + 3.355239, + 3.334576, + 3.343061, + 3.335219, + 3.307623, + 3.289382, + 3.304626, + 3.311312, + 3.349659, + 3.331455, + 3.336162, + 3.325718, + 3.338018, + 3.344015, + 3.321582, + 3.318655, + 3.328598, + 3.327526, + 3.337599, + 3.351638, + 3.318936, + 3.298712, + 3.296023, + 3.33832, + 3.34768, + 3.340467, + 3.320595, + 3.314265, + 3.346783, + 3.326996, + 3.323426, + 3.331347, + 3.329419, + 3.312399, + 3.308439, + 3.339412, + 3.349146, + 3.367644, + 3.365974, + 3.337183, + 3.345461, + 3.329144, + 3.336228, + 3.322772, + 3.312522, + 3.323261, + 3.33611, + 3.353875, + 3.360974, + 3.334887, + 3.315382, + 3.338924, + 3.342093, + 3.351715, + 3.351703, + 3.350258, + 3.374271, + 3.333536, + 3.352929, + 3.291074, + 3.336349, + 3.341952, + 3.360973, + 3.335962, + 3.364847, + 3.332651, + 3.336094, + 3.3382, + 3.353943, + 3.330152, + 3.339653, + 3.355924, + 3.351975, + 3.326241, + 3.324107, + 3.339141, + 3.370745, + 3.327773, + 3.330813, + 3.313259, + 3.319145, + 3.326131, + 3.353665, + 3.370137, + 3.395424, + 3.357498, + 3.345306, + 3.335324, + 3.341, + 3.327874, + 3.319524, + 3.308118 + ], + "client_rtt_ms": [ + 3.387796, + 3.379979, + 3.389442, + 3.380819, + 3.373575, + 3.392484, + 3.357926, + 3.364722, + 3.388547, + 3.36655, + 3.376767, + 3.371987, + 3.342229, + 3.321099, + 3.337915, + 3.344704, + 3.386245, + 3.373308, + 3.369489, + 3.363611, + 3.373615, + 3.376616, + 3.35462, + 3.352535, + 3.363593, + 3.362404, + 3.370475, + 3.387068, + 3.353686, + 3.338216, + 3.329268, + 3.375558, + 3.381309, + 3.373706, + 3.354982, + 3.34804, + 3.381397, + 3.361504, + 3.356421, + 3.364884, + 3.365639, + 3.353658, + 3.341851, + 3.373696, + 3.38555, + 3.400572, + 3.398786, + 3.372758, + 3.379552, + 3.362517, + 3.369565, + 3.356879, + 3.344654, + 3.362996, + 3.371636, + 3.387378, + 3.393682, + 3.371991, + 3.348, + 3.372399, + 3.377129, + 3.385451, + 3.388154, + 3.384919, + 3.409526, + 3.366073, + 3.393801, + 3.326795, + 3.366924, + 3.375174, + 3.395579, + 3.369561, + 3.39936, + 3.365176, + 3.369304, + 3.373103, + 3.388608, + 3.36608, + 3.380587, + 3.390991, + 3.386974, + 3.358388, + 3.358018, + 3.372936, + 3.402999, + 3.362732, + 3.364842, + 3.346155, + 3.351468, + 3.361458, + 3.396106, + 3.403741, + 3.429378, + 3.393995, + 3.378013, + 3.368205, + 3.374346, + 3.359005, + 3.351688, + 3.341081 + ] + } + } + }, + { + "label": "round1-retained-graph", + "raw_file_sha256": "c4dc2dd6945418b84ffa9cd8be04e72b0e96c98c9d738a8df58ec80ed4c78433", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "5fa7ccd47087a40822dcab78b2b80deea1bb42cb54463376e24aa7701b543078", + "mode": "graph", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.605608, + 1.608738, + 1.603752, + 1.611315, + 1.605502, + 1.606632, + 1.605018, + 1.610209, + 1.607036, + 1.605953, + 1.609647, + 1.621133, + 1.609557, + 1.604656, + 1.605528, + 1.598944, + 1.601686, + 1.604296, + 1.59851, + 1.60036, + 1.600868, + 1.603976, + 1.603888, + 1.609092, + 1.613266, + 1.608106, + 1.615197, + 1.602832, + 1.605762, + 1.60758, + 1.602746, + 1.602813, + 1.607791, + 1.602101, + 1.602491, + 1.59898, + 1.601429, + 1.600086, + 1.592736, + 1.593243, + 1.593907, + 1.597813, + 1.586701, + 1.58438, + 1.585405, + 1.591314, + 1.583035, + 1.583788, + 1.588838, + 1.590198, + 1.588945, + 1.590429, + 1.59457, + 1.591625, + 1.58721, + 1.591491, + 1.587243, + 1.595233, + 1.58693, + 1.587314, + 1.593985, + 1.586619, + 1.58833, + 1.589684, + 1.591255, + 1.587082, + 1.589336, + 1.58237, + 1.594091, + 1.583248, + 1.582131, + 1.587684, + 1.583993, + 1.58997, + 1.592431, + 1.587482, + 1.588612, + 1.591791, + 1.58791, + 1.582533, + 1.585941, + 1.580435, + 1.584907, + 1.583202, + 1.59047, + 1.584751, + 1.590107, + 1.592836, + 1.590151, + 1.591102, + 1.590165, + 1.592348, + 1.58977, + 1.588047, + 1.5923, + 1.580547, + 1.584145, + 1.581782, + 1.587231, + 1.588787 + ], + "client_rtt_ms": [ + 1.633243, + 1.633528, + 1.631148, + 1.64643, + 1.637124, + 1.640462, + 1.640478, + 1.646999, + 1.644577, + 1.644961, + 1.645205, + 1.656336, + 1.647067, + 1.648561, + 1.638066, + 1.631372, + 1.636155, + 1.636588, + 1.625969, + 1.626385, + 1.629397, + 1.630564, + 1.629431, + 1.636601, + 1.652243, + 1.632903, + 1.640539, + 1.629586, + 1.634016, + 1.632959, + 1.62664, + 1.628216, + 1.632179, + 1.629707, + 1.638855, + 1.62443, + 1.627918, + 1.624348, + 1.621264, + 1.621183, + 1.619461, + 1.624827, + 1.612352, + 1.610647, + 1.620171, + 1.616278, + 1.610611, + 1.610593, + 1.615608, + 1.616306, + 1.619635, + 1.615287, + 1.619415, + 1.617749, + 1.613432, + 1.629059, + 1.612062, + 1.620512, + 1.615796, + 1.612471, + 1.622079, + 1.611236, + 1.616922, + 1.615505, + 1.616846, + 1.621722, + 1.617829, + 1.606726, + 1.62117, + 1.607417, + 1.610734, + 1.611315, + 1.609682, + 1.618284, + 1.619218, + 1.622139, + 1.614783, + 1.62195, + 1.613589, + 1.607415, + 1.612263, + 1.607497, + 1.610872, + 1.607844, + 1.615342, + 1.62011, + 1.6167, + 1.621938, + 1.615775, + 1.617881, + 1.616503, + 1.617711, + 1.615341, + 1.614425, + 1.616361, + 1.60707, + 1.618775, + 1.609334, + 1.614038, + 1.618685 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.605859, + 1.606822, + 1.607577, + 1.609173, + 1.611362, + 1.612178, + 1.605905, + 1.613585, + 1.611313, + 1.611024, + 1.730645, + 1.619891, + 1.618979, + 1.614491, + 1.615105, + 1.613844, + 1.610827, + 1.605526, + 1.610775, + 1.612522, + 1.615078, + 1.61346, + 1.623719, + 1.614042, + 1.608519, + 1.617234, + 1.615393, + 1.614856, + 1.615594, + 1.612982, + 1.608961, + 1.609234, + 1.604996, + 1.604774, + 1.607681, + 1.608789, + 1.613475, + 1.611098, + 1.607193, + 1.613169, + 1.61088, + 1.610899, + 1.619855, + 1.612493, + 1.609054, + 1.607528, + 1.603669, + 1.604038, + 1.611783, + 1.612604, + 1.613287, + 1.613863, + 1.610996, + 1.614315, + 1.61268, + 1.610333, + 1.611974, + 1.609362, + 1.605533, + 1.604381, + 1.61411, + 1.611402, + 1.609284, + 1.613139, + 1.609906, + 1.608574, + 1.614101, + 1.62231, + 1.612723, + 1.613039, + 1.613124, + 1.614729, + 1.616119, + 1.615803, + 1.614559, + 1.61191, + 1.61271, + 1.613019, + 1.608999, + 1.602918, + 1.605455, + 1.608544, + 1.603157, + 1.605158, + 1.610945, + 1.612306, + 1.614543, + 1.622454, + 1.615524, + 1.626358, + 1.641631, + 1.621888, + 1.62434, + 1.622898, + 1.624988, + 1.621922, + 1.620583, + 1.623573, + 1.621564, + 1.621577 + ], + "client_rtt_ms": [ + 1.630877, + 1.632602, + 1.643285, + 1.637999, + 1.636844, + 1.639263, + 1.632637, + 1.641575, + 1.636878, + 1.638547, + 1.759909, + 1.654346, + 1.646962, + 1.64267, + 1.641674, + 1.640364, + 1.635317, + 1.633126, + 1.635141, + 1.646659, + 1.642967, + 1.637855, + 1.650346, + 1.642391, + 1.636845, + 1.644713, + 1.648131, + 1.64114, + 1.648542, + 1.643063, + 1.635364, + 1.637174, + 1.629424, + 1.630769, + 1.63284, + 1.634566, + 1.65344, + 1.636603, + 1.63567, + 1.641997, + 1.637076, + 1.637405, + 1.645382, + 1.642288, + 1.634604, + 1.639556, + 1.632151, + 1.62905, + 1.638276, + 1.639026, + 1.63786, + 1.643051, + 1.637382, + 1.645296, + 1.649939, + 1.639906, + 1.638757, + 1.634578, + 1.634088, + 1.630297, + 1.64113, + 1.636422, + 1.643231, + 1.644613, + 1.635856, + 1.635237, + 1.642443, + 1.651133, + 1.637768, + 1.639403, + 1.640039, + 1.648116, + 1.645276, + 1.642601, + 1.640141, + 1.64178, + 1.638779, + 1.640036, + 1.634437, + 1.639085, + 1.63348, + 1.63345, + 1.63358, + 1.629853, + 1.639884, + 1.638832, + 1.640656, + 1.649484, + 1.64993, + 1.657846, + 1.667703, + 1.647972, + 1.654102, + 1.648811, + 1.65185, + 1.649682, + 1.658996, + 1.651498, + 1.647343, + 1.652918 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.599881, + 1.596762, + 1.601518, + 1.59775, + 1.594836, + 1.599287, + 1.59654, + 1.586406, + 1.594512, + 1.58932, + 1.586407, + 1.58965, + 1.597353, + 1.597187, + 1.600513, + 1.596628, + 1.59101, + 1.588149, + 1.588553, + 1.592451, + 1.585489, + 1.591273, + 1.590363, + 1.589916, + 1.592605, + 1.59424, + 1.597648, + 1.596811, + 1.592612, + 1.594056, + 1.591006, + 1.595161, + 1.590177, + 1.586934, + 1.589083, + 1.587781, + 1.585386, + 1.589435, + 1.590703, + 1.59459, + 1.599696, + 1.59368, + 1.597843, + 1.591776, + 1.589598, + 1.591621, + 1.587354, + 1.587217, + 1.587485, + 1.592687, + 1.594613, + 1.593997, + 1.594701, + 1.588533, + 1.587156, + 1.589851, + 1.587554, + 1.590641, + 1.591311, + 1.594836, + 1.59503, + 1.591567, + 1.593339, + 1.590991, + 1.594757, + 1.590635, + 1.591633, + 1.592244, + 1.589706, + 1.589104, + 1.590706, + 1.592361, + 1.590432, + 1.58469, + 1.588566, + 1.59036, + 1.58653, + 1.595519, + 1.586555, + 1.586787, + 1.586241, + 1.587792, + 1.589184, + 1.589928, + 1.592008, + 1.596895, + 1.592645, + 1.597314, + 1.596155, + 1.59826, + 1.59286, + 1.595688, + 1.593744, + 1.586791, + 1.588883, + 1.584949, + 1.591288, + 1.594803, + 1.591757, + 1.598207 + ], + "client_rtt_ms": [ + 1.632291, + 1.623265, + 1.62568, + 1.626288, + 1.618378, + 1.626577, + 1.621149, + 1.609291, + 1.617739, + 1.612511, + 1.610357, + 1.613543, + 1.629297, + 1.623967, + 1.625089, + 1.623338, + 1.614874, + 1.611085, + 1.613408, + 1.615392, + 1.611611, + 1.614714, + 1.61348, + 1.614514, + 1.624095, + 1.622854, + 1.621858, + 1.621926, + 1.616966, + 1.617423, + 1.616943, + 1.618357, + 1.616762, + 1.610318, + 1.611731, + 1.614377, + 1.615516, + 1.614735, + 1.615151, + 1.617799, + 1.626111, + 1.617099, + 1.626048, + 1.614861, + 1.611944, + 1.616691, + 1.610024, + 1.612363, + 1.611028, + 1.635105, + 1.620313, + 1.617812, + 1.61977, + 1.611811, + 1.613871, + 1.613634, + 1.610116, + 1.61366, + 1.615123, + 1.619974, + 1.61865, + 1.622255, + 1.619426, + 1.614959, + 1.620536, + 1.615389, + 1.614977, + 1.616836, + 1.612699, + 1.616819, + 1.61399, + 1.616034, + 1.617826, + 1.614797, + 1.613396, + 1.613663, + 1.609482, + 1.617518, + 1.610023, + 1.610374, + 1.611259, + 1.613839, + 1.61696, + 1.614043, + 1.616988, + 1.621908, + 1.62649, + 1.621865, + 1.620141, + 1.622857, + 1.617117, + 1.623173, + 1.618147, + 1.610114, + 1.613011, + 1.608204, + 1.62152, + 1.618977, + 1.623954, + 1.624515 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 1.933652, + 1.937165, + 1.922706, + 1.941845, + 1.942442, + 1.955246, + 1.948356, + 1.945772, + 1.927145, + 1.935371, + 1.92246, + 1.928975, + 1.927878, + 1.926461, + 1.924252, + 1.925038, + 1.935348, + 1.935065, + 1.936306, + 1.959682, + 1.939373, + 1.942666, + 1.933205, + 1.925653, + 1.92825, + 1.942927, + 1.934369, + 1.929417, + 1.920073, + 1.922497, + 1.92822, + 1.926253, + 1.922679, + 1.935042, + 1.933863, + 1.932974, + 1.933145, + 1.940127, + 1.937594, + 1.93974, + 1.93425, + 1.945653, + 1.931413, + 1.927683, + 1.921613, + 1.93986, + 1.928258, + 1.941198, + 1.942694, + 1.944383, + 1.925807, + 1.925226, + 1.917394, + 1.917037, + 1.919479, + 1.922615, + 1.920122, + 1.9189, + 1.919673, + 1.916838, + 1.916188, + 1.915375, + 1.920067, + 1.924804, + 1.934539, + 1.931424, + 1.914026, + 1.932388, + 1.930915, + 1.916992, + 1.92815, + 1.945461, + 1.939501, + 1.932521, + 1.934267, + 1.930065, + 1.933206, + 1.935777, + 1.937211, + 1.935191, + 1.920097, + 1.930254, + 1.934685, + 1.948467, + 1.935796, + 1.94554, + 1.926634, + 1.919154, + 1.921933, + 1.927106, + 1.935955, + 1.934477, + 1.938772, + 1.934869, + 1.924964, + 1.930179, + 1.933805, + 1.913534, + 1.916103, + 1.918394 + ], + "client_rtt_ms": [ + 1.963188, + 1.96269, + 1.957888, + 1.96877, + 1.971956, + 1.981517, + 1.979279, + 1.972644, + 1.956578, + 1.961072, + 1.949848, + 1.954509, + 1.955456, + 1.951968, + 1.959533, + 1.953612, + 1.965911, + 1.962303, + 1.963486, + 1.985936, + 1.966237, + 1.96753, + 1.960029, + 1.951506, + 1.957982, + 1.970596, + 1.961785, + 1.962219, + 1.949998, + 1.947971, + 1.95658, + 1.951229, + 1.950891, + 1.962555, + 1.960975, + 1.96032, + 1.961846, + 1.967566, + 1.966314, + 1.976384, + 1.96117, + 1.974816, + 1.958279, + 1.954576, + 1.946399, + 1.96937, + 1.954411, + 1.968044, + 1.97019, + 1.972812, + 1.952781, + 1.95837, + 1.94289, + 1.943319, + 1.943883, + 1.948269, + 1.945059, + 1.946472, + 1.945202, + 1.943504, + 1.941229, + 1.941916, + 1.944902, + 1.95965, + 1.961974, + 1.962981, + 1.939689, + 1.95928, + 1.95675, + 1.943395, + 1.954043, + 1.972102, + 1.965271, + 1.96433, + 1.961679, + 1.956255, + 1.966273, + 1.963616, + 1.965101, + 1.9633, + 1.946146, + 1.958682, + 1.961905, + 1.976888, + 1.961186, + 1.973325, + 1.951918, + 1.945956, + 1.954152, + 1.955154, + 1.962789, + 1.961697, + 1.96637, + 1.963405, + 1.951831, + 1.957624, + 1.960479, + 1.941122, + 1.942085, + 1.943726 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.021469, + 3.020359, + 3.04487, + 3.012646, + 2.985469, + 2.988421, + 3.006713, + 3.0272, + 2.992367, + 2.994733, + 2.984743, + 2.976176, + 3.000011, + 3.019422, + 3.021258, + 3.02575, + 2.988466, + 2.992701, + 2.998456, + 3.000967, + 3.025143, + 3.055571, + 3.024862, + 3.033414, + 2.999558, + 3.002027, + 2.994839, + 3.021223, + 2.99306, + 2.994531, + 2.995087, + 2.993542, + 3.025499, + 3.036436, + 3.041175, + 3.01938, + 2.996226, + 2.987556, + 2.987267, + 3.00838, + 3.022338, + 3.003901, + 2.996294, + 2.996468, + 3.00929, + 3.060261, + 3.035925, + 3.029977, + 3.022357, + 2.987837, + 2.986371, + 2.981409, + 3.010404, + 3.037431, + 2.990162, + 2.997226, + 3.025381, + 3.021822, + 3.005856, + 2.999212, + 3.028312, + 3.018694, + 3.02867, + 3.032871, + 3.021917, + 2.984154, + 2.996435, + 3.00231, + 3.03546, + 3.052381, + 3.034527, + 3.025725, + 3.010065, + 3.02141, + 3.023802, + 3.018647, + 3.015192, + 3.015036, + 3.01563, + 2.985203, + 3.007222, + 2.994469, + 3.018327, + 2.991547, + 2.996796, + 3.020152, + 3.028197, + 3.030643, + 3.010648, + 3.030456, + 3.0442, + 3.024142, + 3.018382, + 3.020094, + 3.022301, + 3.018189, + 3.023789, + 3.021889, + 2.9962, + 3.018546 + ], + "client_rtt_ms": [ + 3.061922, + 3.055946, + 3.080032, + 3.045599, + 3.018003, + 3.030497, + 3.040595, + 3.060224, + 3.028357, + 3.027654, + 3.018201, + 3.008455, + 3.035333, + 3.054905, + 3.056722, + 3.06078, + 3.02285, + 3.033235, + 3.030435, + 3.034201, + 3.060396, + 3.089616, + 3.056838, + 3.069849, + 3.035046, + 3.034257, + 3.028132, + 3.052906, + 3.028115, + 3.034306, + 3.029566, + 3.024531, + 3.059936, + 3.07247, + 3.078172, + 3.052314, + 3.030511, + 3.02057, + 3.021136, + 3.040724, + 3.055144, + 3.045196, + 3.033032, + 3.032688, + 3.041319, + 3.095809, + 3.069335, + 3.065048, + 3.057045, + 3.020969, + 3.018818, + 3.015061, + 3.042331, + 3.07901, + 3.02175, + 3.029933, + 3.056306, + 3.055176, + 3.038736, + 3.032909, + 3.063468, + 3.051482, + 3.065159, + 3.068681, + 3.056367, + 3.015506, + 3.038361, + 3.036178, + 3.068953, + 3.08591, + 3.069259, + 3.06051, + 3.044533, + 3.053588, + 3.057511, + 3.052748, + 3.047316, + 3.048608, + 3.055213, + 3.017882, + 3.040873, + 3.027553, + 3.050705, + 3.024009, + 3.032005, + 3.053533, + 3.061319, + 3.0654, + 3.044568, + 3.064727, + 3.088537, + 3.057048, + 3.050513, + 3.054011, + 3.058131, + 3.050788, + 3.057122, + 3.058325, + 3.029523, + 3.0512 + ] + } + } + }, + { + "label": "round2-final-eager", + "raw_file_sha256": "35c78ab5a1f751cf137771e8a2be725a130d3beda241d2faf7bdd5e6c062bf6d", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "eeb94478354b5b6f0b26c756263261dd61908a0aafd82f10b04b907c3d46cc36", + "mode": "eager", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.966973, + 1.977752, + 1.962451, + 1.964415, + 1.970371, + 1.965162, + 1.964755, + 1.966175, + 1.975544, + 1.961764, + 1.95495, + 1.950333, + 1.960755, + 1.95041, + 1.973599, + 1.969506, + 1.96527, + 1.966948, + 1.963129, + 1.962883, + 1.949669, + 1.94534, + 1.943335, + 1.948043, + 1.960757, + 1.946721, + 1.956372, + 1.955196, + 1.959913, + 1.945172, + 1.946178, + 1.948478, + 1.957705, + 1.946854, + 1.949646, + 1.950733, + 1.95781, + 1.95306, + 1.954955, + 1.946769, + 1.956879, + 1.946224, + 1.947981, + 1.949744, + 1.953896, + 1.943342, + 1.949588, + 1.944506, + 1.948535, + 1.954149, + 1.950234, + 1.94824, + 1.955457, + 1.951852, + 1.947072, + 1.946727, + 1.957187, + 1.94814, + 1.950644, + 1.948482, + 1.954354, + 1.948017, + 1.945384, + 1.946933, + 1.948817, + 1.953252, + 1.949856, + 1.948845, + 1.946277, + 1.946559, + 1.932176, + 1.939476, + 1.942196, + 1.93606, + 1.936007, + 1.938263, + 1.941529, + 1.93236, + 1.935454, + 1.930584, + 1.939102, + 1.928818, + 1.936874, + 1.943069, + 1.942562, + 1.934449, + 1.932443, + 1.945754, + 1.940077, + 1.941677, + 1.931773, + 1.937488, + 1.941275, + 1.928631, + 1.936128, + 1.936778, + 1.934575, + 1.935413, + 1.929941, + 1.932919 + ], + "client_rtt_ms": [ + 1.993375, + 2.003127, + 1.990765, + 1.998944, + 2.002651, + 1.991808, + 1.991516, + 1.992609, + 2.004125, + 1.987397, + 1.981257, + 1.974977, + 1.987633, + 1.983115, + 2.001689, + 1.995449, + 1.995543, + 1.994563, + 1.988363, + 1.988402, + 1.977232, + 1.968885, + 1.969046, + 1.975442, + 2.001319, + 1.975847, + 1.982851, + 1.981795, + 1.984233, + 1.96928, + 1.971144, + 1.973661, + 1.982914, + 1.973038, + 1.985036, + 1.979111, + 1.984036, + 1.977312, + 1.980301, + 1.972993, + 1.982319, + 1.972233, + 1.973877, + 1.975931, + 1.988994, + 1.968975, + 1.975553, + 1.971123, + 1.976153, + 1.979135, + 1.977013, + 1.973063, + 1.98123, + 1.976415, + 1.974548, + 1.979538, + 1.983849, + 1.973308, + 1.979326, + 1.972733, + 1.978743, + 1.973261, + 1.972464, + 1.972131, + 1.975795, + 1.990261, + 1.978139, + 1.973591, + 1.976055, + 1.971846, + 1.959848, + 1.965232, + 1.970136, + 1.962921, + 1.965671, + 1.972864, + 1.969089, + 1.959736, + 1.962155, + 1.955178, + 1.964821, + 1.957285, + 1.960981, + 1.968784, + 1.967338, + 1.974362, + 1.957761, + 1.971176, + 1.964926, + 1.968135, + 1.956155, + 1.963313, + 1.966325, + 1.959939, + 1.960813, + 1.96402, + 1.973046, + 1.964371, + 1.960816, + 1.959843 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.96161, + 1.953273, + 1.95202, + 1.968779, + 1.96859, + 1.960399, + 1.959966, + 1.959552, + 1.962681, + 1.958172, + 1.962702, + 1.963354, + 1.972204, + 1.965303, + 1.964205, + 1.993889, + 1.971721, + 1.956822, + 1.961604, + 1.957787, + 1.979907, + 1.969222, + 1.961445, + 1.962278, + 1.966655, + 1.962442, + 1.953687, + 1.963255, + 1.964317, + 1.96188, + 1.955878, + 1.960967, + 1.953944, + 1.95977, + 1.95971, + 1.964128, + 1.970391, + 1.953839, + 1.960581, + 1.96087, + 1.970315, + 1.953297, + 1.955644, + 1.955161, + 1.979078, + 1.960823, + 1.956221, + 1.956084, + 1.968128, + 1.962067, + 1.95916, + 1.966331, + 1.972028, + 1.954993, + 1.962028, + 1.96029, + 1.969281, + 1.965083, + 1.958762, + 1.963044, + 1.976634, + 1.949188, + 1.956962, + 1.967619, + 1.966718, + 1.957343, + 1.956315, + 1.96289, + 1.963297, + 1.960289, + 1.957715, + 1.963353, + 1.976744, + 1.963477, + 1.964675, + 1.965413, + 1.961473, + 1.96317, + 1.959673, + 1.96002, + 1.968669, + 1.958994, + 1.958034, + 1.958449, + 1.971627, + 1.950117, + 1.960552, + 1.962993, + 1.965573, + 1.965594, + 1.957512, + 1.966697, + 1.984317, + 1.971883, + 1.97434, + 1.985495, + 1.974761, + 1.971613, + 1.974706, + 1.971656 + ], + "client_rtt_ms": [ + 1.987971, + 1.981883, + 1.986002, + 1.998328, + 1.99497, + 1.987971, + 1.986965, + 1.987827, + 1.990221, + 1.986778, + 1.991031, + 1.999698, + 1.998102, + 1.996796, + 1.991351, + 2.019362, + 1.997611, + 1.983979, + 1.98852, + 1.994698, + 2.008042, + 1.995044, + 1.988132, + 1.991431, + 1.993772, + 1.990387, + 1.982601, + 1.990856, + 1.997815, + 1.991346, + 1.983497, + 1.991774, + 1.979735, + 1.987688, + 1.986383, + 1.992799, + 2.005266, + 1.981319, + 1.985774, + 1.98936, + 1.99684, + 1.980754, + 1.980105, + 1.98307, + 2.004735, + 1.999102, + 1.980914, + 1.983019, + 1.99459, + 1.99101, + 1.984575, + 1.992127, + 1.998191, + 1.987264, + 1.998178, + 1.987539, + 1.996592, + 1.991773, + 1.984315, + 1.992309, + 2.002867, + 1.975234, + 1.991488, + 1.994991, + 1.993053, + 1.986187, + 1.983282, + 1.990085, + 1.99019, + 1.990559, + 1.983133, + 1.997757, + 2.00697, + 1.991931, + 1.990136, + 1.992577, + 1.988245, + 1.989482, + 1.986522, + 1.998157, + 1.994777, + 1.986131, + 1.98558, + 1.985875, + 1.997609, + 1.976999, + 1.988334, + 1.990288, + 2.000102, + 1.995295, + 1.982696, + 1.993841, + 2.012161, + 1.998895, + 2.000674, + 2.013075, + 2.009226, + 2.00461, + 2.010531, + 1.999872 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.951149, + 1.945466, + 1.95333, + 1.944978, + 1.955055, + 1.945763, + 1.943876, + 1.943618, + 1.944609, + 1.952416, + 1.942089, + 1.950387, + 1.952942, + 1.939168, + 1.924658, + 1.946746, + 1.947718, + 1.943152, + 1.943765, + 1.942214, + 1.947884, + 1.942776, + 1.945929, + 1.943508, + 1.944399, + 1.93733, + 1.936092, + 1.94029, + 1.952109, + 1.936116, + 1.936074, + 1.941259, + 1.947013, + 1.937721, + 1.9423, + 1.94507, + 1.954173, + 1.941151, + 1.943322, + 1.946709, + 1.946894, + 1.934395, + 1.942331, + 1.94664, + 1.946571, + 1.939803, + 1.937324, + 1.938956, + 1.947703, + 1.940397, + 1.943303, + 1.934512, + 1.955336, + 1.947498, + 1.942304, + 1.94861, + 1.952267, + 1.945444, + 1.941248, + 1.946529, + 1.951817, + 1.944, + 1.939541, + 1.940551, + 1.94815, + 1.93136, + 1.938373, + 1.936661, + 1.949513, + 1.945196, + 1.939409, + 1.942185, + 1.949543, + 1.94103, + 1.940218, + 1.939368, + 1.949248, + 1.939337, + 1.933189, + 1.942975, + 1.941276, + 1.941824, + 1.942357, + 1.933284, + 1.950646, + 1.938864, + 1.936012, + 1.940008, + 1.949326, + 1.940003, + 1.9381, + 1.944009, + 1.955918, + 1.945138, + 1.939114, + 1.942296, + 1.938193, + 1.94193, + 1.941911, + 1.939625 + ], + "client_rtt_ms": [ + 1.983958, + 1.971568, + 1.976374, + 1.971705, + 1.986238, + 1.971434, + 1.968732, + 1.974893, + 1.968123, + 1.977573, + 1.966635, + 1.975892, + 1.986932, + 1.965431, + 1.948877, + 1.9745, + 1.971859, + 1.968381, + 1.969781, + 1.967603, + 1.971764, + 1.968188, + 1.969335, + 1.967148, + 1.976764, + 1.961861, + 1.959304, + 1.965087, + 1.976489, + 1.960513, + 1.961129, + 1.965469, + 1.973007, + 1.96359, + 1.966466, + 1.973884, + 1.988823, + 1.966256, + 1.968029, + 1.971643, + 1.971525, + 1.958079, + 1.967024, + 1.970453, + 1.970699, + 1.963975, + 1.961745, + 1.963244, + 1.971598, + 1.974516, + 1.973397, + 1.96026, + 1.978309, + 1.974829, + 1.966474, + 1.974225, + 1.976397, + 1.970732, + 1.965679, + 1.97189, + 1.975808, + 1.977176, + 1.964244, + 1.968186, + 1.971634, + 1.956612, + 1.962701, + 1.963503, + 1.974595, + 1.970689, + 1.963754, + 1.967895, + 1.97361, + 1.97273, + 1.964887, + 1.966583, + 1.97438, + 1.965482, + 1.957297, + 1.96771, + 1.964017, + 1.968224, + 1.968885, + 1.960722, + 1.977271, + 1.963821, + 1.967751, + 1.965533, + 1.972459, + 1.967132, + 1.962188, + 1.969089, + 1.97985, + 1.970474, + 1.964398, + 1.967854, + 1.962895, + 1.971757, + 1.972503, + 1.965604 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 2.313966, + 2.295836, + 2.288905, + 2.296953, + 2.325229, + 2.30491, + 2.313659, + 2.29569, + 2.323271, + 2.303774, + 2.302394, + 2.304861, + 2.324564, + 2.291039, + 2.307297, + 2.308275, + 2.32159, + 2.300275, + 2.280493, + 2.311713, + 2.346308, + 2.33067, + 2.332643, + 2.315193, + 2.32419, + 2.301734, + 2.308963, + 2.300368, + 2.322097, + 2.302348, + 2.297448, + 2.302929, + 2.315337, + 2.289023, + 2.288169, + 2.287894, + 2.307006, + 2.284184, + 2.291328, + 2.290626, + 2.315441, + 2.300865, + 2.284787, + 2.29463, + 2.318402, + 2.294299, + 2.294171, + 2.282787, + 2.311565, + 2.285319, + 2.297926, + 2.284053, + 2.304697, + 2.292856, + 2.298646, + 2.287823, + 2.313288, + 2.299189, + 2.29469, + 2.290528, + 2.3187, + 2.297589, + 2.296056, + 2.284429, + 2.314552, + 2.28889, + 2.285636, + 2.284227, + 2.314758, + 2.288163, + 2.291658, + 2.288383, + 2.303323, + 2.297101, + 2.29417, + 2.294773, + 2.305041, + 2.279928, + 2.276901, + 2.275977, + 2.299414, + 2.274241, + 2.291664, + 2.294922, + 2.318222, + 2.308954, + 2.285217, + 2.27694, + 2.315021, + 2.301161, + 2.289449, + 2.285591, + 2.317732, + 2.287615, + 2.290448, + 2.290388, + 2.311448, + 2.288027, + 2.293127, + 2.291839 + ], + "client_rtt_ms": [ + 2.339833, + 2.322458, + 2.323091, + 2.323836, + 2.353627, + 2.332635, + 2.340654, + 2.323049, + 2.34961, + 2.329629, + 2.330789, + 2.332842, + 2.35054, + 2.319325, + 2.352707, + 2.33629, + 2.34961, + 2.327053, + 2.313245, + 2.339175, + 2.37412, + 2.358717, + 2.359722, + 2.343838, + 2.352102, + 2.329829, + 2.33742, + 2.33489, + 2.348232, + 2.328723, + 2.325286, + 2.329197, + 2.34308, + 2.317696, + 2.313794, + 2.314471, + 2.331886, + 2.309078, + 2.31743, + 2.324781, + 2.343322, + 2.327064, + 2.311966, + 2.320722, + 2.345816, + 2.322227, + 2.321181, + 2.308615, + 2.33784, + 2.313199, + 2.32671, + 2.317302, + 2.33314, + 2.319886, + 2.32662, + 2.314766, + 2.33987, + 2.40083, + 2.35809, + 2.32065, + 2.346556, + 2.32704, + 2.326582, + 2.339454, + 2.342284, + 2.31663, + 2.313369, + 2.311638, + 2.34165, + 2.314843, + 2.317206, + 2.316286, + 2.329562, + 2.340314, + 2.321937, + 2.321929, + 2.340961, + 2.306508, + 2.30433, + 2.300604, + 2.325888, + 2.301286, + 2.319203, + 2.322722, + 2.34485, + 2.336963, + 2.312251, + 2.302698, + 2.349106, + 2.328136, + 2.317291, + 2.314228, + 2.344737, + 2.318676, + 2.316557, + 2.317838, + 2.338019, + 2.314825, + 2.321557, + 2.317713 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.40529, + 3.358397, + 3.357778, + 3.363443, + 3.391495, + 3.365999, + 3.372942, + 3.354284, + 3.398304, + 3.368036, + 3.371065, + 3.364748, + 3.389994, + 3.327007, + 3.36769, + 3.367412, + 3.40674, + 3.387806, + 3.356366, + 3.330399, + 3.362865, + 3.373424, + 3.385516, + 3.360376, + 3.386973, + 3.336057, + 3.3429, + 3.342377, + 3.37996, + 3.374005, + 3.381412, + 3.325393, + 3.358063, + 3.366076, + 3.358243, + 3.370787, + 3.375825, + 3.328398, + 3.337438, + 3.373852, + 3.383196, + 3.35645, + 3.355987, + 3.33301, + 3.35772, + 3.403886, + 3.381398, + 3.38149, + 3.373568, + 3.360639, + 3.340417, + 3.360528, + 3.351747, + 3.361312, + 3.33931, + 3.331473, + 3.377964, + 3.365083, + 3.355922, + 3.334332, + 3.369259, + 3.362354, + 3.368908, + 3.375411, + 3.412222, + 3.336069, + 3.33564, + 3.358158, + 3.408283, + 3.410765, + 3.386161, + 3.358041, + 3.384125, + 3.378195, + 3.335017, + 3.36355, + 3.398356, + 3.387865, + 3.372215, + 3.356867, + 3.348186, + 3.342131, + 3.366034, + 3.367432, + 3.388194, + 3.359517, + 3.339214, + 3.334077, + 3.351317, + 3.359974, + 3.365296, + 3.368378, + 3.41033, + 3.401162, + 3.377991, + 3.364564, + 3.420126, + 3.359737, + 3.375641, + 3.353799 + ], + "client_rtt_ms": [ + 3.442344, + 3.392011, + 3.399443, + 3.397598, + 3.425498, + 3.409708, + 3.406203, + 3.386209, + 3.430671, + 3.400538, + 3.405282, + 3.398889, + 3.424703, + 3.359824, + 3.400661, + 3.399672, + 3.440252, + 3.430197, + 3.388132, + 3.36241, + 3.394604, + 3.407768, + 3.41823, + 3.394229, + 3.420082, + 3.367188, + 3.374322, + 3.375495, + 3.414156, + 3.413574, + 3.415605, + 3.357752, + 3.390888, + 3.398419, + 3.391392, + 3.408405, + 3.40887, + 3.360079, + 3.37175, + 3.406492, + 3.418111, + 3.398148, + 3.388467, + 3.369339, + 3.391661, + 3.438343, + 3.415252, + 3.417524, + 3.407076, + 3.392812, + 3.373959, + 3.395629, + 3.385272, + 3.400075, + 3.370918, + 3.363985, + 3.409394, + 3.401494, + 3.389426, + 3.365788, + 3.404203, + 3.393926, + 3.404138, + 3.411329, + 3.445671, + 3.367765, + 3.376481, + 3.391128, + 3.442471, + 3.443164, + 3.418398, + 3.392121, + 3.417591, + 3.410797, + 3.367998, + 3.401292, + 3.429489, + 3.421436, + 3.41554, + 3.38945, + 3.379892, + 3.375131, + 3.400811, + 3.400359, + 3.421879, + 3.392441, + 3.371759, + 3.367656, + 3.384222, + 3.393908, + 3.404204, + 3.401621, + 3.443778, + 3.4339, + 3.411972, + 3.397419, + 3.454356, + 3.39262, + 3.410217, + 3.388762 + ] + } + } + }, + { + "label": "round2-final-graph", + "raw_file_sha256": "7821cd9a6f21335f57a7345c69c077434606e3eeda0a1e38e8fa306d381ce613", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "eeb94478354b5b6f0b26c756263261dd61908a0aafd82f10b04b907c3d46cc36", + "mode": "graph", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.601872, + 1.602455, + 1.613503, + 1.602169, + 1.60365, + 1.603248, + 1.605948, + 1.601354, + 1.618084, + 1.636368, + 1.61017, + 1.613114, + 1.625015, + 1.614814, + 1.644508, + 1.633364, + 1.665595, + 1.681863, + 1.654043, + 1.627999, + 1.651839, + 1.635206, + 1.624066, + 1.62758, + 1.613907, + 1.612123, + 1.62048, + 1.621238, + 1.614735, + 1.635435, + 1.627819, + 1.61711, + 1.605242, + 1.613901, + 1.602944, + 1.602544, + 1.595621, + 1.590502, + 1.613214, + 1.60494, + 1.597303, + 1.596286, + 1.611015, + 1.592366, + 1.590256, + 1.588842, + 1.585809, + 1.585405, + 1.581363, + 1.584897, + 1.587408, + 1.586806, + 1.59219, + 1.587247, + 1.58803, + 1.591171, + 1.592633, + 1.589355, + 1.589997, + 1.584473, + 1.582541, + 1.587093, + 1.582237, + 1.585553, + 1.589011, + 1.591041, + 1.594241, + 1.588747, + 1.586967, + 1.596498, + 1.59797, + 1.593098, + 1.593217, + 1.588736, + 1.592055, + 1.593174, + 1.588278, + 1.585884, + 1.585924, + 1.590967, + 1.590413, + 1.583499, + 1.587447, + 1.590505, + 1.58781, + 1.581073, + 1.583596, + 1.583104, + 1.586841, + 1.580059, + 1.589857, + 1.594471, + 1.592509, + 1.590221, + 1.587661, + 1.597284, + 1.602151, + 1.586468, + 1.589193, + 1.584404 + ], + "client_rtt_ms": [ + 1.627112, + 1.629341, + 1.640145, + 1.650947, + 1.657608, + 1.634306, + 1.639361, + 1.636999, + 1.655917, + 1.670115, + 1.644899, + 1.645504, + 1.655213, + 1.657479, + 1.682532, + 1.664788, + 1.695707, + 1.711726, + 1.682552, + 1.655541, + 1.680291, + 1.660904, + 1.649733, + 1.655225, + 1.652328, + 1.637332, + 1.644131, + 1.648132, + 1.640416, + 1.660747, + 1.652896, + 1.6491, + 1.632069, + 1.639489, + 1.637142, + 1.629672, + 1.621401, + 1.61686, + 1.638617, + 1.633956, + 1.622058, + 1.622461, + 1.637483, + 1.619388, + 1.625527, + 1.613687, + 1.610285, + 1.612508, + 1.606493, + 1.610709, + 1.612688, + 1.61196, + 1.616435, + 1.610958, + 1.61515, + 1.627228, + 1.61883, + 1.615996, + 1.616116, + 1.608781, + 1.606501, + 1.613918, + 1.609784, + 1.609391, + 1.613861, + 1.626378, + 1.626794, + 1.616912, + 1.612917, + 1.624414, + 1.625612, + 1.619373, + 1.619261, + 1.615698, + 1.620021, + 1.637461, + 1.622066, + 1.614687, + 1.612446, + 1.616238, + 1.616774, + 1.610823, + 1.612024, + 1.616847, + 1.611339, + 1.614757, + 1.608841, + 1.608659, + 1.611038, + 1.606134, + 1.614704, + 1.621014, + 1.621829, + 1.618521, + 1.612867, + 1.624431, + 1.637358, + 1.61327, + 1.615843, + 1.609062 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.603908, + 1.602456, + 1.607447, + 1.605281, + 1.607703, + 1.612353, + 1.609905, + 1.609922, + 1.616194, + 1.601235, + 1.606192, + 1.604986, + 1.600342, + 1.606251, + 1.613572, + 1.613034, + 1.611407, + 1.608945, + 1.608703, + 1.605581, + 1.604515, + 1.60363, + 1.601605, + 1.608802, + 1.603015, + 1.607664, + 1.608175, + 1.613086, + 1.608572, + 1.605405, + 1.611514, + 1.612991, + 1.607383, + 1.604342, + 1.608328, + 1.603984, + 1.602787, + 1.605511, + 1.606542, + 1.602336, + 1.606599, + 1.605484, + 1.605761, + 1.603685, + 1.604473, + 1.598861, + 1.6065, + 1.606232, + 1.605552, + 1.604742, + 1.613734, + 1.610458, + 1.611867, + 1.616582, + 1.608983, + 1.608797, + 1.606869, + 1.603024, + 1.60418, + 1.604441, + 1.596304, + 1.604073, + 1.603394, + 1.603831, + 1.649834, + 1.621422, + 1.611114, + 1.614682, + 1.608031, + 1.607066, + 1.60789, + 1.607041, + 1.605418, + 1.610868, + 1.622849, + 1.613683, + 1.610245, + 1.609491, + 1.604636, + 1.603799, + 1.604225, + 1.603273, + 1.60555, + 1.602873, + 1.603479, + 1.613569, + 1.602735, + 1.604436, + 1.610424, + 1.608555, + 1.616352, + 1.619639, + 1.613732, + 1.625447, + 1.618114, + 1.617506, + 1.618534, + 1.623016, + 1.62054, + 1.626034 + ], + "client_rtt_ms": [ + 1.628739, + 1.628639, + 1.640143, + 1.633225, + 1.634925, + 1.63753, + 1.637292, + 1.638073, + 1.642693, + 1.627296, + 1.63247, + 1.638154, + 1.627927, + 1.6342, + 1.640581, + 1.64099, + 1.637834, + 1.634624, + 1.637852, + 1.636791, + 1.636089, + 1.628724, + 1.626048, + 1.636723, + 1.628187, + 1.632775, + 1.636372, + 1.641636, + 1.639394, + 1.629815, + 1.641758, + 1.637803, + 1.635641, + 1.631062, + 1.633933, + 1.629608, + 1.637049, + 1.631725, + 1.630733, + 1.639287, + 1.633801, + 1.629858, + 1.63187, + 1.62962, + 1.630853, + 1.631969, + 1.633505, + 1.632233, + 1.630532, + 1.632163, + 1.640725, + 1.636059, + 1.639249, + 1.648217, + 1.644806, + 1.635004, + 1.635042, + 1.629521, + 1.628489, + 1.630974, + 1.620075, + 1.63076, + 1.637321, + 1.631304, + 1.678163, + 1.648192, + 1.640485, + 1.645756, + 1.634047, + 1.641315, + 1.63286, + 1.640273, + 1.633397, + 1.641684, + 1.652725, + 1.64049, + 1.637667, + 1.636505, + 1.631399, + 1.637501, + 1.629836, + 1.629209, + 1.631661, + 1.627503, + 1.628949, + 1.639243, + 1.633063, + 1.629528, + 1.64347, + 1.634949, + 1.642719, + 1.643899, + 1.638832, + 1.650943, + 1.642769, + 1.644648, + 1.650249, + 1.64888, + 1.648193, + 1.654213 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.595179, + 1.594057, + 1.593881, + 1.592559, + 1.594511, + 1.593124, + 1.596603, + 1.596607, + 1.596412, + 1.59319, + 1.589919, + 1.591216, + 1.599665, + 1.589206, + 1.59781, + 1.594881, + 1.601599, + 1.597253, + 1.596892, + 1.593717, + 1.59056, + 1.592075, + 1.588246, + 1.591219, + 1.590685, + 1.589865, + 1.588397, + 1.58546, + 1.587978, + 1.590602, + 1.597938, + 1.59684, + 1.594743, + 1.59267, + 1.593035, + 1.594879, + 1.597109, + 1.592693, + 1.597469, + 1.596952, + 1.596282, + 1.592706, + 1.591118, + 1.59232, + 1.585386, + 1.588049, + 1.597389, + 1.594662, + 1.595579, + 1.595621, + 1.595637, + 1.596782, + 1.595852, + 1.596584, + 1.592965, + 1.596133, + 1.589444, + 1.59215, + 1.591876, + 1.595257, + 1.59296, + 1.602545, + 1.598834, + 1.594239, + 1.594953, + 1.598906, + 1.596075, + 1.589987, + 1.589781, + 1.593614, + 1.596038, + 1.593411, + 1.596026, + 1.598035, + 1.600619, + 1.5998, + 1.593524, + 1.594132, + 1.592971, + 1.5907, + 1.587951, + 1.587817, + 1.590858, + 1.597617, + 1.589589, + 1.599755, + 1.594433, + 1.590925, + 1.589474, + 1.590201, + 1.592019, + 1.591158, + 1.590475, + 1.586153, + 1.600079, + 1.585366, + 1.587007, + 1.594093, + 1.600499, + 1.591343 + ], + "client_rtt_ms": [ + 1.62665, + 1.618407, + 1.618755, + 1.616812, + 1.620429, + 1.617717, + 1.620592, + 1.6235, + 1.619525, + 1.617541, + 1.613314, + 1.615413, + 1.635057, + 1.618926, + 1.625236, + 1.619573, + 1.62748, + 1.62404, + 1.620018, + 1.619124, + 1.614723, + 1.619455, + 1.611965, + 1.614325, + 1.624294, + 1.614112, + 1.613753, + 1.608347, + 1.611794, + 1.614897, + 1.62383, + 1.622093, + 1.620153, + 1.615904, + 1.619356, + 1.620354, + 1.631244, + 1.616413, + 1.628172, + 1.61909, + 1.619782, + 1.615549, + 1.615242, + 1.616618, + 1.608676, + 1.612207, + 1.622336, + 1.617887, + 1.620939, + 1.628724, + 1.620332, + 1.622136, + 1.620262, + 1.621036, + 1.616573, + 1.621342, + 1.613685, + 1.614785, + 1.618009, + 1.617971, + 1.615595, + 1.636815, + 1.623191, + 1.619507, + 1.618789, + 1.625842, + 1.621189, + 1.613783, + 1.614988, + 1.61755, + 1.623852, + 1.617944, + 1.619418, + 1.630854, + 1.625587, + 1.629542, + 1.619134, + 1.618636, + 1.619361, + 1.614374, + 1.613315, + 1.612332, + 1.616971, + 1.623573, + 1.612991, + 1.62451, + 1.62652, + 1.616615, + 1.614048, + 1.613635, + 1.617472, + 1.615308, + 1.615023, + 1.609461, + 1.62254, + 1.608916, + 1.611489, + 1.617554, + 1.6319, + 1.614937 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 1.949947, + 1.933353, + 1.918736, + 1.921593, + 1.921439, + 1.92607, + 1.925348, + 1.930219, + 1.935242, + 1.9231, + 1.93953, + 1.921792, + 1.928308, + 1.934129, + 1.916025, + 1.92164, + 1.922391, + 1.931708, + 1.937147, + 1.94994, + 1.953459, + 1.949372, + 1.937402, + 1.930848, + 1.916828, + 1.906084, + 1.9135, + 1.923144, + 1.913852, + 1.923455, + 1.929169, + 1.910675, + 1.926282, + 1.915139, + 1.925957, + 1.919201, + 1.926552, + 1.920105, + 1.928783, + 1.916634, + 1.919213, + 1.926298, + 1.915309, + 1.908266, + 1.915541, + 1.905726, + 1.909889, + 1.908903, + 1.906559, + 1.905741, + 1.896732, + 1.90688, + 1.907356, + 1.909968, + 1.919054, + 1.922041, + 1.924848, + 1.934166, + 1.928452, + 1.934485, + 1.922561, + 1.919778, + 1.906215, + 1.927029, + 1.908286, + 1.920124, + 1.922427, + 1.928205, + 1.935264, + 1.92964, + 1.930871, + 1.927717, + 1.920624, + 1.908928, + 1.919197, + 1.907983, + 1.902511, + 1.914206, + 1.933267, + 1.927767, + 1.927879, + 1.927435, + 1.920024, + 1.943778, + 1.933752, + 1.932903, + 1.922458, + 1.921726, + 1.908216, + 1.915518, + 1.916158, + 1.916457, + 1.90689, + 1.903786, + 1.906317, + 1.910975, + 1.924702, + 1.92506, + 1.920852, + 1.919016 + ], + "client_rtt_ms": [ + 1.975747, + 1.961619, + 1.954755, + 1.948247, + 1.946387, + 1.953349, + 1.950291, + 1.960945, + 1.962291, + 1.951654, + 1.967405, + 1.94898, + 1.953463, + 1.961198, + 1.949636, + 1.94747, + 1.948917, + 1.959197, + 1.964869, + 1.978472, + 1.980904, + 1.978638, + 1.962938, + 1.959217, + 1.942879, + 1.934823, + 1.939262, + 1.959801, + 1.93879, + 1.949107, + 1.957313, + 1.942459, + 1.948508, + 1.940464, + 1.95322, + 1.944391, + 1.953918, + 1.945179, + 1.953745, + 1.948761, + 1.946165, + 1.95178, + 1.94205, + 1.93397, + 1.942796, + 1.930127, + 1.935052, + 1.933029, + 1.932885, + 1.931064, + 1.92514, + 1.939232, + 1.934111, + 1.936546, + 1.946013, + 1.948522, + 1.952047, + 1.961977, + 1.962009, + 1.962483, + 1.952441, + 1.946555, + 1.932489, + 1.961756, + 1.935527, + 1.947668, + 1.950754, + 1.956031, + 1.966342, + 1.956813, + 1.958965, + 1.954672, + 1.948348, + 1.935321, + 1.946599, + 1.933612, + 1.937003, + 1.942079, + 1.96085, + 1.955504, + 1.954897, + 1.956016, + 1.945652, + 1.977042, + 1.958906, + 1.959511, + 1.947287, + 1.947343, + 1.940045, + 1.94235, + 1.942593, + 1.94357, + 1.93254, + 1.929569, + 1.931579, + 1.937534, + 1.95128, + 1.951557, + 1.947658, + 1.946797 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 2.971469, + 2.963751, + 2.965982, + 2.995765, + 2.968734, + 2.994139, + 2.961051, + 2.968232, + 2.971646, + 3.000018, + 2.991129, + 2.964958, + 2.967765, + 2.969375, + 2.971127, + 2.962768, + 3.009668, + 2.992412, + 2.997232, + 2.99778, + 2.993176, + 3.024919, + 3.014261, + 3.019721, + 2.996276, + 2.972431, + 2.971228, + 2.972885, + 2.994627, + 2.994627, + 2.999102, + 2.994307, + 3.000094, + 2.96126, + 3.001397, + 3.004734, + 2.998717, + 2.976254, + 2.995568, + 2.974325, + 2.977048, + 2.998482, + 2.980048, + 2.969725, + 2.985038, + 3.000185, + 3.007278, + 3.012362, + 2.99905, + 2.993036, + 2.986312, + 2.958653, + 2.974259, + 2.97368, + 2.968881, + 2.997401, + 3.002918, + 2.990112, + 2.964408, + 2.97734, + 2.972945, + 2.968984, + 3.003099, + 3.009999, + 3.027404, + 2.994738, + 2.966886, + 2.968904, + 2.985767, + 3.036317, + 3.0126, + 2.996979, + 2.961013, + 2.977899, + 2.964989, + 2.993149, + 2.995289, + 2.987627, + 2.976326, + 2.997842, + 2.996921, + 2.984079, + 2.969285, + 2.994957, + 2.994626, + 2.994734, + 2.996931, + 2.975455, + 2.970972, + 2.996108, + 2.9644, + 2.957985, + 2.9859, + 2.997807, + 3.004015, + 3.009827, + 2.994245, + 2.989125, + 2.96785, + 2.963315 + ], + "client_rtt_ms": [ + 3.009516, + 2.995292, + 3.000209, + 3.034063, + 3.001175, + 3.042617, + 2.992066, + 3.000945, + 3.004731, + 3.033463, + 3.02379, + 2.998249, + 3.00153, + 3.002175, + 3.002739, + 2.997149, + 3.050777, + 3.036095, + 3.031546, + 3.032163, + 3.02742, + 3.057302, + 3.046226, + 3.053293, + 3.032022, + 3.00428, + 3.002948, + 3.006449, + 3.027856, + 3.036268, + 3.031784, + 3.029059, + 3.034807, + 2.995188, + 3.034808, + 3.037506, + 3.032827, + 3.009426, + 3.030018, + 3.004878, + 3.009106, + 3.038366, + 3.013201, + 3.00124, + 3.019361, + 3.035005, + 3.042962, + 3.045391, + 3.032603, + 3.028901, + 3.019575, + 2.990093, + 3.008323, + 3.015013, + 3.000346, + 3.030098, + 3.048741, + 3.025148, + 2.998677, + 3.008734, + 3.00428, + 3.003545, + 3.037327, + 3.044509, + 3.060234, + 3.031383, + 3.007238, + 3.001304, + 3.017986, + 3.070462, + 3.046818, + 3.028928, + 2.992584, + 3.010458, + 2.997269, + 3.02765, + 3.026935, + 3.023956, + 3.016883, + 3.032868, + 3.028239, + 3.015719, + 3.003573, + 3.029718, + 3.02678, + 3.028101, + 3.028929, + 3.007141, + 3.0042, + 3.028559, + 3.006013, + 2.989732, + 3.019263, + 3.029807, + 3.038258, + 3.044131, + 3.026788, + 3.021553, + 3.00034, + 2.994912 + ] + } + } + }, + { + "label": "round2-initial-eager", + "raw_file_sha256": "d9f64f644be668e570515912538bee41c96c771c610822a6150486716f325596", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "a95ee8e50065f2e39d8a6c8ced32e8ff434dd42903bd741040ea9205da79813e", + "mode": "eager", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.890009, + 2.890397, + 2.877284, + 2.895061, + 2.88697, + 2.887082, + 2.896375, + 2.87988, + 2.905866, + 2.883261, + 2.884468, + 2.891977, + 2.889606, + 2.888468, + 2.883374, + 2.884985, + 2.886005, + 2.877938, + 2.880862, + 2.888116, + 2.883828, + 2.884798, + 2.881001, + 2.875861, + 2.890383, + 2.873675, + 2.87872, + 2.872376, + 2.877458, + 2.879219, + 2.880141, + 2.882991, + 2.878097, + 2.882165, + 2.877084, + 2.877785, + 2.879185, + 2.882353, + 2.88203, + 2.877686, + 2.881445, + 2.868096, + 2.878131, + 2.873598, + 2.884728, + 2.88145, + 2.874482, + 2.875274, + 2.876616, + 2.877566, + 2.871376, + 2.883896, + 2.87921, + 2.879088, + 2.87111, + 2.868689, + 2.878107, + 3.015218, + 2.94576, + 2.881791, + 2.872964, + 2.869217, + 2.868535, + 2.866934, + 2.873397, + 2.863681, + 2.86519, + 2.869285, + 2.872939, + 2.870427, + 2.871941, + 2.86897, + 2.873588, + 2.865205, + 2.865599, + 2.859336, + 2.868494, + 2.864848, + 2.866742, + 2.864189, + 2.874118, + 2.869007, + 2.865304, + 2.867377, + 2.867126, + 2.8736, + 2.868338, + 2.866877, + 2.869018, + 2.864059, + 2.859151, + 2.864094, + 2.865922, + 2.865199, + 2.879276, + 2.863173, + 2.863166, + 2.863651, + 2.864731, + 2.860488 + ], + "client_rtt_ms": [ + 2.919203, + 2.919254, + 2.905003, + 2.937959, + 2.921015, + 2.916256, + 2.927572, + 2.910524, + 2.935802, + 2.91212, + 2.912064, + 2.9193, + 2.918077, + 2.925909, + 2.909466, + 2.913286, + 2.913874, + 2.904936, + 2.908368, + 2.914465, + 2.912909, + 2.911558, + 2.909497, + 2.906439, + 2.930087, + 2.901526, + 2.905043, + 2.900389, + 2.904843, + 2.91394, + 2.906119, + 2.910682, + 2.904293, + 2.911019, + 2.917338, + 2.906344, + 2.905247, + 2.909496, + 2.910201, + 2.905413, + 2.908666, + 2.89473, + 2.90437, + 2.900999, + 2.920299, + 2.908739, + 2.899897, + 2.905192, + 2.903896, + 2.903988, + 2.898128, + 2.910359, + 2.9055, + 2.905918, + 2.897666, + 2.904037, + 2.905201, + 3.042977, + 2.974646, + 2.910074, + 2.899406, + 2.895363, + 2.897148, + 2.895383, + 2.899628, + 2.900047, + 2.893846, + 2.895123, + 2.898554, + 2.897067, + 2.899727, + 2.894097, + 2.899591, + 2.899868, + 2.89604, + 2.89587, + 2.895305, + 2.892663, + 2.892667, + 2.891294, + 2.900456, + 2.896819, + 2.8914, + 2.894345, + 2.893251, + 2.908965, + 2.895314, + 2.892802, + 2.897235, + 2.89122, + 2.885763, + 2.890003, + 2.892493, + 2.892825, + 2.90541, + 2.890221, + 2.901457, + 2.891038, + 2.891864, + 2.886935 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 2.92966, + 2.926086, + 2.912363, + 2.924906, + 2.921537, + 2.914408, + 2.91729, + 2.920242, + 2.930738, + 2.914402, + 2.912769, + 2.915508, + 2.929947, + 2.920277, + 2.913803, + 2.920293, + 2.920097, + 2.911819, + 2.917103, + 2.910248, + 2.917429, + 2.920409, + 2.914253, + 2.935603, + 2.926291, + 2.916724, + 2.914045, + 2.919926, + 2.924564, + 2.923107, + 2.911983, + 2.921756, + 2.925279, + 2.915186, + 2.920061, + 2.921104, + 2.927698, + 2.921847, + 2.926546, + 2.927302, + 2.923345, + 2.924543, + 2.923514, + 2.92327, + 2.925357, + 2.933725, + 2.91535, + 2.924558, + 2.931079, + 2.913175, + 2.916685, + 2.923938, + 2.92037, + 2.922082, + 2.918392, + 2.917774, + 2.924392, + 2.921757, + 2.912094, + 2.925491, + 2.929644, + 2.924628, + 2.917011, + 2.919392, + 2.923989, + 2.915765, + 2.922881, + 2.921231, + 2.920364, + 2.929952, + 2.915443, + 2.917166, + 2.931439, + 2.914146, + 2.93145, + 2.929473, + 2.915639, + 2.920716, + 2.915528, + 2.915235, + 2.927329, + 2.915909, + 2.917001, + 2.921745, + 2.922553, + 2.921398, + 2.913141, + 2.926417, + 2.921996, + 2.930369, + 2.916663, + 2.937301, + 2.93877, + 2.930351, + 2.932031, + 2.934815, + 2.945068, + 2.932546, + 2.932343, + 2.930175 + ], + "client_rtt_ms": [ + 2.956105, + 2.953068, + 2.949844, + 2.956479, + 2.949996, + 2.943335, + 2.949379, + 2.952071, + 2.959701, + 2.944016, + 2.942706, + 2.954158, + 2.960082, + 2.950522, + 2.9428, + 2.948749, + 2.948339, + 2.941706, + 2.947552, + 2.94809, + 2.9481, + 2.948252, + 2.942191, + 2.965211, + 2.95842, + 2.945733, + 2.943398, + 2.947813, + 2.967947, + 2.950002, + 2.941367, + 2.949568, + 2.953141, + 2.942852, + 2.946354, + 2.948501, + 2.96555, + 2.950807, + 2.95286, + 2.965163, + 2.950589, + 2.951529, + 2.950379, + 2.951436, + 2.952237, + 2.970608, + 2.941722, + 2.951349, + 2.958725, + 2.940366, + 2.943776, + 2.95241, + 2.946207, + 2.954558, + 2.954519, + 2.944084, + 2.953608, + 2.949203, + 2.938148, + 2.953879, + 2.956203, + 2.952234, + 2.957663, + 2.94748, + 2.949899, + 2.943609, + 2.951633, + 2.947874, + 2.946829, + 2.95807, + 2.941872, + 2.952417, + 2.960316, + 2.941743, + 2.958107, + 2.956813, + 2.943435, + 2.948382, + 2.943908, + 2.954852, + 2.955237, + 2.942592, + 2.946715, + 2.948809, + 2.949243, + 2.948455, + 2.939999, + 2.953041, + 2.95978, + 2.957884, + 2.943275, + 2.963983, + 2.966907, + 2.957941, + 3.053352, + 2.983246, + 3.024019, + 2.963312, + 2.96111, + 2.957494 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.881683, + 2.882965, + 2.891982, + 2.878097, + 2.877773, + 2.878383, + 2.873051, + 2.871927, + 2.871963, + 2.867865, + 2.874024, + 2.873128, + 2.885736, + 2.878646, + 2.870812, + 2.872798, + 2.889028, + 2.879126, + 2.869161, + 2.875738, + 2.875735, + 2.871111, + 2.88777, + 2.869887, + 2.874987, + 2.873548, + 2.869194, + 2.868134, + 2.869272, + 2.868517, + 2.868871, + 2.873665, + 2.875883, + 2.867261, + 2.869588, + 2.865596, + 2.87683, + 2.870865, + 2.875431, + 2.869379, + 2.872231, + 2.866429, + 2.868471, + 2.867617, + 2.872888, + 2.876349, + 2.869645, + 2.865984, + 2.877966, + 2.87874, + 2.873646, + 2.872187, + 2.882962, + 2.873719, + 2.866431, + 2.870555, + 2.877007, + 2.869199, + 2.876024, + 2.873936, + 2.878812, + 2.872512, + 2.877117, + 2.877019, + 2.874412, + 2.876907, + 2.869332, + 2.875417, + 2.877639, + 2.872549, + 2.867666, + 2.871303, + 2.884266, + 2.866323, + 2.866581, + 2.871595, + 2.872175, + 2.865263, + 2.872927, + 2.871852, + 2.875926, + 2.869376, + 2.880555, + 2.872146, + 2.880665, + 2.86833, + 2.879993, + 2.874391, + 2.875452, + 2.877225, + 2.86907, + 2.8653, + 2.88303, + 2.8725, + 2.870912, + 2.867394, + 2.877413, + 2.872772, + 2.866143, + 2.872324 + ], + "client_rtt_ms": [ + 2.917222, + 2.908734, + 2.918416, + 2.90597, + 2.902405, + 2.904245, + 2.901236, + 2.897414, + 2.896695, + 2.892314, + 2.897756, + 2.898269, + 2.918857, + 2.908195, + 2.897307, + 2.897634, + 2.913716, + 2.904454, + 2.893714, + 2.90093, + 2.903324, + 2.895497, + 2.9127, + 2.896327, + 2.90789, + 2.903964, + 2.894611, + 2.893559, + 2.892771, + 2.893212, + 2.893111, + 2.898618, + 2.902051, + 2.891789, + 2.894727, + 2.891987, + 2.913828, + 2.896202, + 2.899426, + 2.893615, + 2.896252, + 2.889791, + 2.894081, + 2.892543, + 2.899554, + 2.904877, + 2.894301, + 2.926175, + 2.913048, + 2.930425, + 2.901081, + 2.898216, + 2.908906, + 2.900579, + 2.894555, + 2.897806, + 2.902994, + 2.895952, + 2.902018, + 2.899161, + 2.903363, + 2.904053, + 2.901903, + 2.902633, + 2.899279, + 2.902412, + 2.894805, + 2.900422, + 2.901711, + 2.896982, + 2.893994, + 2.896294, + 2.909118, + 2.898668, + 2.896299, + 2.8991, + 2.898792, + 2.892011, + 2.899039, + 2.896873, + 2.900229, + 2.896321, + 2.908609, + 2.897488, + 2.90599, + 2.896995, + 2.916565, + 2.900314, + 2.90016, + 2.902335, + 2.895777, + 2.891081, + 2.907769, + 2.900186, + 2.896444, + 2.892442, + 2.902807, + 2.897915, + 2.899181, + 2.895955 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 3.210629, + 3.221605, + 3.238933, + 3.220654, + 3.210649, + 3.21747, + 3.234695, + 3.218132, + 3.222886, + 3.22641, + 3.205972, + 3.213611, + 3.218612, + 3.228588, + 3.208332, + 3.209417, + 3.224821, + 3.209306, + 3.218872, + 3.232124, + 3.255058, + 3.254485, + 3.235816, + 3.219538, + 3.228672, + 3.231908, + 3.209663, + 3.213806, + 3.208296, + 3.226318, + 3.217544, + 3.212347, + 3.223012, + 3.224574, + 3.210024, + 3.215375, + 3.224747, + 3.23164, + 3.221017, + 3.214538, + 3.223176, + 3.220234, + 3.213227, + 3.212158, + 3.218905, + 3.217248, + 3.211823, + 3.200975, + 3.206852, + 3.209297, + 3.208441, + 3.213809, + 3.202258, + 3.216734, + 3.19977, + 3.194982, + 3.206597, + 3.203185, + 3.200295, + 3.203421, + 3.205302, + 3.216249, + 3.20994, + 3.1993, + 3.20156, + 3.20049, + 3.185368, + 3.192627, + 3.195587, + 3.20237, + 3.190322, + 3.195507, + 3.193618, + 3.20368, + 3.199339, + 3.203681, + 3.217306, + 3.213582, + 3.197946, + 3.19406, + 3.200983, + 3.215025, + 3.195354, + 3.21577, + 3.217512, + 3.221141, + 3.20695, + 3.200498, + 3.200501, + 3.207547, + 3.201413, + 3.197125, + 3.201084, + 3.218278, + 3.198531, + 3.196828, + 3.18492, + 3.193933, + 3.182316, + 3.19348 + ], + "client_rtt_ms": [ + 3.238899, + 3.249637, + 3.27437, + 3.251015, + 3.237396, + 3.24476, + 3.261608, + 3.24568, + 3.251079, + 3.254863, + 3.235918, + 3.241153, + 3.248485, + 3.257163, + 3.246954, + 3.237088, + 3.250853, + 3.237477, + 3.24756, + 3.25935, + 3.282781, + 3.282906, + 3.263816, + 3.247454, + 3.258279, + 3.26007, + 3.237006, + 3.248951, + 3.234475, + 3.253566, + 3.244476, + 3.239235, + 3.251534, + 3.255224, + 3.237058, + 3.243817, + 3.250425, + 3.259155, + 3.248645, + 3.252173, + 3.251193, + 3.249198, + 3.240697, + 3.240651, + 3.245235, + 3.244909, + 3.239123, + 3.22795, + 3.23385, + 3.237065, + 3.235517, + 3.247936, + 3.230167, + 3.244324, + 3.226981, + 3.221581, + 3.234768, + 3.230758, + 3.22864, + 3.230295, + 3.231986, + 3.243254, + 3.236433, + 3.235196, + 3.228728, + 3.228233, + 3.213826, + 3.21917, + 3.222638, + 3.228223, + 3.216524, + 3.222227, + 3.222485, + 3.234767, + 3.22699, + 3.23221, + 3.258351, + 3.241139, + 3.225086, + 3.222435, + 3.228464, + 3.242663, + 3.224763, + 3.244088, + 3.245732, + 3.248425, + 3.233267, + 3.227367, + 3.236026, + 3.234498, + 3.228185, + 3.22368, + 3.228275, + 3.246275, + 3.225501, + 3.223681, + 3.212594, + 3.219248, + 3.20925, + 3.220188 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 4.390681, + 4.36554, + 4.375111, + 5.832084, + 4.425031, + 4.417521, + 4.399347, + 4.404486, + 4.429759, + 4.425232, + 4.406907, + 4.40248, + 4.430885, + 4.418262, + 4.389455, + 4.396673, + 4.39837, + 4.388975, + 4.404633, + 4.391917, + 4.392944, + 4.52315, + 4.387222, + 4.393848, + 4.405094, + 4.39155, + 4.383151, + 4.389867, + 4.384207, + 4.361037, + 4.372522, + 4.370279, + 4.402319, + 4.378456, + 4.378944, + 4.391993, + 4.39133, + 4.377002, + 4.37581, + 4.36653, + 4.39158, + 4.379032, + 4.374953, + 4.385416, + 4.402872, + 4.416753, + 4.394426, + 4.375732, + 4.373504, + 4.357239, + 4.38058, + 4.387882, + 4.388967, + 4.399785, + 4.394014, + 4.382755, + 4.38607, + 4.355256, + 4.368181, + 4.370874, + 4.382878, + 4.371077, + 4.387238, + 4.37916, + 4.37979, + 4.377824, + 4.371643, + 4.366604, + 4.394404, + 4.416067, + 4.39421, + 4.378857, + 4.396456, + 4.401691, + 4.387546, + 4.379758, + 4.394166, + 4.387476, + 4.388764, + 4.377266, + 4.374376, + 4.395993, + 4.37856, + 4.403119, + 4.389639, + 4.387474, + 4.382727, + 4.382402, + 4.403334, + 4.393666, + 4.380819, + 4.380474, + 4.423149, + 4.439926, + 4.39449, + 4.378362, + 4.407143, + 4.391908, + 4.383767, + 4.405904 + ], + "client_rtt_ms": [ + 4.428235, + 4.399524, + 4.408231, + 5.866292, + 4.461015, + 4.459255, + 4.434042, + 4.438807, + 4.465021, + 4.459321, + 4.439444, + 4.438163, + 4.469298, + 4.452093, + 4.422798, + 4.432513, + 4.432767, + 4.434484, + 4.437308, + 4.425378, + 4.426677, + 4.562921, + 4.421548, + 4.42839, + 4.441438, + 4.425709, + 4.417366, + 4.42229, + 4.418574, + 4.404415, + 4.407619, + 4.404566, + 4.435993, + 4.413169, + 4.419157, + 4.427327, + 4.427811, + 4.414092, + 4.410011, + 4.403201, + 4.427809, + 4.420349, + 4.409224, + 4.420445, + 4.438926, + 4.451489, + 4.42953, + 4.409918, + 4.40784, + 4.389299, + 4.41412, + 4.420563, + 4.4214, + 4.442074, + 4.42825, + 4.415659, + 4.419572, + 4.389239, + 4.401373, + 4.403927, + 4.416665, + 4.403994, + 4.421837, + 4.412905, + 4.413107, + 4.407195, + 4.414237, + 4.399524, + 4.428153, + 4.451013, + 4.42751, + 4.413598, + 4.430331, + 4.43555, + 4.421065, + 4.413254, + 4.42702, + 4.422387, + 4.430962, + 4.412094, + 4.406901, + 4.429682, + 4.412764, + 4.436764, + 4.422936, + 4.421122, + 4.416397, + 4.416409, + 4.436636, + 4.427336, + 4.422396, + 4.415699, + 4.457933, + 4.475021, + 4.428346, + 4.4113, + 4.441894, + 4.424447, + 4.417096, + 4.440429 + ] + } + } + }, + { + "label": "round2-initial-graph", + "raw_file_sha256": "dac5592d99c4074bb48210742d4ba56fe013f992eb52630aa584f37a718fca56", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "a95ee8e50065f2e39d8a6c8ced32e8ff434dd42903bd741040ea9205da79813e", + "mode": "graph", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.557207, + 2.558858, + 2.560476, + 2.557146, + 2.554291, + 2.54713, + 2.551542, + 2.548308, + 2.544152, + 2.544778, + 2.537784, + 2.553784, + 2.548959, + 2.557056, + 2.538551, + 2.547105, + 2.543638, + 2.552688, + 2.551335, + 2.553212, + 2.552011, + 2.541251, + 2.543831, + 2.538044, + 2.545031, + 2.541223, + 2.542907, + 2.553165, + 2.540588, + 2.550141, + 2.543769, + 2.546569, + 2.544856, + 2.540173, + 2.543676, + 2.553724, + 2.551139, + 2.548111, + 2.546916, + 2.547955, + 2.546877, + 2.541819, + 2.542584, + 2.544324, + 2.538764, + 2.544045, + 2.542224, + 2.547262, + 2.546142, + 2.542927, + 2.544854, + 2.5506, + 2.553362, + 2.540882, + 2.540387, + 2.543823, + 2.540343, + 2.544999, + 2.539705, + 2.545073, + 2.544987, + 2.545036, + 2.540808, + 2.539839, + 2.543676, + 2.551907, + 2.547314, + 2.548446, + 2.542811, + 2.543694, + 2.54238, + 2.555271, + 2.543827, + 2.543383, + 2.549589, + 2.546093, + 2.550455, + 2.543825, + 2.546578, + 2.552308, + 2.583426, + 2.554102, + 2.538507, + 2.536279, + 2.535737, + 2.533366, + 2.531717, + 2.533759, + 2.535108, + 2.538492, + 2.539343, + 2.536639, + 2.538792, + 2.534994, + 2.537484, + 2.527867, + 2.531191, + 2.533836, + 2.532364, + 2.533016 + ], + "client_rtt_ms": [ + 2.58371, + 2.585791, + 2.58747, + 2.592084, + 2.583464, + 2.572471, + 2.580431, + 2.572615, + 2.570206, + 2.572196, + 2.564626, + 2.579506, + 2.576683, + 2.590547, + 2.572068, + 2.574004, + 2.571401, + 2.579159, + 2.581038, + 2.577703, + 2.58217, + 2.565942, + 2.568583, + 2.566275, + 2.580678, + 2.568284, + 2.569163, + 2.579157, + 2.564709, + 2.576299, + 2.567844, + 2.570862, + 2.572409, + 2.567952, + 2.578824, + 2.583114, + 2.575891, + 2.575186, + 2.57092, + 2.576054, + 2.5725, + 2.567688, + 2.567318, + 2.570102, + 2.569786, + 2.569759, + 2.5678, + 2.5725, + 2.572234, + 2.569111, + 2.570713, + 2.577691, + 2.580356, + 2.565818, + 2.56938, + 2.57783, + 2.564841, + 2.571489, + 2.566282, + 2.571059, + 2.570636, + 2.567967, + 2.568557, + 2.563715, + 2.568658, + 2.586674, + 2.575717, + 2.573384, + 2.570474, + 2.569945, + 2.568225, + 2.581917, + 2.569665, + 2.569789, + 2.577687, + 2.580675, + 2.578411, + 2.572864, + 2.571341, + 2.578906, + 2.607874, + 2.581601, + 2.565695, + 2.563189, + 2.559671, + 2.568203, + 2.558151, + 2.558184, + 2.561447, + 2.56651, + 2.567721, + 2.564333, + 2.563529, + 2.563214, + 2.564883, + 2.552599, + 2.569665, + 2.564712, + 2.557712, + 2.558556 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 2.579994, + 2.581508, + 2.580304, + 2.579264, + 2.575548, + 2.58767, + 2.579732, + 2.575613, + 2.585777, + 2.588639, + 2.582945, + 2.585566, + 2.582715, + 2.58021, + 2.580761, + 2.582104, + 2.574698, + 2.582534, + 2.581946, + 2.576806, + 2.581295, + 2.582346, + 2.577877, + 2.581303, + 2.575753, + 2.573212, + 2.581491, + 2.582309, + 2.579212, + 2.581162, + 2.576983, + 2.576093, + 2.580465, + 2.582994, + 2.582315, + 2.577115, + 2.572656, + 2.580176, + 2.57641, + 2.572029, + 2.573057, + 2.578675, + 2.577457, + 2.577405, + 2.582318, + 2.579466, + 2.573158, + 2.578153, + 2.578121, + 2.581739, + 2.580582, + 2.571398, + 2.569348, + 2.574888, + 2.571057, + 2.572595, + 2.582328, + 2.578772, + 2.578226, + 2.578692, + 2.576811, + 2.578368, + 2.574986, + 2.581546, + 2.579141, + 2.580084, + 2.577148, + 2.584704, + 2.574556, + 2.575649, + 2.580206, + 2.578671, + 2.574631, + 2.577914, + 2.577972, + 2.580916, + 2.572906, + 2.575794, + 2.574021, + 2.584197, + 2.573527, + 2.581776, + 2.581391, + 2.576019, + 2.57517, + 2.573077, + 2.575653, + 2.577036, + 2.588232, + 2.581856, + 2.586941, + 2.59028, + 2.583804, + 2.589728, + 2.585665, + 2.586975, + 2.589119, + 2.588854, + 2.580261, + 2.588448 + ], + "client_rtt_ms": [ + 2.605776, + 2.607605, + 2.616394, + 2.608033, + 2.599751, + 2.613827, + 2.606074, + 2.603707, + 2.613905, + 2.616979, + 2.612011, + 2.620203, + 2.611234, + 2.607555, + 2.608703, + 2.606895, + 2.600141, + 2.610629, + 2.608564, + 2.609855, + 2.612305, + 2.60976, + 2.603195, + 2.610204, + 2.601176, + 2.600556, + 2.611508, + 2.610331, + 2.611563, + 2.609134, + 2.605549, + 2.600633, + 2.609052, + 2.611071, + 2.609418, + 2.604546, + 2.60503, + 2.606813, + 2.603176, + 2.599442, + 2.598779, + 2.605338, + 2.601585, + 2.605883, + 2.611965, + 2.612197, + 2.600099, + 2.605487, + 2.603455, + 2.610571, + 2.607486, + 2.596369, + 2.594381, + 2.605339, + 2.603505, + 2.599734, + 2.609901, + 2.604918, + 2.603879, + 2.608102, + 2.601083, + 2.604645, + 2.608413, + 2.609114, + 2.607871, + 2.60506, + 2.604402, + 2.6107, + 2.60316, + 2.605554, + 2.606829, + 2.6103, + 2.604246, + 2.607309, + 2.602565, + 2.607512, + 2.601624, + 2.600936, + 2.60032, + 2.622947, + 2.599897, + 2.609906, + 2.611165, + 2.602579, + 2.601805, + 2.599937, + 2.601079, + 2.60729, + 2.622562, + 2.607171, + 2.612607, + 2.616734, + 2.610628, + 2.616509, + 2.61263, + 2.614143, + 2.621459, + 2.621717, + 2.60287, + 2.618727 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 2.560453, + 2.553285, + 2.537725, + 2.555872, + 2.540102, + 2.543508, + 2.54983, + 2.544428, + 2.542322, + 2.544638, + 2.540197, + 2.540719, + 2.537873, + 2.546569, + 2.540866, + 2.541484, + 2.540342, + 2.541901, + 2.540064, + 2.537706, + 2.542082, + 2.55236, + 2.547675, + 2.542816, + 2.542266, + 2.540063, + 2.540078, + 2.537534, + 2.537712, + 2.541189, + 2.537985, + 2.546399, + 2.53908, + 2.548995, + 2.538998, + 2.543073, + 2.542632, + 2.541999, + 2.537572, + 2.537596, + 2.535871, + 2.534967, + 2.540221, + 2.539776, + 2.539521, + 2.543776, + 2.535774, + 2.534881, + 2.536378, + 2.544574, + 2.530836, + 2.537744, + 2.547657, + 2.555068, + 2.54229, + 2.544278, + 2.535016, + 2.54152, + 2.549285, + 2.536904, + 2.541036, + 2.547616, + 2.538919, + 2.535044, + 2.53751, + 2.546206, + 2.537256, + 2.53785, + 2.534956, + 2.545398, + 2.542995, + 2.545386, + 2.543107, + 2.548021, + 2.532115, + 2.543418, + 2.540073, + 2.538409, + 2.537166, + 2.535493, + 2.538303, + 2.542871, + 2.539985, + 2.548176, + 2.540804, + 2.540142, + 2.538373, + 2.538038, + 2.544602, + 2.548684, + 2.544674, + 2.540573, + 2.543441, + 2.546825, + 2.544428, + 2.542976, + 2.547643, + 2.550058, + 2.545198, + 2.544024 + ], + "client_rtt_ms": [ + 2.595829, + 2.578507, + 2.564188, + 2.582466, + 2.564414, + 2.569175, + 2.573207, + 2.569485, + 2.569858, + 2.568707, + 2.563947, + 2.566722, + 2.569834, + 2.573034, + 2.567326, + 2.566103, + 2.56823, + 2.569325, + 2.563096, + 2.564132, + 2.566414, + 2.580736, + 2.57385, + 2.567399, + 2.575647, + 2.564634, + 2.562973, + 2.561782, + 2.562168, + 2.567018, + 2.564838, + 2.572934, + 2.564883, + 2.575928, + 2.565838, + 2.567305, + 2.57545, + 2.565291, + 2.562241, + 2.561991, + 2.559423, + 2.559031, + 2.564917, + 2.563784, + 2.566098, + 2.570674, + 2.558763, + 2.560525, + 2.564337, + 2.575108, + 2.557156, + 2.563159, + 2.572192, + 2.580083, + 2.56576, + 2.570123, + 2.55897, + 2.565468, + 2.574282, + 2.562603, + 2.565078, + 2.578327, + 2.564301, + 2.557772, + 2.563776, + 2.569385, + 2.561995, + 2.565225, + 2.558251, + 2.570836, + 2.568497, + 2.569192, + 2.569203, + 2.580959, + 2.556627, + 2.56936, + 2.564165, + 2.56164, + 2.56211, + 2.561692, + 2.561097, + 2.569323, + 2.566179, + 2.575353, + 2.568386, + 2.563967, + 2.570028, + 2.563801, + 2.568793, + 2.57751, + 2.570948, + 2.565566, + 2.56961, + 2.571472, + 2.569419, + 2.568929, + 2.573634, + 2.57819, + 2.579995, + 2.567816 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 2.885429, + 2.879338, + 2.874963, + 2.872101, + 2.886192, + 2.887848, + 2.884999, + 2.888785, + 2.884451, + 2.875102, + 2.875578, + 2.881036, + 2.892072, + 2.886471, + 2.880118, + 2.871784, + 2.870469, + 2.865461, + 2.864158, + 2.885636, + 2.902896, + 2.896453, + 2.877752, + 2.87611, + 2.876684, + 2.886897, + 2.889404, + 2.88345, + 2.871678, + 2.865857, + 2.868339, + 2.876003, + 2.873424, + 2.871246, + 2.878801, + 2.871867, + 2.857427, + 2.86874, + 2.870837, + 2.88661, + 2.893269, + 2.884161, + 2.885678, + 2.875823, + 2.887888, + 2.879647, + 2.87654, + 2.888338, + 2.891644, + 2.877337, + 2.87276, + 2.870217, + 2.866205, + 2.866814, + 2.865838, + 2.861855, + 2.863961, + 2.862788, + 2.875519, + 2.875184, + 2.885257, + 2.872112, + 2.880706, + 2.863661, + 2.867089, + 2.861824, + 2.86528, + 2.862988, + 2.868178, + 2.868532, + 2.881279, + 2.883653, + 2.871162, + 2.86606, + 2.876581, + 2.881411, + 2.859392, + 2.862168, + 2.874462, + 2.879509, + 2.872608, + 2.881199, + 2.882445, + 2.89113, + 2.877473, + 2.881051, + 2.870591, + 2.872126, + 2.867493, + 2.86617, + 2.882617, + 2.863459, + 2.87331, + 2.86196, + 2.861065, + 2.874041, + 2.881453, + 2.875644, + 2.867856, + 2.864417 + ], + "client_rtt_ms": [ + 2.913709, + 2.907654, + 2.91061, + 2.897942, + 2.914703, + 2.916286, + 2.915574, + 2.916745, + 2.913089, + 2.904095, + 2.902668, + 2.911877, + 2.920403, + 2.914018, + 2.926376, + 2.899361, + 2.900009, + 2.892891, + 2.891287, + 2.913873, + 2.930567, + 2.923466, + 2.902942, + 2.905839, + 2.904426, + 2.914927, + 2.917497, + 2.920261, + 2.897777, + 2.89081, + 2.894986, + 2.902593, + 2.900095, + 2.897767, + 2.905969, + 2.900014, + 2.883122, + 2.894938, + 2.898441, + 2.92434, + 2.921362, + 2.913237, + 2.914309, + 2.904697, + 2.914655, + 2.906162, + 2.905344, + 2.914916, + 2.919829, + 2.905393, + 2.900183, + 2.904334, + 2.89329, + 2.894395, + 2.895431, + 2.887316, + 2.889493, + 2.892415, + 2.906954, + 2.901214, + 2.912996, + 2.900407, + 2.906717, + 2.899331, + 2.894221, + 2.889753, + 2.889964, + 2.890429, + 2.895372, + 2.894518, + 2.908626, + 2.910565, + 2.898034, + 2.893635, + 2.902941, + 2.908202, + 2.894193, + 2.88739, + 2.903709, + 2.910207, + 2.899512, + 2.909335, + 2.908778, + 2.918455, + 2.903031, + 2.908112, + 2.897516, + 2.901102, + 2.900531, + 2.893039, + 2.909958, + 2.89256, + 2.901779, + 2.890675, + 2.889214, + 2.900508, + 2.910471, + 2.906824, + 2.895095, + 2.889676 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.984445, + 3.998448, + 3.973286, + 3.980156, + 3.984375, + 3.9974, + 3.995228, + 3.96403, + 3.967406, + 3.959644, + 3.988939, + 3.962955, + 3.963234, + 3.952717, + 3.954501, + 3.987489, + 3.990963, + 3.96269, + 3.962952, + 3.966031, + 3.976165, + 3.99368, + 3.977669, + 3.967529, + 3.964526, + 3.96344, + 3.971128, + 3.973598, + 3.969639, + 3.991053, + 3.96006, + 3.968936, + 3.936016, + 3.961385, + 3.994937, + 3.98986, + 3.963602, + 3.954749, + 3.974934, + 3.999095, + 3.97973, + 4.005369, + 3.963678, + 3.967499, + 3.987706, + 4.012378, + 4.009435, + 3.982697, + 5.307759, + 4.176678, + 4.049272, + 4.034918, + 4.022439, + 4.018898, + 3.992314, + 3.988382, + 3.996805, + 3.991291, + 3.990206, + 3.979906, + 4.01247, + 4.010857, + 4.023781, + 3.992032, + 3.996439, + 4.010484, + 4.015797, + 3.990083, + 4.108807, + 4.004739, + 4.04889, + 4.016598, + 3.971731, + 3.960463, + 3.968821, + 3.996138, + 4.013994, + 3.995721, + 3.972405, + 3.964624, + 3.973677, + 3.97391, + 3.99298, + 3.995503, + 3.965387, + 3.961278, + 3.987607, + 3.963335, + 3.98195, + 3.965921, + 3.956242, + 3.966582, + 3.97734, + 3.971118, + 3.966044, + 3.965975, + 3.981478, + 3.964061, + 3.955197, + 3.986214 + ], + "client_rtt_ms": [ + 4.023332, + 4.033241, + 4.008453, + 4.013764, + 4.018472, + 4.046583, + 4.030511, + 3.998805, + 4.000773, + 3.992747, + 4.021891, + 3.996766, + 3.998086, + 3.987552, + 3.992972, + 4.023766, + 4.025014, + 4.003296, + 3.996377, + 3.998258, + 4.008887, + 4.026403, + 4.010679, + 4.001734, + 3.999129, + 3.998207, + 4.004111, + 4.006113, + 4.00395, + 4.033764, + 3.994501, + 4.002516, + 3.969822, + 3.994793, + 4.028228, + 4.024706, + 3.996471, + 3.986891, + 4.009188, + 4.033217, + 4.015504, + 4.047785, + 4.000425, + 4.003225, + 4.021351, + 4.047528, + 4.044604, + 4.019613, + 5.342842, + 4.215755, + 4.084112, + 4.070805, + 4.059356, + 4.061049, + 4.025654, + 4.020781, + 4.029272, + 4.02657, + 4.024044, + 4.012761, + 4.047585, + 4.044812, + 4.057377, + 4.025429, + 4.031742, + 4.044316, + 4.059181, + 4.02294, + 4.141569, + 4.04226, + 4.083982, + 4.052385, + 4.005601, + 3.992809, + 4.002001, + 4.031037, + 4.046658, + 4.029983, + 4.011211, + 3.996795, + 4.005864, + 4.007504, + 4.026954, + 4.028838, + 4.000405, + 3.996636, + 4.021065, + 3.995999, + 4.015578, + 3.999088, + 3.998317, + 3.999309, + 4.009587, + 4.004091, + 3.998084, + 4.001084, + 4.015459, + 3.997733, + 3.989462, + 4.020674 + ] + } + } + }, + { + "label": "round2-retained-eager", + "raw_file_sha256": "28b35208c86e7687d44777b27ba0bfc6a9f416965f50425d6888441c313f381c", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "5fa7ccd47087a40822dcab78b2b80deea1bb42cb54463376e24aa7701b543078", + "mode": "eager", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.909941, + 1.897464, + 1.909596, + 1.89823, + 1.910093, + 1.90016, + 1.90668, + 1.900111, + 1.915764, + 1.906427, + 1.904131, + 1.896291, + 1.910947, + 1.90023, + 1.90648, + 1.901149, + 1.901923, + 1.892933, + 1.903205, + 1.900191, + 1.902281, + 1.892662, + 1.890344, + 1.900143, + 1.895858, + 1.897848, + 1.885698, + 1.894049, + 1.902034, + 1.903429, + 1.888517, + 1.892162, + 1.903269, + 1.890866, + 1.891896, + 1.890154, + 1.905239, + 1.898815, + 1.886048, + 1.899216, + 1.895138, + 1.899986, + 1.886189, + 1.893839, + 1.898739, + 1.89038, + 1.882654, + 1.895811, + 1.898617, + 1.892789, + 1.894441, + 1.901633, + 1.906865, + 1.905299, + 1.894208, + 1.895646, + 1.908165, + 1.889681, + 1.892017, + 1.886639, + 1.929864, + 1.9239, + 1.895833, + 1.898072, + 1.90094, + 1.888549, + 1.896359, + 1.896918, + 1.902172, + 1.887217, + 1.89714, + 1.891831, + 1.88895, + 1.879531, + 1.879538, + 1.885587, + 1.875418, + 1.868551, + 1.869941, + 1.879923, + 1.879882, + 1.875791, + 1.874472, + 1.887463, + 1.884431, + 1.874705, + 1.878995, + 1.880608, + 1.88314, + 1.871733, + 1.873092, + 1.873042, + 1.888632, + 1.882896, + 1.872217, + 1.876674, + 1.881874, + 1.879806, + 1.878569, + 1.875051 + ], + "client_rtt_ms": [ + 1.937446, + 1.923086, + 1.937524, + 1.933368, + 1.941073, + 1.926167, + 1.934456, + 1.925605, + 1.947069, + 1.933691, + 1.932223, + 1.924237, + 1.941807, + 1.933392, + 1.933025, + 1.926182, + 1.930886, + 1.918505, + 1.929142, + 1.926612, + 1.937151, + 1.918024, + 1.915302, + 1.929444, + 1.934403, + 1.9245, + 1.910878, + 1.922904, + 1.928455, + 1.933074, + 1.914913, + 1.919449, + 1.930773, + 1.918312, + 1.92744, + 1.919701, + 1.930096, + 1.925123, + 1.911639, + 1.927948, + 1.920314, + 1.927265, + 1.911797, + 1.922535, + 1.931164, + 1.917466, + 1.908331, + 1.924492, + 1.92469, + 1.919865, + 1.923528, + 1.930153, + 1.933277, + 1.938267, + 1.920503, + 1.927559, + 1.932074, + 1.913891, + 1.919785, + 1.912778, + 1.956341, + 1.948391, + 1.923051, + 1.919946, + 1.925548, + 1.921662, + 1.923138, + 1.921309, + 1.927418, + 1.914162, + 1.925859, + 1.918432, + 1.917121, + 1.905794, + 1.908792, + 1.921751, + 1.90165, + 1.894366, + 1.895396, + 1.906793, + 1.907404, + 1.904989, + 1.900847, + 1.913208, + 1.908817, + 1.909637, + 1.904778, + 1.909023, + 1.908447, + 1.900842, + 1.899101, + 1.899211, + 1.913577, + 1.91071, + 1.897665, + 1.90182, + 1.918763, + 1.911036, + 1.90493, + 1.902774 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.908051, + 1.899298, + 1.913721, + 1.905573, + 1.922475, + 1.903395, + 1.911594, + 1.907374, + 1.916489, + 1.90375, + 1.903662, + 1.908278, + 1.898889, + 1.906627, + 1.904957, + 1.902673, + 1.916068, + 1.902831, + 1.905567, + 1.905333, + 1.916428, + 1.933986, + 1.91623, + 1.902333, + 1.910147, + 1.899066, + 1.910016, + 1.89965, + 1.9148, + 1.903223, + 1.909671, + 1.908792, + 1.918341, + 1.902238, + 1.907833, + 1.90063, + 1.91842, + 1.898627, + 1.902086, + 1.901304, + 1.921284, + 1.906119, + 1.902377, + 1.901883, + 1.910157, + 1.899667, + 1.902544, + 1.898763, + 1.908758, + 1.901581, + 1.91011, + 1.900029, + 1.915964, + 1.90454, + 1.903655, + 1.896057, + 1.908173, + 1.89827, + 1.909266, + 1.90275, + 1.907256, + 1.896561, + 1.902109, + 1.901624, + 1.910133, + 1.895572, + 1.908605, + 1.908691, + 1.910769, + 1.899434, + 1.910247, + 1.905759, + 1.911114, + 1.897785, + 1.917783, + 1.911968, + 1.907429, + 1.913923, + 1.910542, + 1.89439, + 1.906424, + 1.902521, + 1.904743, + 1.903953, + 1.911547, + 1.903858, + 1.904361, + 1.899065, + 1.922617, + 1.903991, + 1.91532, + 1.915213, + 1.917527, + 1.903815, + 1.909581, + 1.906853, + 1.923715, + 1.910569, + 1.908434, + 1.907472 + ], + "client_rtt_ms": [ + 1.932748, + 1.928385, + 1.948844, + 1.940075, + 1.948102, + 1.934505, + 1.937507, + 1.935007, + 1.940977, + 1.931796, + 1.930253, + 1.941997, + 1.924925, + 1.938259, + 1.931396, + 1.929122, + 1.942344, + 1.930042, + 1.930703, + 1.93847, + 1.946018, + 1.961221, + 1.942028, + 1.929727, + 1.939392, + 1.927368, + 1.938357, + 1.927161, + 1.948425, + 1.930773, + 1.93631, + 1.937857, + 1.94416, + 1.935135, + 1.933526, + 1.925868, + 1.956896, + 1.924439, + 1.927885, + 1.931403, + 1.946984, + 1.931226, + 1.927782, + 1.930367, + 1.936107, + 1.931405, + 1.929479, + 1.925268, + 1.935207, + 1.928831, + 1.938329, + 1.926807, + 1.941754, + 1.935956, + 1.939056, + 1.92211, + 1.939997, + 1.924425, + 1.938604, + 1.93083, + 1.936916, + 1.922811, + 1.938911, + 1.928311, + 1.936495, + 1.92254, + 1.939383, + 1.935865, + 1.939967, + 1.928402, + 1.938542, + 1.938412, + 1.939822, + 1.923085, + 1.943585, + 1.940393, + 1.932964, + 1.942214, + 1.938556, + 1.931191, + 1.934098, + 1.93174, + 1.933161, + 1.930856, + 1.937674, + 1.932559, + 1.93065, + 1.926628, + 1.960072, + 1.93283, + 1.942879, + 1.941995, + 1.943973, + 1.930456, + 1.934567, + 1.936978, + 1.95741, + 1.940202, + 1.934274, + 1.935979 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.894093, + 1.894179, + 1.881873, + 1.889342, + 1.892853, + 1.875426, + 1.879418, + 1.883263, + 1.891419, + 1.884246, + 1.89009, + 1.87919, + 1.883526, + 1.88541, + 1.88278, + 1.888383, + 1.89155, + 1.888684, + 1.891336, + 1.883269, + 1.893512, + 1.881709, + 1.8939, + 1.884013, + 1.889948, + 1.882745, + 1.879798, + 1.881236, + 1.89435, + 1.871209, + 1.879608, + 1.888395, + 1.88357, + 1.884464, + 1.880218, + 1.876674, + 1.888243, + 1.884953, + 1.884795, + 1.883145, + 1.889299, + 1.887461, + 1.877505, + 1.87663, + 1.890833, + 1.881837, + 1.875338, + 1.885466, + 1.889942, + 1.882342, + 1.885125, + 1.880083, + 1.893258, + 1.881821, + 1.87756, + 1.882303, + 1.891229, + 1.881337, + 1.884974, + 1.883393, + 1.90074, + 1.882127, + 1.879452, + 1.877009, + 1.889893, + 1.875951, + 1.887372, + 1.879701, + 1.887081, + 1.883057, + 1.880605, + 1.890875, + 1.888241, + 1.885225, + 1.882504, + 1.882261, + 1.885417, + 1.887057, + 1.890949, + 1.880548, + 1.889187, + 1.881238, + 1.878874, + 1.882524, + 1.893649, + 1.880766, + 1.884811, + 1.877453, + 1.889189, + 1.877899, + 1.885336, + 1.877896, + 1.888247, + 1.874985, + 1.879429, + 1.879189, + 1.884557, + 1.880701, + 1.880187, + 1.882783 + ], + "client_rtt_ms": [ + 1.927236, + 1.918032, + 1.906224, + 1.913244, + 1.917684, + 1.900764, + 1.905013, + 1.908372, + 1.917433, + 1.909573, + 1.916642, + 1.904802, + 1.919418, + 1.908936, + 1.909782, + 1.911577, + 1.919095, + 1.913802, + 1.919127, + 1.907293, + 1.918908, + 1.905846, + 1.917761, + 1.90896, + 1.921434, + 1.909457, + 1.905661, + 1.908817, + 1.918691, + 1.896295, + 1.904359, + 1.913855, + 1.909391, + 1.908729, + 1.903154, + 1.903061, + 1.921588, + 1.911181, + 1.910093, + 1.909548, + 1.913533, + 1.9123, + 1.901474, + 1.904101, + 1.915006, + 1.907939, + 1.899599, + 1.911236, + 1.91718, + 1.913834, + 1.910936, + 1.903691, + 1.921905, + 1.904866, + 1.903433, + 1.907445, + 1.916824, + 1.905299, + 1.910776, + 1.908455, + 1.926718, + 1.913132, + 1.90495, + 1.900191, + 1.91463, + 1.899316, + 1.913797, + 1.90344, + 1.914758, + 1.907176, + 1.908053, + 1.91515, + 1.914429, + 1.916877, + 1.90932, + 1.90997, + 1.910952, + 1.91356, + 1.915519, + 1.904309, + 1.912724, + 1.908709, + 1.906638, + 1.921804, + 1.918099, + 1.908404, + 1.915924, + 1.905682, + 1.913162, + 1.903411, + 1.909917, + 1.903553, + 1.911577, + 1.900879, + 1.903407, + 1.906197, + 1.909431, + 1.914827, + 1.911793, + 1.912863 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 2.232557, + 2.220897, + 2.219786, + 2.251048, + 2.253567, + 2.242214, + 2.237419, + 2.251928, + 2.247392, + 2.238145, + 2.231962, + 2.232232, + 2.234655, + 2.233867, + 2.228613, + 2.234316, + 2.263245, + 2.244199, + 2.2296, + 2.266871, + 2.28307, + 2.236001, + 2.234115, + 2.231585, + 2.242911, + 2.236445, + 2.225469, + 2.219389, + 2.222705, + 2.221873, + 2.241859, + 2.222225, + 2.24029, + 2.21713, + 2.229596, + 2.22646, + 2.246608, + 2.236994, + 2.237689, + 2.246158, + 2.256176, + 2.236019, + 2.228489, + 2.235288, + 2.221247, + 2.216604, + 2.241815, + 2.235938, + 2.241099, + 2.228329, + 2.223344, + 2.234098, + 2.247298, + 2.246249, + 2.235207, + 2.230112, + 2.220957, + 2.222611, + 2.23222, + 2.234259, + 2.238948, + 2.218829, + 2.219008, + 2.216312, + 2.227922, + 2.213015, + 2.22648, + 2.230221, + 2.232522, + 2.226462, + 2.222086, + 2.227603, + 2.237747, + 2.229683, + 2.22796, + 2.239271, + 2.23202, + 2.222062, + 2.236221, + 2.227768, + 2.236892, + 2.226181, + 2.236446, + 2.253683, + 2.245832, + 2.22886, + 2.221691, + 2.245612, + 2.221925, + 2.22872, + 2.22762, + 2.216381, + 2.222977, + 2.223858, + 2.225341, + 2.224328, + 2.236478, + 2.232039, + 2.226223, + 2.226616 + ], + "client_rtt_ms": [ + 2.260131, + 2.24663, + 2.258196, + 2.280187, + 2.281226, + 2.270706, + 2.266102, + 2.280235, + 2.274422, + 2.266062, + 2.260176, + 2.259307, + 2.260447, + 2.259698, + 2.262969, + 2.26051, + 2.29288, + 2.271625, + 2.25665, + 2.297834, + 2.311634, + 2.262884, + 2.259482, + 2.259211, + 2.273286, + 2.264652, + 2.253844, + 2.252049, + 2.250408, + 2.24838, + 2.270011, + 2.248519, + 2.269206, + 2.247111, + 2.258914, + 2.254433, + 2.273258, + 2.265888, + 2.264412, + 2.28382, + 2.284801, + 2.26472, + 2.255416, + 2.261428, + 2.251016, + 2.2421, + 2.269893, + 2.265505, + 2.268242, + 2.256788, + 2.249774, + 2.269332, + 2.274694, + 2.276644, + 2.265009, + 2.256861, + 2.247684, + 2.249871, + 2.258858, + 2.26008, + 2.265176, + 2.246036, + 2.244972, + 2.25339, + 2.254196, + 2.240805, + 2.25395, + 2.25855, + 2.265991, + 2.252744, + 2.249214, + 2.254215, + 2.263942, + 2.258031, + 2.256274, + 2.265514, + 2.270112, + 2.250948, + 2.262813, + 2.255183, + 2.265058, + 2.253427, + 2.263596, + 2.282774, + 2.274406, + 2.255672, + 2.248958, + 2.272175, + 2.257678, + 2.254519, + 2.254497, + 2.250559, + 2.248174, + 2.249488, + 2.251414, + 2.253728, + 2.263368, + 2.260368, + 2.254928, + 2.252739 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.313728, + 3.320271, + 3.292763, + 3.286548, + 3.299524, + 3.321499, + 3.296034, + 3.322527, + 3.30789, + 3.299333, + 3.295816, + 3.322442, + 3.33387, + 3.309708, + 3.297945, + 3.303378, + 3.322147, + 3.333147, + 3.333091, + 3.303678, + 3.314429, + 3.324122, + 3.335527, + 3.330431, + 3.329488, + 3.300413, + 3.309925, + 3.331602, + 3.352102, + 3.329282, + 3.306308, + 3.304958, + 3.325668, + 3.287345, + 3.29714, + 3.310665, + 3.322316, + 3.303793, + 3.319004, + 3.296708, + 3.307697, + 3.325324, + 3.324495, + 3.306033, + 3.345222, + 3.358279, + 3.344793, + 3.321038, + 3.29866, + 3.31081, + 3.322202, + 3.294258, + 3.339269, + 3.331666, + 3.333942, + 3.310035, + 3.312751, + 3.305432, + 3.343403, + 3.3361, + 3.337513, + 3.312749, + 3.295365, + 3.30641, + 3.331642, + 3.323737, + 3.345591, + 3.294871, + 3.323996, + 3.34491, + 3.343196, + 3.338945, + 3.339865, + 3.299301, + 3.306432, + 3.312303, + 3.342981, + 3.313699, + 3.325725, + 3.299963, + 3.317345, + 3.311136, + 3.339133, + 3.333218, + 3.312017, + 3.287973, + 3.32087, + 3.321271, + 3.343964, + 3.314447, + 3.318815, + 3.311779, + 3.361419, + 3.347491, + 3.344676, + 3.300273, + 3.302149, + 3.299579, + 3.333692, + 3.325098 + ], + "client_rtt_ms": [ + 3.353256, + 3.355595, + 3.326103, + 3.317832, + 3.331723, + 3.359421, + 3.330023, + 3.356956, + 3.341829, + 3.332107, + 3.330446, + 3.354502, + 3.369122, + 3.344003, + 3.331179, + 3.340348, + 3.357232, + 3.374049, + 3.3703, + 3.336293, + 3.346063, + 3.356729, + 3.370988, + 3.364521, + 3.363266, + 3.333893, + 3.341828, + 3.366268, + 3.386112, + 3.370348, + 3.33887, + 3.337769, + 3.362189, + 3.319798, + 3.330281, + 3.344421, + 3.353737, + 3.344441, + 3.353009, + 3.330538, + 3.342197, + 3.367578, + 3.359364, + 3.339936, + 3.380353, + 3.393507, + 3.379503, + 3.35512, + 3.331305, + 3.342081, + 3.35563, + 3.329524, + 3.372959, + 3.373162, + 3.36856, + 3.350972, + 3.345714, + 3.338963, + 3.380929, + 3.369261, + 3.372154, + 3.348609, + 3.327554, + 3.339454, + 3.364989, + 3.3581, + 3.385423, + 3.327895, + 3.356491, + 3.378155, + 3.375255, + 3.372888, + 3.373657, + 3.334014, + 3.338062, + 3.346507, + 3.377016, + 3.34731, + 3.368441, + 3.334782, + 3.350867, + 3.343242, + 3.375999, + 3.367804, + 3.348574, + 3.32044, + 3.352817, + 3.3535, + 3.378019, + 3.350284, + 3.359251, + 3.345683, + 3.394654, + 3.379759, + 3.377925, + 3.333463, + 3.3344, + 3.331634, + 3.368256, + 3.360483 + ] + } + } + }, + { + "label": "round2-retained-graph", + "raw_file_sha256": "d30b4fda1cf2680b522bcd39192fa1f47c415828a1da231b5850ef8a317b3fbd", + "binary_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "library_sha256": "5fa7ccd47087a40822dcab78b2b80deea1bb42cb54463376e24aa7701b543078", + "mode": "graph", + "cases": { + "choice": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.60411, + 1.614419, + 1.611234, + 1.612075, + 1.609266, + 1.615327, + 1.613778, + 1.611272, + 1.612406, + 1.603647, + 1.605168, + 1.605971, + 1.611837, + 1.603319, + 1.607348, + 1.608151, + 1.611356, + 1.614496, + 1.611629, + 1.61103, + 1.608505, + 1.610408, + 1.600971, + 1.610351, + 1.604088, + 1.602476, + 1.612239, + 1.609423, + 1.615693, + 1.61558, + 1.613561, + 1.611346, + 1.608053, + 1.609713, + 1.603553, + 1.607303, + 1.603859, + 1.605846, + 1.601989, + 1.606622, + 1.612108, + 1.611808, + 1.608191, + 1.603888, + 1.609705, + 1.611066, + 1.608245, + 1.602114, + 1.605534, + 1.607037, + 1.613396, + 1.612453, + 1.60494, + 1.606653, + 1.605319, + 1.610069, + 1.602227, + 1.61087, + 1.60825, + 1.60364, + 1.610284, + 1.600572, + 1.604389, + 1.601883, + 1.604433, + 1.601605, + 1.60372, + 1.603038, + 1.60302, + 1.609239, + 1.604151, + 1.60951, + 1.608294, + 1.598416, + 1.591432, + 1.592417, + 1.592246, + 1.591534, + 1.600795, + 1.595384, + 1.60434, + 1.594976, + 1.598914, + 1.596278, + 1.600817, + 1.59158, + 1.59064, + 1.594212, + 1.592329, + 1.597731, + 1.591243, + 1.598115, + 1.597566, + 1.597854, + 1.58636, + 1.585512, + 1.593021, + 1.59046, + 1.591007, + 1.586642 + ], + "client_rtt_ms": [ + 1.629904, + 1.641802, + 1.637833, + 1.647026, + 1.638891, + 1.642218, + 1.639868, + 1.637229, + 1.639471, + 1.640689, + 1.629506, + 1.631664, + 1.637489, + 1.636871, + 1.632721, + 1.633251, + 1.640969, + 1.639667, + 1.637477, + 1.635434, + 1.635452, + 1.636068, + 1.624301, + 1.637851, + 1.638676, + 1.627531, + 1.640811, + 1.635328, + 1.642692, + 1.641605, + 1.639872, + 1.636493, + 1.633458, + 1.636981, + 1.636127, + 1.635967, + 1.628184, + 1.630858, + 1.627634, + 1.63366, + 1.639038, + 1.637711, + 1.633467, + 1.631561, + 1.643996, + 1.636917, + 1.6309, + 1.628496, + 1.630669, + 1.631907, + 1.642804, + 1.636567, + 1.631026, + 1.631247, + 1.630763, + 1.645931, + 1.627898, + 1.637314, + 1.634025, + 1.630298, + 1.636538, + 1.624938, + 1.63188, + 1.625661, + 1.62929, + 1.633207, + 1.629422, + 1.628911, + 1.627268, + 1.637871, + 1.630856, + 1.634255, + 1.634098, + 1.622094, + 1.624118, + 1.626645, + 1.619077, + 1.618676, + 1.625863, + 1.621008, + 1.629269, + 1.623525, + 1.624905, + 1.622047, + 1.627684, + 1.625967, + 1.618745, + 1.618703, + 1.617387, + 1.62491, + 1.616479, + 1.623537, + 1.623235, + 1.624776, + 1.61261, + 1.609615, + 1.629673, + 1.616341, + 1.618395, + 1.611327 + ] + }, + "score": { + "B": 1, + "L": 64, + "engine_wall_ms": [ + 1.615698, + 1.619128, + 1.612553, + 1.615672, + 1.620613, + 1.611409, + 1.613405, + 1.610016, + 1.612257, + 1.610706, + 1.602812, + 1.607995, + 1.612042, + 1.609276, + 1.603201, + 1.603415, + 1.614626, + 1.610383, + 1.610979, + 1.609444, + 1.698864, + 1.633622, + 1.610658, + 1.606855, + 1.616164, + 1.611702, + 1.601206, + 1.605375, + 1.606722, + 1.605386, + 1.607895, + 1.604529, + 1.602977, + 1.609404, + 1.608657, + 1.611331, + 1.60429, + 1.608388, + 1.602959, + 1.607144, + 1.609176, + 1.604565, + 1.60417, + 1.606069, + 1.603743, + 1.607401, + 1.604871, + 1.611313, + 1.613661, + 1.607886, + 1.604061, + 1.60595, + 1.607668, + 1.604643, + 1.616383, + 1.605054, + 1.607008, + 1.601407, + 1.605348, + 1.609044, + 1.61115, + 1.608662, + 1.60692, + 1.606403, + 1.606031, + 1.602407, + 1.598512, + 1.603085, + 1.601369, + 1.606396, + 1.607703, + 1.612479, + 1.620856, + 1.607517, + 1.605311, + 1.609995, + 1.610928, + 1.608258, + 1.609561, + 1.615039, + 1.608319, + 1.608026, + 1.60469, + 1.603521, + 1.607443, + 1.611762, + 1.611171, + 1.615916, + 1.614304, + 1.62873, + 1.628333, + 1.625554, + 1.621519, + 1.627927, + 1.624932, + 1.62648, + 1.630587, + 1.62259, + 1.619111, + 1.617082 + ], + "client_rtt_ms": [ + 1.640186, + 1.645409, + 1.645756, + 1.644075, + 1.64809, + 1.63677, + 1.642019, + 1.63618, + 1.638986, + 1.636368, + 1.628519, + 1.639979, + 1.637436, + 1.636337, + 1.628218, + 1.628837, + 1.640639, + 1.635488, + 1.637098, + 1.641486, + 1.726791, + 1.661553, + 1.63432, + 1.635171, + 1.641312, + 1.637488, + 1.628161, + 1.629898, + 1.639207, + 1.630057, + 1.636994, + 1.629185, + 1.626518, + 1.635951, + 1.633809, + 1.636569, + 1.638559, + 1.634023, + 1.627624, + 1.634405, + 1.634394, + 1.629601, + 1.629187, + 1.632457, + 1.628044, + 1.639819, + 1.631808, + 1.63849, + 1.637686, + 1.639752, + 1.629795, + 1.631578, + 1.634144, + 1.636571, + 1.664963, + 1.630647, + 1.633478, + 1.62773, + 1.629936, + 1.638341, + 1.63754, + 1.63442, + 1.642115, + 1.63233, + 1.630253, + 1.627027, + 1.624742, + 1.631007, + 1.625838, + 1.635324, + 1.631977, + 1.646778, + 1.649273, + 1.633281, + 1.63362, + 1.635187, + 1.638699, + 1.63252, + 1.63506, + 1.651772, + 1.635389, + 1.635717, + 1.631181, + 1.630062, + 1.63273, + 1.637075, + 1.638121, + 1.642537, + 1.649452, + 1.657826, + 1.653765, + 1.654451, + 1.647897, + 1.655346, + 1.649875, + 1.653191, + 1.662412, + 1.647721, + 1.645576, + 1.643476 + ] + }, + "short_1": { + "B": 1, + "L": 48, + "engine_wall_ms": [ + 1.596772, + 1.592984, + 1.597438, + 1.597182, + 1.586734, + 1.599507, + 1.596085, + 1.592108, + 1.592736, + 1.594489, + 1.591014, + 1.590923, + 1.592755, + 1.589899, + 1.591791, + 1.590439, + 1.593969, + 1.599477, + 1.594616, + 1.590379, + 1.594864, + 1.591267, + 1.594179, + 1.590494, + 1.588716, + 1.590679, + 1.588231, + 1.612576, + 1.594993, + 1.596611, + 1.588536, + 1.591497, + 1.591634, + 1.590192, + 1.591469, + 1.588734, + 1.588831, + 1.592808, + 1.590067, + 1.591392, + 1.593087, + 1.59492, + 1.59014, + 1.591643, + 1.588027, + 1.587749, + 1.58954, + 1.59129, + 1.590957, + 1.59144, + 1.595651, + 1.590657, + 1.591858, + 1.590876, + 1.594178, + 1.588627, + 1.588062, + 1.594143, + 1.592526, + 1.588793, + 1.586073, + 1.591739, + 1.589978, + 1.5932, + 1.587334, + 1.591552, + 1.590316, + 1.59131, + 1.590102, + 1.589179, + 1.589225, + 1.591111, + 1.587367, + 1.592443, + 1.587515, + 1.585859, + 1.589643, + 1.59226, + 1.596048, + 1.596255, + 1.596019, + 1.601712, + 1.600148, + 1.596156, + 1.599334, + 1.589691, + 1.601115, + 1.593471, + 1.601686, + 1.603097, + 1.591939, + 1.596063, + 1.594202, + 1.590692, + 1.587138, + 1.59004, + 1.588275, + 1.592383, + 1.59104, + 1.591539 + ], + "client_rtt_ms": [ + 1.631637, + 1.617645, + 1.623399, + 1.620902, + 1.611672, + 1.627335, + 1.620498, + 1.617328, + 1.615932, + 1.619869, + 1.614428, + 1.614837, + 1.625452, + 1.61529, + 1.616456, + 1.614217, + 1.617674, + 1.625642, + 1.619699, + 1.617715, + 1.618631, + 1.615724, + 1.61875, + 1.612858, + 1.620082, + 1.614491, + 1.611496, + 1.637775, + 1.618732, + 1.622287, + 1.612876, + 1.615823, + 1.619374, + 1.61321, + 1.614727, + 1.613884, + 1.622487, + 1.61795, + 1.61454, + 1.615361, + 1.616984, + 1.619306, + 1.613493, + 1.614288, + 1.611029, + 1.610726, + 1.613747, + 1.61464, + 1.613471, + 1.621603, + 1.619488, + 1.615898, + 1.615422, + 1.613495, + 1.620199, + 1.612948, + 1.613422, + 1.618209, + 1.617139, + 1.61447, + 1.609538, + 1.623758, + 1.613497, + 1.617471, + 1.611299, + 1.613957, + 1.615131, + 1.615377, + 1.614969, + 1.612684, + 1.611945, + 1.615725, + 1.611368, + 1.623577, + 1.612315, + 1.609796, + 1.615577, + 1.616605, + 1.622093, + 1.61956, + 1.619068, + 1.627167, + 1.626499, + 1.622839, + 1.626902, + 1.615234, + 1.633909, + 1.618734, + 1.626089, + 1.627714, + 1.617218, + 1.620045, + 1.618003, + 1.616923, + 1.611553, + 1.615111, + 1.612538, + 1.614931, + 1.621239, + 1.615295 + ] + }, + "medium_1": { + "B": 1, + "L": 176, + "engine_wall_ms": [ + 1.927871, + 1.932128, + 1.940722, + 1.941797, + 1.94012, + 1.921489, + 1.926884, + 1.926102, + 1.933192, + 1.928623, + 1.935823, + 1.946025, + 1.939219, + 1.944358, + 1.927809, + 1.926243, + 1.913727, + 1.928592, + 1.924706, + 1.950024, + 1.966743, + 1.972881, + 1.970048, + 1.960962, + 1.928377, + 1.934636, + 1.926129, + 1.922655, + 1.922049, + 1.929829, + 1.940861, + 1.945936, + 1.948396, + 1.927853, + 1.924855, + 1.924734, + 1.929111, + 1.919399, + 1.933942, + 1.94133, + 1.943383, + 1.951708, + 1.953322, + 1.937615, + 1.930184, + 1.918499, + 1.925091, + 1.935354, + 1.926993, + 1.935228, + 1.932133, + 1.936317, + 1.939157, + 1.935037, + 1.928904, + 1.919091, + 1.918022, + 1.921461, + 1.921977, + 1.934631, + 1.944382, + 1.932791, + 1.935241, + 1.928217, + 1.930367, + 1.924489, + 1.919492, + 1.925059, + 1.922198, + 1.941455, + 1.928258, + 1.920482, + 1.931543, + 1.921273, + 1.92292, + 1.92682, + 1.934795, + 1.933889, + 1.932161, + 1.930456, + 1.928614, + 1.920412, + 1.926088, + 1.938975, + 1.935341, + 1.937914, + 1.947788, + 1.939716, + 1.937448, + 1.944268, + 1.945356, + 1.925135, + 1.920222, + 1.91745, + 1.916688, + 1.924135, + 1.922862, + 1.918901, + 1.93435, + 1.936203 + ], + "client_rtt_ms": [ + 1.953893, + 1.960403, + 1.974973, + 1.970788, + 1.965766, + 1.949236, + 1.951996, + 1.952032, + 1.958468, + 1.956913, + 1.963352, + 1.974279, + 1.966217, + 1.973206, + 1.960805, + 1.952352, + 1.939137, + 1.957476, + 1.951087, + 1.978883, + 1.993266, + 2.001933, + 1.99626, + 1.989, + 1.955271, + 1.962643, + 1.951537, + 1.955813, + 1.947901, + 1.957532, + 1.96935, + 1.971894, + 1.975712, + 1.953639, + 1.951741, + 1.949344, + 1.955326, + 1.94485, + 1.959836, + 1.976562, + 1.975823, + 1.97962, + 1.983335, + 1.964386, + 1.957094, + 1.943598, + 1.952548, + 1.961215, + 1.954277, + 1.962491, + 1.958928, + 1.970573, + 1.965993, + 1.961191, + 1.958329, + 1.945268, + 1.945896, + 1.949444, + 1.950285, + 1.961914, + 1.972399, + 1.959797, + 1.96227, + 1.962423, + 1.958842, + 1.951005, + 1.947156, + 1.951081, + 1.950008, + 1.968102, + 1.954247, + 1.945552, + 1.95719, + 1.948269, + 1.950517, + 1.952696, + 1.968987, + 1.961139, + 1.960041, + 1.956983, + 1.955864, + 1.945994, + 1.952765, + 1.96445, + 1.961487, + 1.963554, + 1.976407, + 1.96628, + 1.971981, + 1.970729, + 1.97487, + 1.953855, + 1.948989, + 1.943092, + 1.94387, + 1.949672, + 1.950282, + 1.945851, + 1.962756, + 1.964791 + ] + }, + "long_1": { + "B": 1, + "L": 512, + "engine_wall_ms": [ + 3.009579, + 3.010617, + 2.986416, + 2.988513, + 3.021566, + 2.982791, + 3.018295, + 3.004619, + 3.024052, + 3.032885, + 3.032254, + 3.013491, + 3.017659, + 2.999441, + 3.001236, + 3.000494, + 3.019711, + 3.042601, + 3.01765, + 3.010915, + 2.993468, + 3.034251, + 3.046535, + 3.037572, + 3.020856, + 2.992503, + 2.990198, + 3.001128, + 3.032337, + 3.028542, + 2.99906, + 3.022719, + 3.030208, + 3.023184, + 3.030595, + 3.016727, + 3.011744, + 2.979852, + 2.992057, + 3.003136, + 3.021753, + 3.012038, + 3.002897, + 2.997619, + 3.020794, + 3.058347, + 3.033661, + 3.001614, + 2.986424, + 3.005137, + 3.024107, + 3.038619, + 3.026969, + 3.02909, + 3.018106, + 3.026253, + 3.021747, + 3.024788, + 3.015544, + 2.989935, + 2.990104, + 2.992919, + 3.021182, + 3.018018, + 2.998005, + 3.012948, + 2.994553, + 2.994081, + 3.012402, + 3.028901, + 3.020957, + 3.001155, + 2.994455, + 2.992515, + 2.998859, + 2.993003, + 2.988362, + 2.998794, + 3.027427, + 2.997031, + 3.023491, + 3.01917, + 3.007285, + 2.991255, + 2.990794, + 3.006599, + 2.990737, + 3.013443, + 3.032836, + 3.02219, + 3.019663, + 2.997249, + 3.014117, + 3.014759, + 2.996717, + 2.999578, + 2.991674, + 2.996964, + 3.00324, + 3.033051 + ], + "client_rtt_ms": [ + 3.046923, + 3.043284, + 3.019277, + 3.019301, + 3.057033, + 3.034162, + 3.053313, + 3.039006, + 3.057013, + 3.068416, + 3.067782, + 3.047626, + 3.050927, + 3.032243, + 3.032223, + 3.032994, + 3.05426, + 3.085104, + 3.051694, + 3.044584, + 3.025543, + 3.067444, + 3.080767, + 3.072054, + 3.054118, + 3.024009, + 3.021503, + 3.034728, + 3.065332, + 3.068826, + 3.034171, + 3.056668, + 3.065902, + 3.055269, + 3.064121, + 3.049179, + 3.045276, + 3.014181, + 3.026907, + 3.037882, + 3.057161, + 3.054832, + 3.034368, + 3.033345, + 3.055644, + 3.092425, + 3.065509, + 3.034261, + 3.017811, + 3.038475, + 3.05589, + 3.072003, + 3.061449, + 3.070625, + 3.051065, + 3.059692, + 3.058281, + 3.06433, + 3.052262, + 3.021864, + 3.022219, + 3.025317, + 3.05532, + 3.049626, + 3.028422, + 3.045188, + 3.034915, + 3.025739, + 3.044799, + 3.06237, + 3.054712, + 3.033191, + 3.030961, + 3.02543, + 3.031009, + 3.024822, + 3.018933, + 3.036476, + 3.072037, + 3.032785, + 3.056241, + 3.053117, + 3.040813, + 3.023939, + 3.021234, + 3.039493, + 3.024524, + 3.048776, + 3.064406, + 3.054414, + 3.059375, + 3.031911, + 3.046489, + 3.045189, + 3.028752, + 3.031171, + 3.024231, + 3.02726, + 3.036302, + 3.066846 + ] + } + } + } + ] +} diff --git a/recipe/laya/native/optimized-export.patch b/recipe/laya/native/optimized-export.patch new file mode 100644 index 00000000..9ee3b3ed --- /dev/null +++ b/recipe/laya/native/optimized-export.patch @@ -0,0 +1,105 @@ +--- a/src/backends/cuda/tools/export.py ++++ b/src/backends/cuda/tools/export.py +@@ -17,6 +17,18 @@ + + sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "kernels")) + import laya_tilelang as kernels ++ ++QKV_DISPATCH = """extern "C" int laya_qkv(void** p,int B,int L,int M,cudaStream_t stream) { ++ if(B==1 && L<=64)return laya_qkv_short(p,B,L,M,stream); ++ return laya_qkv_full(p,B,L,M,stream); ++} ++""" ++ ++OUT_DISPATCH = """extern "C" int laya_out(void** p,int B,int L,int M,cudaStream_t stream) { ++ if(B==1 && L<=64)return laya_out_short(p,B,L,M,stream); ++ return laya_out_full(p,B,L,M,stream); ++} ++""" + + SLOT = re.compile( + r"\(\(\(TVMFFIAny\*\)stack_ffi_any\)\[(\d+)\]\.v_(?:int64|ptr)\) = (.*);" +@@ -48,6 +60,21 @@ + def integer(value): + value = value.replace("(int64_t)", "").replace("(", "").replace(")", "") + return int(value) ++ ++ ++def patch_geglu_static_registers(body): ++ """Remove fixed register reservations only from the accepted BN32 lowering.""" ++ expected = "1ed96990542c07b58dca419dafcc45c6163bb9b6fff04ffca5ecedb2a34e921c" ++ if hashlib.sha256(body.encode()).hexdigest() != expected: ++ raise ValueError("long GEGLU BN32 lowering changed") ++ for call in ( ++ " tl::warpgroup_reg_dealloc<24>();\n", ++ " tl::warpgroup_reg_alloc<240>();\n", ++ ): ++ if body.count(call) != 1: ++ raise ValueError("long GEGLU register calls changed") ++ body = body.replace(call, "", 1) ++ return body + + + def export(name, kernel): +@@ -133,6 +160,8 @@ + body = source[source.index('extern "C" __global__') :].replace( + "main_kernel", symbol + ) ++ if name == "geglu": ++ body = patch_geglu_static_registers(body) + # TileLang reuses Q_s for O_s. Its generated wait is inside the key loop, + # so zero-key rows can overwrite Q_s while the asynchronous Q load is live. + # Wait before entering producer/consumer branches, including zero iterations. +@@ -163,16 +192,20 @@ + for identifier in re.findall(r"\b[A-Za-z_]\w*\b", value): + if identifier not in allowed and not identifier.endswith("_desc"): + raise ValueError(("unknown host symbol", identifier)) +- wrapper = f"""extern "C" int laya_{name}(void** p,int B,int L,int M,cudaStream_t stream) {{ ++ dispatch = "" ++ if name == "geglu": ++ dispatch = " if(B==1 && M<=64)return laya_geglu_short(p,B,L,M,stream);\n" ++ wrapper_name = {"qkv": "qkv_full", "out": "out_full"}.get(name, name) ++ wrapper = f"""extern "C" int laya_{wrapper_name}(void** p,int B,int L,int M,cudaStream_t stream) {{ + if(B<1 || B>16 || L<16 || L>512 || L%16 || M!=B*L)return -1; +-{chr(10).join(bindings)} ++{dispatch}{chr(10).join(bindings)} + {chr(10).join(descriptors)} + {symbol}<<>>({','.join(args)}); + return static_cast(cudaGetLastError()); + }} + """ + init = "" +- if shared_memory > 49152: ++ if shared_memory >= 49152: + init = f"if(auto e=cudaFuncSetAttribute({symbol},cudaFuncAttributeMaxDynamicSharedMemorySize,{shared_memory});e!=cudaSuccess)return static_cast(e);" + metadata = { + "name": name, +@@ -207,14 +240,17 @@ + "rope": rope.build(16, 64, 1, 8), + "rope_original": kernels.rope_kernel(16, 64), + "qkv": kernels.gemm_kernel(3072, 1024), ++ "qkv_short": kernels.gemm_kernel(3072, 1024, bn=64), + "attn_full": kernels.attn_kernel(None, None, 16, 64), + } + if not args.probe_only: + exports.update( + { + "out": kernels.gemm_kernel(1024, 1024), +- "geglu": kernels.gemm_geglu_kernel(2624, 1024), +- "down": kernels.gemm_kernel(1024, 2624), ++ "out_short": kernels.gemm_kernel(1024, 1024, bm=64, bn=64), ++ "geglu_short": kernels.gemm_geglu_kernel(2624, 1024, bn=32), ++ "geglu": kernels.gemm_geglu_kernel(2624, 1024, bn=32), ++ "down": kernels.gemm_kernel(1024, 2624, bm=64, bn=64), + "addln": kernels.add_ln_kernel(1024), + "addln_bias": kernels.add_ln_kernel(1024, bias=True), + "ln_bias": kernels.add_ln_kernel(1024, residual=False, bias=True), +@@ -255,6 +291,8 @@ + + preamble + + "\n" + + "\n".join(bodies) ++ + QKV_DISPATCH ++ + ("" if args.probe_only else OUT_DISPATCH) + + '\nextern "C" int laya_kernels_init(){' + + "".join(inits) + + "return 0;}\n" diff --git a/src/backends/cuda/Cargo.toml b/src/backends/cuda/Cargo.toml new file mode 100644 index 00000000..58885bb2 --- /dev/null +++ b/src/backends/cuda/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "omni-cuda" +version = "0.1.0" +edition = "2024" +publish = false + +[dependencies] +anyhow = "1" +libloading = "0.8" diff --git a/src/backends/cuda/README.md b/src/backends/cuda/README.md index f8d8d136..771afda7 100644 --- a/src/backends/cuda/README.md +++ b/src/backends/cuda/README.md @@ -18,3 +18,14 @@ retaining their processing/batching ownership. Status: [`qwen3_5/`](qwen3_5/) provides the shared Qwen3.5/3.8 prefill operations used by the Cua-S1 and Open-Jev native workers. See the [supported-model coverage](../../../docs/supported-models.md) for validation scope. + +## Laya on Hopper + +The `omni-cuda` Rust crate and `kernels/` / `tools/` provide Laya's ABI1 bundle. +They are independent of Qwen's `cs1_*` library. Allocation, streams and captured +graphs stay on the executor's owning thread; buffers outlive queued device work. +The AOT build uses CUDA and TileLang; serving needs the compiled library and +rotary tables, without Python, PyTorch or TileLang. Only `sm_90a` is supported. + +See the [native Laya recipe](../../../recipe/laya/native/README.md) for building +and launching, and [third-party sources](THIRD_PARTY.md) for attribution. diff --git a/src/backends/cuda/THIRD_PARTY.md b/src/backends/cuda/THIRD_PARTY.md new file mode 100644 index 00000000..e913bd98 --- /dev/null +++ b/src/backends/cuda/THIRD_PARTY.md @@ -0,0 +1,5 @@ +# Sources + +- `kernels/laya_tilelang.py`: Laya 0.3.20 `tl_kernels.py`, Apache-2.0; see `licenses/Laya.txt`. CUDA export preserves the arithmetic of rows with reachable keys; the emitted Attention adds an unconditional wait before shared-memory reuse on empty key ranges. Native Attention also explicitly writes zero for every query row without a reachable key, including empty rows inside partially valid local-attention tiles. +- `kernels/model_ops.cu`: Welford reduction and normalization order adapted from [PyTorch 2.11 CUDA LayerNorm](https://github.com/pytorch/pytorch/blob/v2.11.0/aten/src/ATen/native/cuda/layer_norm_kernel.cu), BSD-3-Clause; see `licenses/PyTorch.txt`. Compiled without fast math, matching that reference. +- AOT host-stub inspection follows the approach in [PegaInfer](https://github.com/pegainfer-project/pegainfer), commit b2efe52726cda0ae9c460e56f398fbe7c1b2b584. No runtime dependency on PegaInfer or TileLang. diff --git a/src/backends/cuda/build.sh b/src/backends/cuda/build.sh new file mode 100755 index 00000000..6785968a --- /dev/null +++ b/src/backends/cuda/build.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +# +# Build liblaya_cuda.so through one interface. +# +# src/backends/cuda/build.sh [compute capability] +# +# This is a wrapper, not a replacement: `tools/export.py` generates the CUDA +# source from TileLang and `tools/build.py` compiles it, exactly as +# recipe/laya/native/README.md documents. Keeping a single entry point means CI +# can build this backend the same way it builds any other, without knowing that +# this one happens to be generated rather than hand-written. +# +# It does NOT remove TileLang from the build: export.py imports it, so a machine +# building this bundle needs TileLang installed. Checking in the generated +# `generated.cu` and compiling only that with nvcc is a separate change, and the +# model owner's call. +# +# BUILD_STAGE= stage the export there and retain it (default: mktemp -d) +# KEEP_STAGE=1 keep the staging directory and print its path +# PYTHON= interpreter for the tools (default: python3, else python) +# CUDA_HOME= CUDA toolkit root (default: /usr/local/cuda) +# +# A checkpoint is not needed here. `tools/export_tables.py` needs one; it is a +# separate step in the recipe and is not required to produce the library. + +set -euo pipefail + +here=$(cd "$(dirname "$0")" && pwd) +out=${1:?usage: build.sh [compute capability]} +arch=${2:-${CUDA_COMPUTE_CAP:-90}} + +case "$arch" in + 90) ;; + *) + echo "build.sh: these kernels are pinned to sm_90a (Hopper); got '$arch'." >&2 + echo " The TileLang export embeds compute_90a and the kernels use" >&2 + echo " Hopper-only instructions, so another target cannot be built." >&2 + exit 2 + ;; +esac + +python=${PYTHON:-} +if [ -z "$python" ]; then + if command -v python3 >/dev/null 2>&1; then python=python3; else python=python; fi +fi +if ! command -v "$python" >/dev/null 2>&1; then + echo "build.sh: no Python interpreter found; set PYTHON" >&2 + exit 2 +fi +if ! "$python" -c 'import tilelang' >/dev/null 2>&1; then + echo "build.sh: TileLang is not importable by '$python', and tools/export.py needs it." >&2 + echo " Install it (see recipe/laya/native/README.md) or set PYTHON." >&2 + exit 2 +fi + +stage=${BUILD_STAGE:-} +if [ -z "$stage" ]; then + stage=$(mktemp -d "${TMPDIR:-/tmp}/laya-cuda.XXXXXX") + if [ -z "${KEEP_STAGE:-}" ]; then + trap 'rm -rf "$stage"' EXIT + fi +else + mkdir -p "$stage" +fi + +echo "build.sh: staging in $stage" +"$python" "$here/tools/export.py" "$stage" +"$python" "$here/tools/build.py" "$stage" + +library=$stage/liblaya_cuda.so +if [ ! -f "$library" ]; then + echo "build.sh: tools/build.py did not produce $library" >&2 + exit 1 +fi + +mkdir -p "$out" +if ! [ "$stage" -ef "$out" ]; then + cp "$library" "$out/liblaya_cuda.so" + if [ -f "$stage/build-manifest.json" ]; then + cp "$stage/build-manifest.json" "$out/build-manifest.json" + fi +fi + +echo "build.sh: built $out/liblaya_cuda.so for sm_${arch}a" diff --git a/src/backends/cuda/kernels/laya_tilelang.py b/src/backends/cuda/kernels/laya_tilelang.py new file mode 100644 index 00000000..3bf0e501 --- /dev/null +++ b/src/backends/cuda/kernels/laya_tilelang.py @@ -0,0 +1,227 @@ +"""TileLang kernels for the Laya (ModernBERT + decision head) encoder. + +All kernels take bf16 activations, accumulate in fp32. Row count M is a runtime +symbol so one compiled kernel serves every batch/sequence bucket; M must be a +multiple of 16 (the caller pads); out-of-bounds rows are predicated by TileLang. +""" +import tilelang +import tilelang.language as T + +DT, ACC = "bfloat16", "float" +FAST = {tilelang.PassConfigKey.TL_ENABLE_FAST_MATH: True} + + +def _act(x, kind): + if kind == "gelu": # exact erf-GELU, what HF "gelu" means + return 0.5 * x * (1.0 + T.erf(x * 0.7071067811865476)) + if kind == "relu": + return T.max(x, 0.0) + return x + + +# ----------------------------------------------------------------------------- GEMM +@tilelang.jit(pass_configs=FAST) +def gemm_kernel(N, K, bias=False, act="none", bm=64, bn=128, bk=64, stages=3, threads=128): + """C[M,N] = act(A[M,K] @ W[N,K]^T + b).""" + M = T.dynamic("M") + + @T.prim_func + def main(A: T.Tensor((M, K), DT), W: T.Tensor((N, K), DT), Bv: T.Tensor((N,), ACC), C: T.Tensor((M, N), DT)): + with T.Kernel(T.ceildiv(N, bn), T.ceildiv(M, bm), threads=threads) as (bx, by): + A_s = T.alloc_shared((bm, bk), DT) + W_s = T.alloc_shared((bn, bk), DT) + C_l = T.alloc_fragment((bm, bn), ACC) + T.clear(C_l) + for k in T.Pipelined(T.ceildiv(K, bk), num_stages=stages): + T.copy(A[by * bm, k * bk], A_s) + T.copy(W[bx * bn, k * bk], W_s) + T.gemm(A_s, W_s, C_l, transpose_B=True) + for i, j in T.Parallel(bm, bn): + v = C_l[i, j] + if bias: + v = v + Bv[bx * bn + j] + C_l[i, j] = _act(v, act) + T.copy(C_l, C[by * bm, bx * bn]) + return main + + +@tilelang.jit(pass_configs=FAST) +def gemm_geglu_kernel(F, K, bm=64, bn=64, bk=64, stages=3, threads=128): + """ModernBERT GLU MLP up-projection, fused: C[M,F] = gelu(A @ Wi[:F]^T) * (A @ Wi[F:]^T).""" + M = T.dynamic("M") + + @T.prim_func + def main(A: T.Tensor((M, K), DT), W: T.Tensor((2 * F, K), DT), C: T.Tensor((M, F), DT)): + with T.Kernel(T.ceildiv(F, bn), T.ceildiv(M, bm), threads=threads) as (bx, by): + A_s = T.alloc_shared((bm, bk), DT) + Wi_s = T.alloc_shared((bn, bk), DT) + Wg_s = T.alloc_shared((bn, bk), DT) + Ci = T.alloc_fragment((bm, bn), ACC) + Cg = T.alloc_fragment((bm, bn), ACC) + T.clear(Ci); T.clear(Cg) + for k in T.Pipelined(T.ceildiv(K, bk), num_stages=stages): + T.copy(A[by * bm, k * bk], A_s) + T.copy(W[bx * bn, k * bk], Wi_s) + T.copy(W[F + bx * bn, k * bk], Wg_s) + T.gemm(A_s, Wi_s, Ci, transpose_B=True) + T.gemm(A_s, Wg_s, Cg, transpose_B=True) + for i, j in T.Parallel(bm, bn): + Ci[i, j] = _act(Ci[i, j], "gelu") * Cg[i, j] + T.copy(Ci, C[by * bm, bx * bn]) + return main + + +# ----------------------------------------------------------------------------- LayerNorm (+residual) +@tilelang.jit(pass_configs=FAST) +def add_ln_kernel(D, residual=True, bias=False, eps=1e-5, bm=4, threads=32): + """X (fp32 residual stream) += R (bf16 branch output, if residual); Y (bf16) = LN(X) * w (+ b). + + The residual stream stays in fp32 exactly like the stock autocast path: ModernBERT-large's residual + activations reach ~3e4, where bf16's 8-bit mantissa would lose ~100 units per add and drift layer by layer.""" + M = T.dynamic("M") + + @T.prim_func + def main(X: T.Tensor((M, D), ACC), R: T.Tensor((M, D), DT), Wv: T.Tensor((D,), ACC), Bv: T.Tensor((D,), ACC), + Y: T.Tensor((M, D), DT)): + with T.Kernel(T.ceildiv(M, bm), threads=threads) as bx: + x = T.alloc_fragment((bm, D), ACC) + xs = T.alloc_fragment((bm, D), ACC) + mean = T.alloc_fragment((bm,), ACC) + var = T.alloc_fragment((bm,), ACC) + Xb = T.alloc_shared((bm, D), ACC) + Rb = T.alloc_shared((bm, D), DT) + Yb = T.alloc_shared((bm, D), DT) + T.copy(X[bx * bm, 0], Xb) + T.copy(Xb, x) + if residual: + T.copy(R[bx * bm, 0], Rb) + T.copy(Rb, xs) + for i, j in T.Parallel(bm, D): + x[i, j] = x[i, j] + xs[i, j] + T.copy(x, Xb) + T.copy(Xb, X[bx * bm, 0]) + T.reduce_sum(x, mean, dim=1) + for i in T.Parallel(bm): + mean[i] = mean[i] / D + for i, j in T.Parallel(bm, D): + xs[i, j] = (x[i, j] - mean[i]) * (x[i, j] - mean[i]) + T.reduce_sum(xs, var, dim=1) + for i in T.Parallel(bm): + var[i] = T.rsqrt(var[i] / D + eps) + for i, j in T.Parallel(bm, D): + v = (x[i, j] - mean[i]) * var[i] * Wv[j] + if bias: + v = v + Bv[j] + xs[i, j] = v + T.copy(xs, Yb) + T.copy(Yb, Y[bx * bm, 0]) + return main + + +# ----------------------------------------------------------------------------- RoPE (in place on packed qkv) +@tilelang.jit(pass_configs=FAST) +def rope_kernel(H, Dh, bm=32, threads=128): + """QKV[M, 3*H*Dh] packed as (q|k|v)(h)(d). Rotates q and k in place (rotate-half convention, fp32 math). + cos/sin: [L, Dh/2]. Row r has position r % L. M and L are runtime symbols.""" + M, L = T.dynamic("M"), T.dynamic("L") + half = Dh // 2 + W = 2 * H * Dh # q and k columns + + @T.prim_func + def main(QKV: T.Tensor((M, 3 * H * Dh), DT), Cos: T.Tensor((L, half), ACC), Sin: T.Tensor((L, half), ACC)): + with T.Kernel(T.ceildiv(M, bm), threads=threads) as bx: + for i, c in T.Parallel(bm, W // 2): + r = bx * bm + i + pos = r % L + hh = c // half # which (q|k, head) + d = c % half + c0 = hh * Dh + d + c1 = c0 + half + x0 = T.cast(QKV[r, c0], ACC) + x1 = T.cast(QKV[r, c1], ACC) + cs = Cos[pos, d] + sn = Sin[pos, d] + QKV[r, c0] = T.cast(x0 * cs - x1 * sn, DT) + QKV[r, c1] = T.cast(x1 * cs + x0 * sn, DT) + return main + + +# ----------------------------------------------------------------------------- flash attention (padding mask + sliding window) +@tilelang.jit(pass_configs=FAST) +def attn_kernel(B, L, H, Dh, window=0, bm=64, bn=64, stages=1, threads=128): + """QKV: [B, L, 3, H, Dh] bf16 (a view of the packed [M, 3*H*Dh] buffer). Lens: [B] int32 valid length. + O: [B, L, H*Dh]. window>0 => bidirectional sliding window |i-j| <= window. Masked scores use a large + finite negative; rows with no keys are explicitly zeroed after accumulation, + including empty rows inside a tile whose other rows still have local keys. + + B and/or L may be None: they then become runtime symbols (one compile serves every shape, at the + cost of predicated loads -- ~4x slower for full attention at L=1024, free for short inputs).""" + scale = (1.0 / Dh) ** 0.5 * 1.44269504 # log2(e) + if B is None: + B = T.dynamic("B") + if L is None: + L = T.dynamic("L") + NEG = -1e9 + + @T.prim_func + def main(QKV: T.Tensor((B, L, 3, H, Dh), DT), Lens: T.Tensor((B,), "int32"), O: T.Tensor((B, L, H * Dh), DT)): + with T.Kernel(T.ceildiv(L, bm), H, B, threads=threads) as (bx, by, bz): + Q_s = T.alloc_shared((bm, Dh), DT) + K_s = T.alloc_shared((bn, Dh), DT) + V_s = T.alloc_shared((bn, Dh), DT) + O_s = T.alloc_shared((bm, Dh), DT) + s = T.alloc_fragment((bm, bn), ACC) + s_c = T.alloc_fragment((bm, bn), DT) + o = T.alloc_fragment((bm, Dh), ACC) + m = T.alloc_fragment((bm,), ACC) + m_prev = T.alloc_fragment((bm,), ACC) + sc = T.alloc_fragment((bm,), ACC) + rs = T.alloc_fragment((bm,), ACC) + l = T.alloc_fragment((bm,), ACC) + T.annotate_layout({Q_s: tilelang.layout.make_swizzled_layout(Q_s)}) + T.copy(QKV[bz, bx * bm:(bx + 1) * bm, 0, by, :], Q_s) + T.fill(o, 0); T.fill(l, 0); T.fill(m, NEG) + n = Lens[bz] + if window > 0: + k_lo = T.max(0, (bx * bm - window) // bn) + k_hi = T.min(T.ceildiv(L, bn), T.ceildiv(T.min(n, (bx + 1) * bm + window), bn)) + else: + k_lo = 0 + k_hi = T.ceildiv(n, bn) + for k in T.Pipelined(k_lo, k_hi, num_stages=stages): + T.copy(QKV[bz, k * bn:(k + 1) * bn, 1, by, :], K_s) + for i, j in T.Parallel(bm, bn): + qi = bx * bm + i + kj = k * bn + j + if window > 0: + ok = (kj < n) & (qi - kj <= window) & (kj - qi <= window) + else: + ok = kj < n + s[i, j] = T.if_then_else(ok, 0.0, NEG) + T.gemm(Q_s, K_s, s, transpose_B=True, policy=T.GemmWarpPolicy.FullRow) + T.copy(QKV[bz, k * bn:(k + 1) * bn, 2, by, :], V_s) + T.copy(m, m_prev) + T.reduce_max(s, m, dim=1, clear=False) + for i in T.Parallel(bm): + sc[i] = T.exp2(m_prev[i] * scale - m[i] * scale) + for i, j in T.Parallel(bm, bn): + s[i, j] = T.exp2(s[i, j] * scale - m[i] * scale) + T.reduce_sum(s, rs, dim=1) + for i in T.Parallel(bm): + l[i] = l[i] * sc[i] + rs[i] + T.copy(s, s_c) + for i, j in T.Parallel(bm, Dh): + o[i, j] = o[i, j] * sc[i] + T.gemm(s_c, V_s, o, policy=T.GemmWarpPolicy.FullRow) + for i, j in T.Parallel(bm, Dh): + # A finite NEG mask alone gives positive softmax weights when + # every key is masked. Preserve arithmetic for every row with + # keys, and zero the exact empty range (inclusive window). + if window > 0: + has_keys = (n > 0) & (bx * bm + i < n + window) + else: + has_keys = n > 0 + o[i, j] = T.if_then_else(has_keys, o[i, j] / T.max(l[i], 1e-30), 0.0) + T.copy(o, O_s) + T.copy(O_s, O[bz, bx * bm:(bx + 1) * bm, by * Dh:(by + 1) * Dh]) + return main diff --git a/src/backends/cuda/kernels/model_ops.cu b/src/backends/cuda/kernels/model_ops.cu new file mode 100644 index 00000000..fad23b1d --- /dev/null +++ b/src/backends/cuda/kernels/model_ops.cu @@ -0,0 +1,258 @@ +// Glue operations around the exported official TileLang encoder. +#include +#include +#include +#include +#include +using BF = __nv_bfloat16; + +// Reduction order follows PyTorch 2.11 CUDA LayerNorm (BSD-3-Clause). +// See THIRD_PARTY.md. Four warps, four adjacent values per vector, then tree reduction. +struct Stats { + float mean, var, count; +}; + +__device__ Stats combine(Stats b, Stats a) { + float delta = b.mean - a.mean, count = a.count + b.count; + if (count > 0) { + float coef = 1.f / count, na = a.count * coef, nb = b.count * coef; + return {na * a.mean + nb * b.mean, + a.var + b.var + delta * delta * a.count * nb, count}; + } + return {0, 0, 0}; +} + +template +__device__ Stats stats(Load load, float* buf) { + int lane = threadIdx.x, warp = threadIdx.y, t = lane + warp * 32; + Stats wd{0, 0, 0}; + for (int i = t; i < 256; i += 128) { + #pragma unroll + for (int j = 0; j < 4; j++) { + float v = load(4 * i + j), delta = v - wd.mean, count = wd.count + 1.f, + mean = wd.mean + delta * (1.f / count); + wd = {mean, wd.var + delta * (v - mean), count}; + } + } + for (int offset = 16; offset; offset >>= 1) { + Stats other{__shfl_down_sync(0xffffffff, wd.mean, offset), + __shfl_down_sync(0xffffffff, wd.var, offset), + __shfl_down_sync(0xffffffff, wd.count, offset)}; + wd = combine(wd, other); + } + for (int offset = 2; offset; offset >>= 1) { + if (lane == 0 && warp >= offset && warp < 2 * offset) { + int j = warp - offset; + buf[2 * j] = wd.mean; + buf[2 * j + 1] = wd.var; + buf[4 + j] = wd.count; + } + __syncthreads(); + if (lane == 0 && warp < offset) { + Stats other{buf[2 * warp], buf[2 * warp + 1], buf[4 + warp]}; + wd = combine(wd, other); + } + __syncthreads(); + } + if (lane == 0 && warp == 0) { + buf[0] = wd.mean; + buf[1] = wd.var / 1024.f; + } + __syncthreads(); + return {buf[0], buf[1], 0}; +} + +struct HalfLoad { + const half* p; + __device__ float operator()(int j) const { + return __half2float(p[j]); + } +}; + +struct FloatLoad { + const float* p; + __device__ float operator()(int j) const { + return p[j]; + } +}; + +__global__ void embed_norm(const int64_t* ids, const half* w, const float* gamma, + float* x, BF* y) { + int r = blockIdx.x, t = threadIdx.x + threadIdx.y * 32; + __shared__ float buf[6]; + HalfLoad load{w + ids[r] * 1024}; + Stats wd = stats(load, buf); + float inv = rsqrtf(wd.var + 1e-5f); + for (int i = t; i < 256; i += 128) { + #pragma unroll + for (int k = 0; k < 4; k++) { + int j = 4 * i + k; + float z = gamma[j] * (inv * (load(j) - wd.mean)); + x[r * 1024 + j] = z; + y[r * 1024 + j] = __float2bfloat16_rn(z); + } + } +} + +__global__ void add_type(const BF* y, const BF* emb, const int64_t* types, + float* x, int L, int total) { + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < total) + x[i] = __bfloat162float(y[i]) + + __bfloat162float(emb[types[i / (L * 1024)] * 1024 + i % 1024]); +} + +__global__ void add_residual(float* x, const BF* y, int total) { + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < total) + x[i] += __bfloat162float(y[i]); +} + +__global__ void gather_norm(const float* h, const int32_t* indices, + const float* gamma, const float* bias, BF* y) { + int r = blockIdx.x, t = threadIdx.x + threadIdx.y * 32; + __shared__ float buf[6]; + FloatLoad load{h + indices[r] * 1024}; + Stats wd = stats(load, buf); + float inv = rsqrtf(wd.var + 1e-5f); + for (int i = t; i < 256; i += 128) { + #pragma unroll + for (int k = 0; k < 4; k++) { + int j = 4 * i + k; + y[r * 1024 + j] = + __float2bfloat16_rn(gamma[j] * (inv * (load(j) - wd.mean)) + bias[j]); + } + } +} + +// Match torch.addmm: accumulate and add bias in FP32, then round once to BF16. +__global__ void linear_finish(const float* acc, const BF* bias, BF* out, int n, + int count, int activation) { + int i = blockIdx.x * blockDim.x + threadIdx.x; + if (i < count) { + BF rounded = __float2bfloat16_rn(acc[i] + __bfloat162float(bias[i % n])); + if (activation) { + float v = __bfloat162float(rounded); + rounded = __float2bfloat16_rn( + 0.5f * v * (1.0f + erff(v * 0.7071067811865476f))); + } + out[i] = rounded; + } +} + +struct LinearContext { + cublasHandle_t handle; + float* scratch; +}; + +__global__ void action_features(const float* h, const BF* logits, + const int32_t* offsets, BF* out, int L) { + int b = blockIdx.x, t = threadIdx.x; + int lo = offsets[b], hi = offsets[b + 1]; + for (int j = t; j < 1024; j += blockDim.x) + out[b * 1028 + j] = __float2bfloat16_rn(h[b * L * 1024 + j]); + if (t == 0) { + float maxv = -INFINITY; + for (int i = lo; i < hi; i++) + maxv = fmaxf(maxv, __bfloat162float(logits[i])); + float sum = 0; + for (int i = lo; i < hi; i++) + sum += expf(__bfloat162float(logits[i]) - maxv); + float top1 = 0, top2 = 0, entropy = 0; + for (int i = lo; i < hi; i++) { + float p = expf(__bfloat162float(logits[i]) - maxv) / sum; + entropy -= p * logf(fmaxf(p, 1e-9f)); + if (p > top1) { + top2 = top1; + top1 = p; + } else if (p > top2) + top2 = p; + } + int k = max(2, hi - lo); + out[b * 1028 + 1024] = __float2bfloat16_rn(top1); + out[b * 1028 + 1025] = __float2bfloat16_rn(top1 - top2); + out[b * 1028 + 1026] = __float2bfloat16_rn(entropy / logf(float(k))); + out[b * 1028 + 1027] = __float2bfloat16_rn(float(k) / 255.0f); + } +} + +extern "C" { +int laya_embed(void** p, int B, int L, int M, cudaStream_t s) { + embed_norm<<>>( + (int64_t*)p[0], (half*)p[1], (float*)p[2], (float*)p[3], (BF*)p[4]); + return cudaGetLastError(); +} + +int laya_type(void** p, int B, int L, int M, cudaStream_t s) { + add_type<<<(M * 1024 + 255) / 256, 256, 0, s>>>( + (BF*)p[0], (BF*)p[1], (int64_t*)p[2], (float*)p[3], L, M * 1024); + return cudaGetLastError(); +} + +int laya_residual(void** p, int B, int L, int M, cudaStream_t s) { + add_residual<<<(M * 1024 + 255) / 256, 256, 0, s>>>( + (float*)p[0], (BF*)p[1], M * 1024); + return cudaGetLastError(); +} + +int laya_gather(void** p, int B, int L, int M, cudaStream_t s) { + gather_norm<<>>( + (float*)p[0], (int32_t*)p[1], (float*)p[2], (float*)p[3], (BF*)p[4]); + return cudaGetLastError(); +} + +int laya_features(void** p, int B, int L, int M, cudaStream_t s) { + action_features<<>>( + (float*)p[0], (BF*)p[1], (int32_t*)p[2], (BF*)p[3], L); + return cudaGetLastError(); +} + +int laya_blas_create(void** out, cudaStream_t s) { + *out = nullptr; + auto* h = new LinearContext{}; + auto rc = cublasCreate(&h->handle); + if (rc != CUBLAS_STATUS_SUCCESS) { + delete h; + return 20000 + rc; + } + rc = cublasSetStream(h->handle, s); + if (rc != CUBLAS_STATUS_SUCCESS) { + cublasDestroy(h->handle); + delete h; + return 20000 + rc; + } + auto ce = cudaMalloc(&h->scratch, 2048 * 1024 * sizeof(float)); + if (ce != cudaSuccess) { + cublasDestroy(h->handle); + delete h; + return ce; + } + *out = h; + return 0; +} + +int laya_blas_free(void* ptr) { + auto* h = (LinearContext*)ptr; + auto ce = cudaFree(h->scratch); + auto rc = cublasDestroy(h->handle); + delete h; + return ce != cudaSuccess ? int(ce) : (rc != CUBLAS_STATUS_SUCCESS ? 20000 + rc : 0); +} + +int laya_linear(void* ptr, const void* a, const void* w, const void* bias, + void* out, int rows, int n, int k, int activation, cudaStream_t s) { + if (rows < 1 || rows > 2048 || n < 1 || n > 1024 || k < 1) + return -1; + auto* h = (LinearContext*)ptr; + float alpha = 1, beta = 0; + auto rc = cublasGemmEx( + h->handle, CUBLAS_OP_T, CUBLAS_OP_N, n, rows, k, &alpha, w, CUDA_R_16BF, k, + a, CUDA_R_16BF, k, &beta, h->scratch, CUDA_R_32F, n, CUBLAS_COMPUTE_32F, + CUBLAS_GEMM_DEFAULT_TENSOR_OP); + if (rc != CUBLAS_STATUS_SUCCESS) + return 20000 + rc; + linear_finish<<<(rows * n + 255) / 256, 256, 0, s>>>( + h->scratch, (const BF*)bias, (BF*)out, n, rows * n, activation); + return cudaGetLastError(); +} +} diff --git a/src/backends/cuda/kernels/rope_selected.py b/src/backends/cuda/kernels/rope_selected.py new file mode 100644 index 00000000..4351adac --- /dev/null +++ b/src/backends/cuda/kernels/rope_selected.py @@ -0,0 +1,130 @@ +"""Retile official in-place RoPE; arithmetic, precision and layout stay unchanged. + +QKV is contiguous BF16 [M, 3*H*Dh], packed (q|k|v)(head)(dim). Cos/Sin +are contiguous FP32 [L, Dh/2], L > 0. Each row uses position r % L. +Q/K pairs are loaded in FP32, rotated in the official operation order and +rounded to BF16; V is never read or written. Inputs must be non-overlapping +CUDA tensors on one device. Dynamic M/L and partial row/head tiles are supported. +Only launch geometry changes. Numerical/performance acceptance is external. +""" + +import tilelang +import tilelang.language as T +import torch + +DT, ACC = "bfloat16", "float" +FAST = {tilelang.PassConfigKey.TL_ENABLE_FAST_MATH: True} +VARIANTS = {"r1_h4": (1, 4), "r2_h4": (2, 4), "r1_h8": (1, 8)} + + +@tilelang.jit(pass_configs=FAST) +def _kernel(H, Dh, rows, heads): + M, L = T.dynamic("M"), T.dynamic("L") + half = Dh // 2 + + @T.prim_func + def main(QKV: T.Tensor((M, 3 * H * Dh), DT), + Cos: T.Tensor((L, half), ACC), Sin: T.Tensor((L, half), ACC)): + with T.Kernel(T.ceildiv(M, rows), T.ceildiv(2 * H, heads), + threads=128) as (bx, by): + for i, c in T.Parallel(rows, heads * half): + r = bx * rows + i + hh = by * heads + c // half + d = c % half + if r < M: + if hh < 2 * H: + pos = r % L + c0 = hh * Dh + d + c1 = c0 + half + x0 = T.cast(QKV[r, c0], ACC) + x1 = T.cast(QKV[r, c1], ACC) + cs = Cos[pos, d] + sn = Sin[pos, d] + QKV[r, c0] = T.cast(x0 * cs - x1 * sn, DT) + QKV[r, c1] = T.cast(x1 * cs + x0 * sn, DT) + return main + + +def build(H, Dh, rows, heads): + """Build a generic positive-H, even-Dh kernel; measured target is H=16,Dh=64.""" + values = (H, Dh, rows, heads) + if any(type(value) is not int or value <= 0 for value in values) or Dh % 2: + raise ValueError("H/rows/heads must be positive integers; Dh must be positive and even") + return _kernel(H, Dh, rows, heads) + + +class InstalledRoPE: + """Count host calls during capture only, never GPU graph replays. + + capture_calls does not prove successful graph construction or replay; use + the caller's graph inventory and a GPU trace to establish those separately. + """ + + def __init__(self, kernel, H, Dh, variant, rows, heads, original): + self.kernel = kernel + self.original = original + self.metadata = {"variant": variant, "H": H, "Dh": Dh, + "rows": rows, "heads": heads, "threads": 128, + "fast_math": True, "counter_scope": "host_calls_during_capture"} + self.capture_calls = 0 + self.capture_shapes = {} + + def __call__(self, qkv, cos, sin): + H, Dh = self.metadata["H"], self.metadata["Dh"] + if (qkv.ndim != 2 or qkv.shape[1] != 3 * H * Dh or qkv.shape[0] <= 0 + or cos.ndim != 2 or cos.shape[0] <= 0 or cos.shape[1] != Dh // 2 + or tuple(sin.shape) != tuple(cos.shape)): + raise ValueError("RoPE requires QKV[M,3*H*Dh] and Cos/Sin[L,Dh/2], M/L > 0") + if (qkv.dtype != torch.bfloat16 or cos.dtype != torch.float32 + or sin.dtype != torch.float32 or not qkv.is_cuda + or cos.device != qkv.device or sin.device != qkv.device + or not all(t.is_contiguous() for t in (qkv, cos, sin))): + raise ValueError("RoPE requires contiguous CUDA BF16 QKV and FP32 Cos/Sin on one device") + capturing = torch.cuda.is_current_stream_capturing() + result = self.kernel(qkv, cos, sin) + if capturing: + self.capture_calls += 1 + M, L = int(qkv.shape[0]), int(cos.shape[0]) + key = f"M={M},L={L}" + entry = self.capture_shapes.setdefault(key, { + "M": M, "L": L, + "grid": [(M + self.metadata["rows"] - 1) // self.metadata["rows"], + (2 * H + self.metadata["heads"] - 1) // self.metadata["heads"], 1], + "block": [128, 1, 1], "capture_calls": 0, + }) + entry["capture_calls"] += 1 + return result + + +def install(fast, variant): + """Replace FastLaya RoPE before any graph is built; return capture metadata. + + Call only on an idle FastLaya instance. No existing graph is invalidated or + silently reused with a different kernel. Compilation failures leave it intact. + """ + if fast.graphs: + raise ValueError("Install RoPE on a fresh FastLaya instance with no captured graphs") + if (fast.H, fast.Dh) != (16, 64): + raise ValueError("This integration experiment supports only H=16, Dh=64") + if variant not in VARIANTS: + raise ValueError(f"Unknown RoPE variant: {variant}") + if isinstance(fast._rope_k, InstalledRoPE): + raise ValueError("Restore the previous RoPE candidate before installing another") + rows, heads = VARIANTS[variant] + candidate = InstalledRoPE(build(fast.H, fast.Dh, rows, heads), fast.H, + fast.Dh, variant, rows, heads, fast._rope_k) + fast._rope_k = candidate + return candidate + + +def restore(fast): + """Restore the exact saved official callable (or None for official lazy build). + + Existing captured graphs cannot be patched: use a fresh FastLaya instance + for paired runs, or explicitly dispose of the caller-owned graphs first. + """ + if fast.graphs: + raise ValueError("Cannot restore RoPE while captured graphs still reference the candidate") + if not isinstance(fast._rope_k, InstalledRoPE): + raise ValueError("No RoPE candidate is installed") + fast._rope_k = fast._rope_k.original diff --git a/src/backends/cuda/kernels/runtime.cu b/src/backends/cuda/kernels/runtime.cu new file mode 100644 index 00000000..185de53d --- /dev/null +++ b/src/backends/cuda/kernels/runtime.cu @@ -0,0 +1,83 @@ +#include +#include +#include + +extern "C" { +int laya_kernels_init(); + +int laya_init(void** stream) { + auto e = cudaSetDevice(0); + if (e != cudaSuccess) + return e; + int major = 0; + cudaDeviceGetAttribute(&major, cudaDevAttrComputeCapabilityMajor, 0); + if (major != 9) + return -2; + e = cudaStreamCreateWithFlags(reinterpret_cast(stream), + cudaStreamNonBlocking); + if (e != cudaSuccess) + return e; + int rc = laya_kernels_init(); + if (rc) { + cudaStreamDestroy(*reinterpret_cast(stream)); + *stream = nullptr; + } + return rc; +} + +const char* laya_error(int code) { + return code < 0 ? "invalid native CUDA argument or unsupported GPU" + : code >= 10000 ? "CUDA driver error" + : cudaGetErrorString(static_cast(code)); +} + +int laya_alloc(void** p, size_t bytes) { + return cudaMalloc(p, bytes); +} + +int laya_free(void* p) { + return cudaFree(p); +} + +int laya_upload(void* dst, const void* src, size_t bytes, void* stream) { + return cudaMemcpyAsync(dst, src, bytes, cudaMemcpyHostToDevice, + static_cast(stream)); +} + +int laya_download(void* dst, const void* src, size_t bytes, void* stream) { + return cudaMemcpyAsync(dst, src, bytes, cudaMemcpyDeviceToHost, + static_cast(stream)); +} + +int laya_sync(void* stream) { + return cudaStreamSynchronize(static_cast(stream)); +} + +int laya_stream_free(void* stream) { + return cudaStreamDestroy(static_cast(stream)); +} + +int laya_capture_begin(void* stream) { + return cudaStreamBeginCapture(static_cast(stream), + cudaStreamCaptureModeThreadLocal); +} + +int laya_capture_end(void* stream, void** executable) { + cudaGraph_t graph = nullptr; + auto e = cudaStreamEndCapture(static_cast(stream), &graph); + if (e != cudaSuccess) + return e; + e = cudaGraphInstantiate(reinterpret_cast(executable), graph, 0); + cudaGraphDestroy(graph); + return e; +} + +int laya_graph_run(void* executable, void* stream) { + return cudaGraphLaunch(static_cast(executable), + static_cast(stream)); +} + +int laya_graph_free(void* executable) { + return cudaGraphExecDestroy(static_cast(executable)); +} +} diff --git a/src/backends/cuda/laya.backend.json b/src/backends/cuda/laya.backend.json new file mode 100644 index 00000000..3d0452c2 --- /dev/null +++ b/src/backends/cuda/laya.backend.json @@ -0,0 +1,22 @@ +{ + "name": "laya", + "abi_version": 1, + "status": "experimental", + "sources": [ + "kernels/runtime.cu", + "kernels/model_ops.cu", + "kernels/laya_tilelang.py", + "kernels/rope_selected.py", + "tools/export.py", + "tools/build.py", + "tools/export_tables.py", + "src/lib.rs" + ], + "build": { + "script": "build.sh", + "output": "liblaya_cuda.so", + "default_arch": 90, + "architectures": [90], + "min_capability": 90 + } +} diff --git a/src/backends/cuda/licenses/Laya.txt b/src/backends/cuda/licenses/Laya.txt new file mode 100644 index 00000000..d9a10c0d --- /dev/null +++ b/src/backends/cuda/licenses/Laya.txt @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/src/backends/cuda/licenses/PyTorch.txt b/src/backends/cuda/licenses/PyTorch.txt new file mode 100644 index 00000000..c23172f7 --- /dev/null +++ b/src/backends/cuda/licenses/PyTorch.txt @@ -0,0 +1,84 @@ +From PyTorch: + +Copyright (c) 2016- Facebook, Inc (Adam Paszke) +Copyright (c) 2014- Facebook, Inc (Soumith Chintala) +Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) +Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) +Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) +Copyright (c) 2011-2013 NYU (Clement Farabet) +Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) +Copyright (c) 2006 Idiap Research Institute (Samy Bengio) +Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) + +From Caffe2: + +Copyright (c) 2016-present, Facebook Inc. All rights reserved. + +All contributions by Facebook: +Copyright (c) 2016 Facebook Inc. + +All contributions by Google: +Copyright (c) 2015 Google Inc. +All rights reserved. + +All contributions by Yangqing Jia: +Copyright (c) 2015 Yangqing Jia +All rights reserved. + +All contributions by Kakao Brain: +Copyright 2019-2020 Kakao Brain + +All contributions by Cruise LLC: +Copyright (c) 2022 Cruise LLC. +All rights reserved. + +All contributions by Tri Dao: +Copyright (c) 2024 Tri Dao. +All rights reserved. + +All contributions by Arm: +Copyright (c) 2021, 2023-2025 Arm Limited and/or its affiliates + +All contributions from Caffe: +Copyright(c) 2013, 2014, 2015, the respective contributors +All rights reserved. + +All other contributions: +Copyright(c) 2015, 2016 the respective contributors +All rights reserved. + +Caffe2 uses a copyright model similar to Caffe: each contributor holds +copyright over their contributions to Caffe2. The project versioning records +all such contribution and copyright details. If a contributor wants to further +mark their specific copyright on a particular contribution, they should +indicate their copyright solely in the commit message of the change when it is +committed. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America + and IDIAP Research Institute nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/src/backends/cuda/src/lib.rs b/src/backends/cuda/src/lib.rs new file mode 100644 index 00000000..5343723c --- /dev/null +++ b/src/backends/cuda/src/lib.rs @@ -0,0 +1,247 @@ +//! Single-threaded CUDA ownership. Loading a compiled bundle is explicit; CPU builds need no CUDA. +use anyhow::{Result, anyhow, ensure}; +use libloading::Library; +use std::{ + ffi::{CStr, c_void}, + path::Path, + rc::Rc, +}; +pub type Ptr = *mut c_void; +type Kernel = unsafe extern "C" fn(*mut Ptr, i32, i32, i32, Ptr) -> i32; +struct Context { + lib: Library, + stream: Ptr, +} +impl Context { + fn check(&self, code: i32) -> Result<()> { + if code == 0 { + return Ok(()); + } + unsafe { + let f = self + .lib + .get:: *const i8>(b"laya_error\0")?; + Err(anyhow!( + "CUDA {code}: {}", + CStr::from_ptr(f(code)).to_string_lossy() + )) + } + } + fn symbol(&self, name: &[u8]) -> Result { + unsafe { Ok(*self.lib.get::(name)?) } + } + fn sync(&self) -> Result<()> { + let f = self.symbol:: i32>(b"laya_sync\0")?; + self.check(unsafe { f(self.stream) }) + } +} +impl Drop for Context { + fn drop(&mut self) { + let _ = self.sync(); + unsafe { + if let Ok(f) = self + .lib + .get:: i32>(b"laya_stream_free\0") + { + f(self.stream); + } + } + } +} +#[derive(Clone)] +pub struct Cuda { + ctx: Rc, +} +impl Cuda { + /// Load a trusted library produced by this backend's build tools. + /// # Safety + /// The path must point to the matching native ABI, not arbitrary/untrusted code. + pub unsafe fn load(path: &Path) -> Result { + let lib = unsafe { Library::new(path) }?; + let mut stream = std::ptr::null_mut(); + let init = unsafe { lib.get:: i32>(b"laya_init\0") }?; + let code = unsafe { init(&mut stream) }; + let ctx = Rc::new(Context { lib, stream }); + ctx.check(code)?; + Ok(Self { ctx }) + } + pub fn alloc(&self, bytes: usize) -> Result { + ensure!(bytes > 0, "zero CUDA allocation"); + let f = self + .ctx + .symbol:: i32>(b"laya_alloc\0")?; + let mut p = std::ptr::null_mut(); + self.ctx.check(unsafe { f(&mut p, bytes) })?; + Ok(Buffer { + ctx: self.ctx.clone(), + p, + bytes, + }) + } + pub fn upload(&self, bytes: &[u8]) -> Result { + let b = self.alloc(bytes.len())?; + b.write(bytes)?; + Ok(b) + } + pub fn sync(&self) -> Result<()> { + self.ctx.sync() + } + /// # Safety + /// Tensor shape, dtype, layout, aliasing and allocation sizes must match the generated kernel. + /// Buffers must belong to this context and stay alive until synchronization or graph destruction. + pub unsafe fn launch(&self, name: &str, args: &[Ptr], b: usize, l: usize) -> Result<()> { + ensure!( + b > 0 && b <= 16 && l > 0 && l <= 512 && l.is_multiple_of(16), + "invalid CUDA shape" + ); + let k = self + .ctx + .symbol::(format!("laya_{name}\0").as_bytes())?; + self.ctx.check(unsafe { + k( + args.as_ptr() as *mut Ptr, + b as i32, + l as i32, + (b * l) as i32, + self.ctx.stream, + ) + }) + } + /// # Safety + /// Every allocation referenced by `work` must outlive the returned graph. No allocation or copy + /// that may synchronize is permitted inside work. This context is confined to one OS thread. + pub unsafe fn capture(&self, work: impl FnOnce() -> Result<()>) -> Result { + self.sync()?; + let begin = self + .ctx + .symbol:: i32>(b"laya_capture_begin\0")?; + let end = self + .ctx + .symbol:: i32>(b"laya_capture_end\0")?; + self.ctx.check(unsafe { begin(self.ctx.stream) })?; + let result = work(); + let mut p = std::ptr::null_mut(); + let code = unsafe { end(self.ctx.stream, &mut p) }; + if result.is_err() || code != 0 { + if !p.is_null() { + let f = self + .ctx + .symbol:: i32>(b"laya_graph_free\0")?; + unsafe { + f(p); + } + } + result?; + self.ctx.check(code)?; + } + Ok(Graph { + ctx: self.ctx.clone(), + p, + }) + } + /// # Safety + /// Caller supplies the precise dimensions and allocation sizes required by this glue kernel. + pub unsafe fn launch_rows( + &self, + name: &str, + args: &[Ptr], + b: usize, + l: usize, + rows: usize, + ) -> Result<()> { + let k = self + .ctx + .symbol::(format!("laya_{name}\0").as_bytes())?; + self.ctx.check(unsafe { + k( + args.as_ptr() as *mut Ptr, + b as i32, + l as i32, + rows as i32, + self.ctx.stream, + ) + }) + } + pub fn stream(&self) -> Ptr { + self.ctx.stream + } + /// # Safety + /// `T` must exactly match the ABI and signature of the named bundle symbol. + pub unsafe fn symbol(&self, name: &[u8]) -> Result { + self.ctx.symbol(name) + } + pub fn check(&self, code: i32) -> Result<()> { + self.ctx.check(code) + } +} +pub struct Buffer { + ctx: Rc, + p: Ptr, + bytes: usize, +} +impl Buffer { + pub fn bytes(&self) -> usize { + self.bytes + } + pub fn ptr(&self) -> Ptr { + self.p + } + pub fn write(&self, bytes: &[u8]) -> Result<()> { + ensure!(bytes.len() <= self.bytes, "upload exceeds allocation"); + let f = self + .ctx + .symbol:: i32>(b"laya_upload\0")?; + self.ctx + .check(unsafe { f(self.p, bytes.as_ptr(), bytes.len(), self.ctx.stream) })?; + self.ctx.sync() + } + pub fn read(&self, bytes: usize) -> Result> { + ensure!(bytes <= self.bytes, "download exceeds allocation"); + let mut data = vec![0; bytes]; + let f = self + .ctx + .symbol:: i32>(b"laya_download\0")?; + self.ctx + .check(unsafe { f(data.as_mut_ptr(), self.p, bytes, self.ctx.stream) })?; + self.ctx.sync()?; + Ok(data) + } +} +impl Drop for Buffer { + fn drop(&mut self) { + let _ = self.ctx.sync(); + if let Ok(f) = self + .ctx + .symbol:: i32>(b"laya_free\0") + { + unsafe { + f(self.p); + } + } + } +} +pub struct Graph { + ctx: Rc, + p: Ptr, +} +impl Graph { + pub fn replay(&self) -> Result<()> { + let f = self + .ctx + .symbol:: i32>(b"laya_graph_run\0")?; + self.ctx.check(unsafe { f(self.p, self.ctx.stream) }) + } +} +impl Drop for Graph { + fn drop(&mut self) { + let _ = self.ctx.sync(); + if let Ok(f) = self + .ctx + .symbol:: i32>(b"laya_graph_free\0") + { + unsafe { + f(self.p); + } + } + } +} diff --git a/src/backends/cuda/tools/build.py b/src/backends/cuda/tools/build.py new file mode 100644 index 00000000..10424d27 --- /dev/null +++ b/src/backends/cuda/tools/build.py @@ -0,0 +1,75 @@ +"""Compile an exported bundle. Preserve separate TileLang/PyTorch arithmetic flags.""" + +import argparse +import hashlib +import json +import os +import subprocess +from pathlib import Path + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("bundle", type=Path) + args = parser.parse_args() + + manifest = json.loads((args.bundle / "manifest.json").read_text()) + root = Path(__file__).resolve().parents[1] + nvcc = str(Path(os.environ.get("CUDA_HOME", "/usr/local/cuda")) / "bin/nvcc") + commands = [] + objects = [] + sources = {} + + for source, fast_math in [ + (args.bundle / "generated.cu", True), + (root / "kernels/runtime.cu", False), + (root / "kernels/model_ops.cu", False), + ]: + sources[str(source)] = hashlib.sha256(source.read_bytes()).hexdigest() + obj = args.bundle / (source.stem + ".o") + objects.append(str(obj)) + flags = [ + flag + for flag in manifest["nvcc_flags"] + if fast_math or flag != "--use_fast_math" + ] + command = [ + nvcc, + *flags, + "--expt-relaxed-constexpr", + "-c", + "-Xcompiler=-fPIC", + "-O3", + *[ + arg + for directory in manifest["include_dirs"] + for arg in ["-I", directory] + ], + str(source), + "-o", + str(obj), + ] + commands.append(command) + subprocess.run(command, check=True) + + library = args.bundle / "liblaya_cuda.so" + command = [nvcc, "-shared", *objects, "-lcublas", "-lcuda", "-o", str(library)] + commands.append(command) + subprocess.run(command, check=True) + (args.bundle / "build-command.json").write_text(json.dumps(commands, indent=2)) + + build_manifest = { + "abi": 1, + "arch": "sm_90a", + "nvcc": subprocess.check_output([nvcc, "--version"], text=True), + "sources": sources, + "commands": commands, + "library_sha256": hashlib.sha256(library.read_bytes()).hexdigest(), + } + (args.bundle / "build-manifest.json").write_text( + json.dumps(build_manifest, indent=2) + ) + + +if __name__ == "__main__": + main() diff --git a/src/backends/cuda/tools/export.py b/src/backends/cuda/tools/export.py new file mode 100644 index 00000000..b1c0460d --- /dev/null +++ b/src/backends/cuda/tools/export.py @@ -0,0 +1,317 @@ +"""Build-only TileLang -> CUDA export. Runtime needs CUDA, not Python/TVM/Torch. + +Host argument stacks are inspected, including dynamic TMA extents and strides. +Unknown symbols/launch layouts fail generation instead of guessing an ABI. +""" + +import argparse +import hashlib +import importlib.util +import json +import re +import sys +from pathlib import Path + +import tilelang +from tilelang.env import CUTLASS_INCLUDE_DIR, TILELANG_TEMPLATE_PATH + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "kernels")) +import laya_tilelang as kernels + +QKV_DISPATCH = """extern "C" int laya_qkv(void** p,int B,int L,int M,cudaStream_t stream) { + if(B==1 && L<=64)return laya_qkv_short(p,B,L,M,stream); + return laya_qkv_full(p,B,L,M,stream); +} +""" + +OUT_DISPATCH = """extern "C" int laya_out(void** p,int B,int L,int M,cudaStream_t stream) { + if(B==1 && L<=64)return laya_out_short(p,B,L,M,stream); + return laya_out_full(p,B,L,M,stream); +} +""" + +SLOT = re.compile( + r"\(\(\(TVMFFIAny\*\)stack_ffi_any\)\[(\d+)\]\.v_(?:int64|ptr)\) = (.*);" +) +CALL = re.compile( + r"TVMFFIFunctionCall\((\w+?)_packed, \(TVMFFIAny\*\) stack_ffi_any, (\d+)," +) + + +def host_calls(kernel): + slots = {} + calls = [] + for line in kernel.get_host_source().splitlines(): + match = SLOT.search(line) + if match: + slots[int(match[1])] = match[2] + continue + match = CALL.search(line) + if match: + if match[1] in ("__tvm_tensormap_create_tiled", "main_kernel"): + values = [slots.get(i) for i in range(int(match[2]))] + if None in values: + raise ValueError(("missing argument", match[1], values)) + calls.append((match[1], values)) + slots = {} + return calls + + +def integer(value): + value = value.replace("(int64_t)", "").replace("(", "").replace(")", "") + return int(value) + + +def patch_geglu_static_registers(body): + """Remove fixed register reservations only from the accepted BN32 lowering.""" + expected = "1ed96990542c07b58dca419dafcc45c6163bb9b6fff04ffca5ecedb2a34e921c" + if hashlib.sha256(body.encode()).hexdigest() != expected: + raise ValueError("long GEGLU BN32 lowering changed") + for call in ( + " tl::warpgroup_reg_dealloc<24>();\n", + " tl::warpgroup_reg_alloc<240>();\n", + ): + if body.count(call) != 1: + raise ValueError("long GEGLU register calls changed") + body = body.replace(call, "", 1) + return body + + +def export(name, kernel): + source = kernel.get_kernel_source() + signature = re.search(r"void main_kernel\((.*?)\);", source, re.S)[1] + params = [param.strip() for param in signature.split(",")] + names = [param.split()[-1].lstrip("*") for param in params] + bindings = [] + for index, param in enumerate(kernel.prim_func.params): + buffer = kernel.prim_func.buffer_map[param] + ctype = { + "bfloat16": "bfloat16_t", + "float32": "float", + "int32": "int", + "int64": "int64_t", + }[str(buffer.dtype)] + bindings.append(f" auto* {buffer.name}=static_cast<{ctype}*>(p[{index}]);") + + descriptors = [] + launch = None + for callee, args in host_calls(kernel): + if callee == "main_kernel": + launch = args + continue + variable, dtype, rank, tensor = args[:4] + rank_value = integer(rank) + dtype_value = integer(dtype) + if dtype_value not in (7, 9) or not 1 <= rank_value <= 5: + raise ValueError(("unsupported TMA format", name, dtype, rank)) + dtype_enum = { + 7: "CU_TENSOR_MAP_DATA_TYPE_FLOAT32", + 9: "CU_TENSOR_MAP_DATA_TYPE_BFLOAT16", + }[dtype_value] + dims = args[4 : 4 + rank_value] + strides = args[4 + rank_value : 4 + 2 * rank_value] + box = args[4 + 2 * rank_value : 4 + 3 * rank_value] + steps = args[4 + 3 * rank_value : 4 + 4 * rank_value] + interleave, swizzle, l2, oob = map(integer, args[4 + 4 * rank_value :]) + if ( + integer(strides[0]) != {7: 4, 9: 2}[dtype_value] + or interleave != 0 + or oob != 0 + or swizzle not in range(4) + or l2 not in range(4) + ): + raise ValueError("unsupported TMA layout") + descriptors.append( + f""" alignas(64) CUtensorMap {variable}; + {{ uint64_t dims[]={{{','.join('static_cast('+v+')' for v in dims)}}}, strides[]={{{','.join('static_cast('+v+')' for v in strides[1:])}}}; + uint32_t box[]={{{','.join(box)}}}, steps[]={{{','.join(steps)}}}; + CUresult rc=cuTensorMapEncodeTiled(&{variable},{dtype_enum},{rank_value},{tensor},dims,strides,box,steps, + CU_TENSOR_MAP_INTERLEAVE_NONE,static_cast({swizzle}),static_cast({l2}),CU_TENSOR_MAP_FLOAT_OOB_FILL_NONE); + if(rc!=CUDA_SUCCESS)return 10000+static_cast(rc); }}""" + ) + + if launch is None: + raise ValueError("no launch") + # Scalar/pointer entries are exactly the recovered device signature order. + args = launch[: len(params)] + tail = launch[len(params) :] + for parameter, value in zip(names, args): + if parameter != value and parameter not in ("M", "B", "L"): + raise ValueError(("argument changed", parameter, value)) + if ( + len(tail) >= 4 + and integer(tail[-2]) == 1 + and integer(tail[-3]) == 1 + and integer(tail[-1]) > 1 + ): + grid = tail[:-4] + block = list(map(integer, tail[-4:-1])) + shared_memory = integer(tail[-1]) + else: + grid = tail[:-3] + block = list(map(integer, tail[-3:])) + shared_memory = 0 + if not 1 <= len(grid) <= 3 or block[1:] != [1, 1] or shared_memory > 227 * 1024: + raise ValueError(("launch", tail)) + if len(grid) < 3: + grid += ["1"] * (3 - len(grid)) + + symbol = "laya_" + name + "_kernel" + body = source[source.index('extern "C" __global__') :].replace( + "main_kernel", symbol + ) + if name == "geglu": + body = patch_geglu_static_registers(body) + # TileLang reuses Q_s for O_s. Its generated wait is inside the key loop, + # so zero-key rows can overwrite Q_s while the asynchronous Q load is live. + # Wait before entering producer/consumer branches, including zero iterations. + # Match the lowered structure strictly; do not silently patch a new lowering. + if name.startswith("attn_"): + q_load = re.search(r"tl::tma_load\(QKV_desc, mbarrier\[(\d+)\].*?Q_s.*?;", body) + if not q_load: + raise ValueError("attention Q TMA load changed") + end = body.index("__syncthreads();", q_load.end()) + len("__syncthreads();") + body = ( + body[:end] + + f"\n mbarrier[{q_load[1]}].wait(0); // Q load must complete even with no valid keys.\n" + + body[end:] + ) + preamble = source[: source.index('extern "C" __global__')] + + # Never inject unknown identifiers from a compiler expression into the wrapper. + allowed = ( + set(names) + | {"M", "B", "L", "int64_t"} + | { + str(kernel.prim_func.buffer_map[param].name) + for param in kernel.prim_func.params + } + ) + for _, values in host_calls(kernel): + for value in values: + for identifier in re.findall(r"\b[A-Za-z_]\w*\b", value): + if identifier not in allowed and not identifier.endswith("_desc"): + raise ValueError(("unknown host symbol", identifier)) + dispatch = "" + if name == "geglu": + dispatch = " if(B==1 && M<=64)return laya_geglu_short(p,B,L,M,stream);\n" + wrapper_name = {"qkv": "qkv_full", "out": "out_full"}.get(name, name) + wrapper = f"""extern "C" int laya_{wrapper_name}(void** p,int B,int L,int M,cudaStream_t stream) {{ + if(B<1 || B>16 || L<16 || L>512 || L%16 || M!=B*L)return -1; +{dispatch}{chr(10).join(bindings)} +{chr(10).join(descriptors)} + {symbol}<<>>({','.join(args)}); + return static_cast(cudaGetLastError()); +}} +""" + init = "" + if shared_memory >= 49152: + init = f"if(auto e=cudaFuncSetAttribute({symbol},cudaFuncAttributeMaxDynamicSharedMemorySize,{shared_memory});e!=cudaSuccess)return static_cast(e);" + metadata = { + "name": name, + "params": names, + "block": block, + "smem": shared_memory, + "grid": grid, + "source_sha256": hashlib.sha256(source.encode()).hexdigest(), + "emitted_sha256": hashlib.sha256(body.encode()).hexdigest(), + "zero_key_wait": name.startswith("attn_"), + "host_calls": host_calls(kernel), + } + return preamble, body + wrapper, init, metadata + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("output", type=Path) + parser.add_argument( + "--rope-source", + type=Path, + default=Path(__file__).resolve().parents[1] / "kernels/rope_selected.py", + ) + parser.add_argument("--probe-only", action="store_true") + args = parser.parse_args() + args.output.mkdir(parents=True, exist_ok=True) + + spec = importlib.util.spec_from_file_location("rope_selected", args.rope_source) + rope = importlib.util.module_from_spec(spec) + spec.loader.exec_module(rope) + exports = { + "rope": rope.build(16, 64, 1, 8), + "rope_original": kernels.rope_kernel(16, 64), + "qkv": kernels.gemm_kernel(3072, 1024), + "qkv_short": kernels.gemm_kernel(3072, 1024, bn=64), + "attn_full": kernels.attn_kernel(None, None, 16, 64), + } + if not args.probe_only: + exports.update( + { + "out": kernels.gemm_kernel(1024, 1024), + "out_short": kernels.gemm_kernel(1024, 1024, bm=64, bn=64), + "geglu_short": kernels.gemm_geglu_kernel(2624, 1024, bn=32), + "geglu": kernels.gemm_geglu_kernel(2624, 1024, bn=32), + "down": kernels.gemm_kernel(1024, 2624, bm=64, bn=64), + "addln": kernels.add_ln_kernel(1024), + "addln_bias": kernels.add_ln_kernel(1024, bias=True), + "ln_bias": kernels.add_ln_kernel(1024, residual=False, bias=True), + "head_in": kernels.gemm_kernel(3072, 1024, bias=True), + "head_out": kernels.gemm_kernel(1024, 1024, bias=True), + "ffn1": kernels.gemm_kernel(4096, 1024, bias=True, act="relu"), + "ffn2": kernels.gemm_kernel(1024, 4096, bias=True), + "attn_local": kernels.attn_kernel(None, None, 16, 64, window=64), + } + ) + for batch in (1, 4): + for label, window in [("full", 0), ("local", 64)]: + exports[f"attn_{label}_b{batch}_l512"] = kernels.attn_kernel( + batch, 512, 16, 64, window=window + ) + + preambles = [] + bodies = [] + inits = [] + metadata = [] + for name, kernel in exports.items(): + preamble, body, init, details = export(name, kernel) + preambles.append(preamble) + bodies.append(body) + inits.append(init) + metadata.append(details) + # Only one copy of debug helper definitions. Other headers carry include guards. + preamble = "\n".join( + dict.fromkeys( + line + for block in preambles + for line in block.splitlines() + if line.startswith("#include \n#include \n" + + preamble + + "\n" + + "\n".join(bodies) + + QKV_DISPATCH + + ("" if args.probe_only else OUT_DISPATCH) + + '\nextern "C" int laya_kernels_init(){' + + "".join(inits) + + "return 0;}\n" + ) + (args.output / "generated.cu").write_text(code) + manifest = { + "tilelang_version": tilelang.__version__, + "kernels": metadata, + "nvcc_flags": [ + "-std=c++20", + "-gencode=arch=compute_90a,code=sm_90a", + "--use_fast_math", + "-DENABLE_BF16", + ], + "include_dirs": [str(TILELANG_TEMPLATE_PATH), str(CUTLASS_INCLUDE_DIR)], + } + (args.output / "manifest.json").write_text(json.dumps(manifest, indent=2)) + print("EXPORTED", len(exports), flush=True) + + +if __name__ == "__main__": + main() diff --git a/src/backends/cuda/tools/export_tables.py b/src/backends/cuda/tools/export_tables.py new file mode 100644 index 00000000..95bbb1b9 --- /dev/null +++ b/src/backends/cuda/tools/export_tables.py @@ -0,0 +1,65 @@ +"""Build-only rotary tables, preserving official FastLaya GPU BF16 rounding.""" + +import argparse +import hashlib +import importlib.metadata +import json +from pathlib import Path + +from laya import Agent + +CHECKPOINT_ARTIFACTS = [ + "rl_agent_config.json", + "encoder/config.json", + "model.safetensors", + "tokenizer/tokenizer.json", + "tokenizer/tokenizer_config.json", +] + + +def sha256_file(path): + digest = hashlib.sha256() + with path.open("rb") as source: + for chunk in iter(lambda: source.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("checkpoint", type=Path) + parser.add_argument("bundle", type=Path) + args = parser.parse_args() + + assert importlib.metadata.version("laya") == "0.3.20", "requires laya==0.3.20" + agent = Agent(str(args.checkpoint), device="cuda", fast=False, compile=False) + assert agent.device.type == "cuda" + assert agent.accelerate(use_graphs=False, strict=True) + + args.bundle.mkdir(parents=True, exist_ok=True) + files = {} + for kind, label in [("full_attention", "full"), ("sliding_attention", "local")]: + for part, tensor in zip(["cos", "sin"], agent._fast.rope[kind]): + name = f"rope_{label}_{part}.f32" + data = tensor.cpu().numpy().tobytes() + assert len(data) == 512 * 32 * 4 + (args.bundle / name).write_bytes(data) + files[name] = hashlib.sha256(data).hexdigest() + + metadata = { + "abi": 1, + "laya": "0.3.20", + "hidden_size": 1024, + "head_dim": 64, + "max_len": 512, + "tables": files, + "checkpoint_sha256": { + name: sha256_file(args.checkpoint / name) for name in CHECKPOINT_ARTIFACTS + }, + } + (args.bundle / "tables.json").write_text(json.dumps(metadata, indent=2)) + print("exported four rotary tables") + + +if __name__ == "__main__": + main() diff --git a/src/models/laya/Cargo.toml b/src/models/laya/Cargo.toml index 0eba9200..d8a16ff5 100644 --- a/src/models/laya/Cargo.toml +++ b/src/models/laya/Cargo.toml @@ -10,10 +10,15 @@ half = "2" memmap2 = "0.9" safetensors = "0.6" serde = { version = "1", features = ["derive"] } -serde_json = "1" +serde_json = { version = "1", features = ["preserve_order", "arbitrary_precision", "raw_value"] } +tokenizers = { version = "0.23.2", default-features = false, features = ["fancy-regex"] } +sha2 = "0.10" +omni-cuda = { path = "../../backends/cuda", optional = true } +omni-runtime = { path = "../../runtime", optional = true } +tokio = { version = "1", features = ["macros", "rt-multi-thread", "net", "signal", "sync"], optional = true } +axum = { version = "0.8", optional = true } [dev-dependencies] -sha2 = "0.10" tempfile = "3" [[test]] @@ -23,3 +28,23 @@ path = "../../../tests/laya/checkpoint.rs" [[test]] name = "weights" path = "../../../tests/laya/weights.rs" + +[features] +cuda = ["dep:omni-cuda"] +serve = ["cuda", "dep:omni-runtime", "dep:tokio", "dep:axum"] + +[[test]] +name = "preprocess" +path = "../../../tests/laya/preprocess.rs" + +[[test]] +name = "packing" +path = "../../../tests/laya/packing.rs" + +[[test]] +name = "decision" +path = "../../../tests/laya/decision.rs" + +[[test]] +name = "batch" +path = "../../../tests/laya/batch.rs" diff --git a/src/models/laya/README.md b/src/models/laya/README.md index 1f27102a..5131c1d7 100644 --- a/src/models/laya/README.md +++ b/src/models/laya/README.md @@ -1,18 +1,38 @@ -# LAYA model engine +# Laya English native executor -LAYA is the first planned System1-Omni model. Its future executor follows the -[architecture contracts](../../../docs/architecture.md), with processing -orchestration and scheduling outside model execution. LAYA-specific processors -and batch adapters belong in separate modules; the executor owns weights, forward -passes, learned heads, device state, and backend-specific kernel selection. -The native target uses Rust host orchestration and backend device operations; -the existing Python worker and CPU checkpoint reader retain their current roles. +The `omni-laya` crate supports English Laya 0.3.20 text requests with Rust host +processing and a Hopper CUDA executor. The Python worker below remains available. +The pinned checkpoint is `convaiinnovations/laya@55cf4c4ebb4ebe31b2550e8bdf3bd21b99753851`. -GPU operations and kernel implementations belong in [`backends/cuda/`](../../backends/cuda/) and [`backends/metal/`](../../backends/metal/). Setup and usage examples belong in the top-level [`recipe/`](../../../recipe/) directory. +`processing::Processor` validates requests and retains response context. +`preprocess` preserves token/option order; `packing` pads questions to a +power-of-two row count and sequence lengths to multiples of 16. The executor +accepts up to 16 questions, 512 tokens per sequence and 2048 option markers. +Input-token usage excludes padding. `choice`, `score` and `noul` answers use the +checkpoint temperatures, first-option ties and four-decimal output rounding. +Only `model=english` and English language selectors are accepted; there is no +automatic language routing or image/audio/video path. -The `omni-laya` crate currently reads and checks the English Laya 0.3.20 checkpoint. `Config::load` validates the architecture and temperatures; `Weights` checks tensor names and shapes and converts FP32, FP16 and BF16 values. `checkpoint_tensors()` lists the 206 expected tensors. Each backend chooses its own storage precision. +The model owns all 206 checkpoint tensors, 28 ModernBERT encoder layers, two +decision transformer layers, the scorer and action head. Residuals/norm weights +are FP32; token embeddings are FP16, and projection weights and GPU activations are BF16. Graphs capture only +Encoder/Decision and are cached by padded shape (four entries, 512 MiB workspace +budget). Scorer/action head and copyback run outside Graph. Complete-Graph and +continuous batching are not implemented. -Keep checkpoint files unchanged while `Weights` holds a read-only memory mapping. This crate does not yet execute inference. +The native worker reuses `omni-runtime::SerialScheduler` for one complete request +per admission. A dedicated thread owns CUDA's non-Send state; a rendezvous channel +transports admitted work without another pending queue. Cancellation after +dispatch retains admission and model resources until device work and readback +finish. CUDA failure stops this executor; `/health` returns 503. A real warmup +finishes before the HTTP listener binds. + +`Config::load` checks architecture and temperatures; `Weights` preserves the +main-branch inventory and conversion checks. Keep checkpoint files immutable +while mapped. Bundle/table/checkpoint hashes are checked before CUDA loading. + +See the [CUDA setup and worker recipe](../../../recipe/laya/native/README.md) +and [measured scope](../../../recipe/laya/native/VALIDATION.md). ## CPU checks @@ -32,7 +52,7 @@ These two CPU tests check all 206 tensor names and shapes, 618 conversion hashes ## Python worker The Python worker serves LAYA through laya-serve on CPU and Apple Silicon (PyTorch MPS, -validated on an M1 Pro and, by another contributor, an M5). No native CUDA or Metal backend yet. +validated on an M1 Pro and, by another contributor, an M5). The native CUDA worker is separate; native Metal remains unimplemented. - [`src/frontend/laya_mps.py`](../../frontend/laya_mps.py): the HTTP worker. laya-serve (`laya[serve]==0.3.20`) with its request handling unchanged, started as `PYTHONPATH=src python -m frontend.laya_mps --device mps`. diff --git a/src/models/laya/src/artifacts.rs b/src/models/laya/src/artifacts.rs new file mode 100644 index 00000000..70185dc6 --- /dev/null +++ b/src/models/laya/src/artifacts.rs @@ -0,0 +1,78 @@ +//! Bind a compiled bundle to its read-only checkpoint before CUDA startup. +use anyhow::{Context, Result, ensure}; +use sha2::{Digest, Sha256}; +use std::{fs, io::Read, path::Path}; + +pub const CHECKPOINT_ARTIFACTS: [&str; 5] = [ + "rl_agent_config.json", + "encoder/config.json", + "model.safetensors", + "tokenizer/tokenizer.json", + "tokenizer/tokenizer_config.json", +]; + +fn sha256_file(path: &Path) -> Result { + let mut file = fs::File::open(path).with_context(|| format!("open {}", path.display()))?; + let mut digest = Sha256::new(); + let mut buffer = [0u8; 64 * 1024]; + loop { + let count = file + .read(&mut buffer) + .with_context(|| format!("hash {}", path.display()))?; + if count == 0 { + break; + } + digest.update(&buffer[..count]); + } + Ok(format!("{:x}", digest.finalize())) +} + +pub fn validate_bundle(checkpoint: &Path, bundle: &Path) -> Result<()> { + let tables: serde_json::Value = serde_json::from_slice(&fs::read(bundle.join("tables.json"))?)?; + let build: serde_json::Value = + serde_json::from_slice(&fs::read(bundle.join("build-manifest.json"))?)?; + ensure!( + tables["abi"] == 1 + && tables["laya"] == "0.3.20" + && tables["hidden_size"] == 1024 + && tables["head_dim"] == 64 + && tables["max_len"] == 512 + && build["abi"] == 1 + && build["arch"] == "sm_90a", + "unsupported CUDA bundle" + ); + let check = |path: std::path::PathBuf, expected: Option<&str>| -> Result<()> { + let hash = sha256_file(&path)?; + ensure!( + expected == Some(hash.as_str()), + "bundle hash mismatch: {}", + path.display() + ); + Ok(()) + }; + for name in CHECKPOINT_ARTIFACTS { + let expected = tables["checkpoint_sha256"][name] + .as_str() + .with_context(|| { + format!("missing checkpoint hash for {name}; regenerate tables.json") + })?; + check(checkpoint.join(name), Some(expected))?; + } + for name in [ + "rope_full_cos.f32", + "rope_full_sin.f32", + "rope_local_cos.f32", + "rope_local_sin.f32", + ] { + check(bundle.join(name), tables["tables"][name].as_str())?; + } + check( + bundle.join("liblaya_cuda.so"), + build["library_sha256"].as_str(), + )?; + Ok(()) +} + +#[cfg(test)] +#[path = "../../../../tests/laya/artifacts.rs"] +mod tests; diff --git a/src/models/laya/src/bin/laya-pack.rs b/src/models/laya/src/bin/laya-pack.rs new file mode 100644 index 00000000..9e481b96 --- /dev/null +++ b/src/models/laya/src/bin/laya-pack.rs @@ -0,0 +1,16 @@ +fn main() -> anyhow::Result<()> { + use anyhow::Context; + use omni_laya::preprocess::{Preprocessor, Request}; + use std::io::{self, BufRead}; + let args: Vec<_> = std::env::args().collect(); + let checkpoint = std::path::Path::new(args.get(1).context("usage: laya-pack CHECKPOINT")?); + let preprocessor = Preprocessor::load(&checkpoint.join("tokenizer/tokenizer.json"))?; + for line in io::stdin().lock().lines() { + let request = Request::from_json(&line?)?; + println!( + "{}", + serde_json::to_string(&preprocessor.prepare(&request)?)? + ); + } + Ok(()) +} diff --git a/src/models/laya/src/bin/laya-run.rs b/src/models/laya/src/bin/laya-run.rs new file mode 100644 index 00000000..d9a37afc --- /dev/null +++ b/src/models/laya/src/bin/laya-run.rs @@ -0,0 +1,63 @@ +#[cfg(feature = "cuda")] +fn main() -> anyhow::Result<()> { + use anyhow::Context; + use omni_laya::{model::Model, processing::Processor}; + use std::{ + io::{self, BufRead}, + path::PathBuf, + time::Instant, + }; + let args: Vec<_> = std::env::args().collect(); + let checkpoint = PathBuf::from( + args.get(1) + .context("usage: laya-run CHECKPOINT CUDA_BUNDLE [--eager] [--original-rope]")?, + ); + let bundle = PathBuf::from(args.get(2).context("missing CUDA bundle")?); + let pre = Processor::load(&checkpoint)?; + let mut model = Model::load( + &checkpoint, + &bundle, + !args.iter().any(|s| s == "--eager"), + args.iter().any(|s| s == "--original-rope"), + )?; + eprintln!("READY native Laya (Rust + CUDA)"); + for line in io::stdin().lock().lines() { + let line = line?; + let start = Instant::now(); + let prepared = pre.prepare(line.as_bytes()); + let prepared = match prepared { + Ok(prepared) => prepared, + Err(e) => { + println!("{}", serde_json::json!({"error":format!("{e:#}")})); + eprintln!( + "engine_wall_ms={:.6}", + start.elapsed().as_secs_f64() * 1000.0 + ); + continue; + } + }; + // Only client input errors are recoverable. A native failure may poison + // the CUDA context, so never submit another request after infer fails. + let (logits, actions) = model + .infer(&prepared.inputs) + .context("native inference failed")?; + if std::env::var_os("LAYA_RAW_LOGITS").is_some() { + eprintln!("raw_logits={logits:?} raw_actions={actions:?}"); + } + let value = prepared + .context + .finish(logits, actions) + .context("native output decoding failed")?; + println!("{}", serde_json::to_string(&value)?); + eprintln!( + "engine_wall_ms={:.6}", + start.elapsed().as_secs_f64() * 1000.0 + ); + } + Ok(()) +} +#[cfg(not(feature = "cuda"))] +fn main() { + eprintln!("laya-run requires --features cuda; use laya-pack for CPU input validation"); + std::process::exit(2); +} diff --git a/src/models/laya/src/bin/omni-laya.rs b/src/models/laya/src/bin/omni-laya.rs new file mode 100644 index 00000000..648fa195 --- /dev/null +++ b/src/models/laya/src/bin/omni-laya.rs @@ -0,0 +1,34 @@ +#[cfg(feature = "serve")] +#[tokio::main] +async fn main() -> anyhow::Result<()> { + use anyhow::{Context, ensure}; + use omni_laya::serve::{Engine, router}; + use std::{path::PathBuf, sync::Arc}; + let checkpoint = + PathBuf::from(std::env::var_os("LAYA_CHECKPOINT").context("set LAYA_CHECKPOINT")?); + let bundle = + PathBuf::from(std::env::var_os("LAYA_CUDA_BUNDLE").context("set LAYA_CUDA_BUNDLE")?); + let engine = Arc::new(Engine::load(&checkpoint, &bundle).await?); + let warmup = br#"{"model":"english","state":"Please refund the duplicate charge.","questions":{"refund":{"type":"noul","instructions":"Does the customer ask for a refund?"}}}"#; + ensure!( + engine.decide(warmup).await.status().is_success(), + "warmup failed" + ); + let host = std::env::var("LAYA_HOST").unwrap_or_else(|_| "127.0.0.1".into()); + let port: u16 = std::env::var("LAYA_PORT") + .map_or(Ok(8000), |s| s.parse()) + .context("LAYA_PORT")?; + let listener = tokio::net::TcpListener::bind((host.as_str(), port)).await?; + println!("listening on {host}:{port}"); + axum::serve(listener, router(engine)) + .with_graceful_shutdown(async { + let _ = tokio::signal::ctrl_c().await; + }) + .await?; + Ok(()) +} +#[cfg(not(feature = "serve"))] +fn main() { + eprintln!("omni-laya requires --features serve"); + std::process::exit(2); +} diff --git a/src/models/laya/src/decision.rs b/src/models/laya/src/decision.rs new file mode 100644 index 00000000..28feb46c --- /dev/null +++ b/src/models/laya/src/decision.rs @@ -0,0 +1,154 @@ +//! Decode Laya's raw option and action logits without a GPU or HTTP response wrapper. +use crate::{config::AgentConfig, preprocess::Prepared}; +use anyhow::{Result, bail, ensure}; +use serde_json::{Map, Value, json}; + +fn round4(value: f64) -> f64 { + // Match Python round(value, 4), without rounding an intermediate value * 10000. + format!("{value:.4}").parse().unwrap() +} + +fn softmax(values: &[f32]) -> Vec { + let max = values.iter().copied().fold(f32::NEG_INFINITY, f32::max); + let mut probabilities: Vec<_> = values.iter().map(|v| (v - max).exp()).collect(); + let sum: f32 = probabilities.iter().sum(); + for probability in &mut probabilities { + *probability /= sum; + } + probabilities +} + +/// Rows follow `prepared.questions`; each option row follows its marker order. +/// Action rows contain two raw logits, with the first meaning "act". +pub fn decode( + prepared: &Prepared, + config: &AgentConfig, + logits: &[Vec], + action_logits: &[[f32; 2]], +) -> Result> { + ensure!( + logits.len() == prepared.questions.len() && action_logits.len() == logits.len(), + "output row count mismatch" + ); + ensure!( + config.temperature.len() == 3 + && config + .temperature + .iter() + .chain(config.temperature_by_options.values()) + .all(|t| t.is_finite() && *t > 0.0), + "invalid temperatures" + ); + let mut answers = Map::new(); + for ((question, raw), action) in prepared.questions.iter().zip(logits).zip(action_logits) { + let k = question.markers.len(); + ensure!( + k > 0 && raw.len() == k && raw.iter().chain(action).all(|v| v.is_finite()), + "question {:?}: invalid model logits", + question.id + ); + let (qtype, keys): (_, Vec) = match question.kind.as_str() { + "choice" => { + let criteria = question.criteria.as_object(); + ensure!( + criteria.is_some_and(|c| c.len() == k), + "invalid choice criteria" + ); + (0, criteria.unwrap().keys().cloned().collect()) + } + "score" => { + ensure!( + question.criteria.as_array().is_some_and(|c| c.len() == k), + "invalid score criteria" + ); + (1, (0..k).map(|i| i.to_string()).collect()) + } + "noul" => { + ensure!(k == 2, "noul requires two options"); + (2, Vec::new()) + } + _ => bail!("unknown question type {:?}", question.kind), + }; + ensure!(question.qtype == qtype as i64, "question type ID mismatch"); + ensure!(!answers.contains_key(&question.id), "duplicate question ID"); + let bucket = match k { + 1..=2 => "2", + 3..=5 => "3-5", + 6..=10 => "6-10", + _ => "11+", + }; + let temperature = config + .temperature_by_options + .get(&format!("{}:{bucket}", question.kind)) + .copied() + .unwrap_or(config.temperature[qtype]) + .clamp(0.5, 5.0); + let scaled: Vec<_> = raw.iter().map(|v| v / temperature).collect(); + ensure!( + scaled.iter().all(|v| v.is_finite()), + "scaled logits overflow" + ); + let probabilities = softmax(&scaled); + // Strict comparison keeps the first option on a tie, as NumPy does. + let mut winner = 0; + for i in 1..k { + if probabilities[i] > probabilities[winner] { + winner = i; + } + } + let confidence = if question.kind == "noul" { + f64::from(probabilities[1]).max(1.0 - f64::from(probabilities[1])) + } else if k == 1 { + 1.0 + } else { + let entropy: f32 = probabilities + .iter() + .map(|p| -p * p.clamp(1e-12, 1.0).ln()) + .sum(); + f64::from((1.0 - entropy / (k as f64).ln() as f32).clamp(0.0, 1.0)) + }; + let mut answer = json!({ + "type": question.kind, + "confidence": round4(confidence), + "answer_confidence": round4(f64::from(probabilities[winner])), + "action": {"act_probability": round4(f64::from(softmax(action)[0]))} + }); + if question.kind == "noul" { + answer["noul"] = json!(round4(f64::from(probabilities[1]))); + } else { + answer["probabilities"] = Value::Object( + keys.iter() + .zip(&probabilities) + .map(|(key, probability)| (key.clone(), json!(round4(f64::from(*probability))))) + .collect(), + ); + if question.kind == "choice" { + answer["choice"] = json!(keys[winner]); + } else { + answer["score"] = json!(round4( + probabilities + .iter() + .enumerate() + .map(|(i, p)| i as f64 * f64::from(*p)) + .sum() + )); + answer["legend"] = Value::Object( + question + .criteria + .as_array() + .unwrap() + .iter() + .enumerate() + .map(|(i, value)| (i.to_string(), value.clone())) + .collect(), + ); + } + } + answers.insert(question.id.clone(), answer); + } + Ok(answers) +} + +#[cfg(test)] +#[path = "../../../../tests/laya/unit/decision.rs"] +mod tests; diff --git a/src/models/laya/src/executor.rs b/src/models/laya/src/executor.rs new file mode 100644 index 00000000..76acae27 --- /dev/null +++ b/src/models/laya/src/executor.rs @@ -0,0 +1,126 @@ +//! Keep CUDA's Rc state on one thread; admission belongs to the shared runtime. +use std::{ + path::{Path, PathBuf}, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + mpsc, + }, + thread, +}; + +use anyhow::{Context, Result, anyhow}; +use omni_runtime::SerialScheduler; + +use crate::{ + model::{Model, ModelOutput}, + packing::Batch, +}; + +struct Job { + inputs: Batch, + reply: mpsc::Sender>, +} + +struct Worker { + sender: Option>, + thread: Option>, + ready: Arc, +} + +impl Drop for Worker { + fn drop(&mut self) { + drop(self.sender.take()); + if let Some(thread) = self.thread.take() { + let _ = thread.join(); + } + } +} + +pub struct Executor { + worker: Arc, +} + +impl Executor { + pub async fn load(checkpoint: &Path, bundle: &Path) -> Result { + let (checkpoint, bundle) = (checkpoint.to_path_buf(), bundle.to_path_buf()); + tokio::task::spawn_blocking(move || Self::load_blocking(checkpoint, bundle)).await? + } + + fn load_blocking(checkpoint: PathBuf, bundle: PathBuf) -> Result { + // Rendezvous transport has no pending queue; SerialScheduler admits one request. + let (sender, receiver) = mpsc::sync_channel::(0); + let (loaded, initialized) = mpsc::channel(); + let ready = Arc::new(AtomicBool::new(false)); + let worker_ready = ready.clone(); + let thread = thread::Builder::new() + .name("laya-cuda".into()) + .spawn(move || { + let mut model = match Model::load(&checkpoint, &bundle, true, false) { + Ok(model) => model, + Err(e) => { + let _ = loaded.send(Err(format!("{e:#}"))); + return; + } + }; + worker_ready.store(true, Ordering::Release); + if loaded.send(Ok(())).is_err() { + return; + } + while let Ok(job) = receiver.recv() { + let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + model.infer(&job.inputs) + })); + match result { + Ok(Ok(output)) => { + let _ = job.reply.send(Ok(output)); + } + failed => { + worker_ready.store(false, Ordering::Release); + // Drop synchronizes outstanding CUDA work before the caller releases admission. + drop(model); + let error = match failed { + Ok(Err(e)) => e, + _ => anyhow!("CUDA executor panicked"), + }; + let _ = job.reply.send(Err(error)); + return; + } + } + } + worker_ready.store(false, Ordering::Release); + })?; + let worker = Arc::new(Worker { + sender: Some(sender), + thread: Some(thread), + ready, + }); + initialized + .recv() + .context("CUDA worker stopped during startup")? + .map_err(anyhow::Error::msg)?; + Ok(Self { worker }) + } + + pub fn ready(&self) -> bool { + self.worker.ready.load(Ordering::Acquire) + } + + pub async fn execute(&self, scheduler: &SerialScheduler, inputs: Batch) -> Result { + let worker = self.worker.clone(); + scheduler + .run(move || { + let (reply, result) = mpsc::channel(); + worker + .sender + .as_ref() + .context("CUDA worker unavailable")? + .send(Job { inputs, reply }) + .map_err(|_| anyhow!("CUDA worker unavailable"))?; + result + .recv() + .context("CUDA worker stopped during execution")? + }) + .await + } +} diff --git a/src/models/laya/src/lib.rs b/src/models/laya/src/lib.rs index fbc136f4..7db9d9ad 100644 --- a/src/models/laya/src/lib.rs +++ b/src/models/laya/src/lib.rs @@ -1,2 +1,14 @@ +pub mod artifacts; pub mod config; +pub mod decision; +pub mod packing; +pub mod preprocess; +pub mod processing; pub mod weights; + +#[cfg(feature = "serve")] +pub mod executor; +#[cfg(feature = "cuda")] +pub mod model; +#[cfg(feature = "serve")] +pub mod serve; diff --git a/src/models/laya/src/model.rs b/src/models/laya/src/model.rs new file mode 100644 index 00000000..ba25a769 --- /dev/null +++ b/src/models/laya/src/model.rs @@ -0,0 +1,591 @@ +//! Single-GPU Laya executor. All CUDA buffers and graphs remain on the owning worker thread. +use crate::{config::Config, packing::Batch, weights::Weights}; +use anyhow::{Context, Result, ensure}; +use half::bf16; +use omni_cuda::{Buffer, Cuda, Graph, Ptr}; +use std::{ + collections::{HashMap, VecDeque}, + fs, + path::Path, +}; +const D: usize = 1024; +pub type ModelOutput = (Vec>, Vec<[f32; 2]>); +fn storage_dtype(name: &str) -> &'static str { + if name == "encoder.embeddings.tok_embeddings.weight" { + "f16" + } else if name.starts_with("scorer.0.") + || name == "temperature" + || name.contains("norm") + || (name.starts_with("head.layers.") && name.ends_with("bias")) + { + "f32" + } else { + "bf16" + } +} +fn bytes16(v: &[u16]) -> Vec { + v.iter().flat_map(|x| x.to_le_bytes()).collect() +} +fn bytes32(v: &[f32]) -> Vec { + v.iter().flat_map(|x| x.to_le_bytes()).collect() +} +fn i32bytes(v: &[i32]) -> Vec { + v.iter().flat_map(|x| x.to_le_bytes()).collect() +} +fn i64bytes(v: &[i64]) -> Vec { + v.iter().flat_map(|x| x.to_le_bytes()).collect() +} +fn decode_bf16(v: &[u8]) -> Vec { + v.as_chunks::<2>() + .0 + .iter() + .map(|x| bf16::from_bits(u16::from_le_bytes([x[0], x[1]])).to_f32()) + .collect() +} + +type Linear = unsafe extern "C" fn(Ptr, Ptr, Ptr, Ptr, Ptr, i32, i32, i32, i32, Ptr) -> i32; +struct Blas { + cuda: Cuda, + p: Ptr, +} +impl Blas { + fn new(cuda: &Cuda) -> Result { + let mut p = std::ptr::null_mut(); + unsafe { + let f = + cuda.symbol:: i32>(b"laya_blas_create\0")?; + cuda.check(f(&mut p, cuda.stream()))?; + } + Ok(Self { + cuda: cuda.clone(), + p, + }) + } + #[allow(clippy::too_many_arguments)] // Mirrors the checked GEMM boundary. + fn linear( + &self, + a: &Buffer, + w: &Buffer, + bias: &Buffer, + out: &Buffer, + rows: usize, + n: usize, + k: usize, + gelu: bool, + ) -> Result<()> { + ensure!( + a.bytes() >= rows * k * 2 + && w.bytes() == n * k * 2 + && bias.bytes() == n * 2 + && out.bytes() >= rows * n * 2, + "linear buffer shape mismatch" + ); + unsafe { + let f = self.cuda.symbol::(b"laya_linear\0")?; + self.cuda.check(f( + self.p, + a.ptr(), + w.ptr(), + bias.ptr(), + out.ptr(), + rows as i32, + n as i32, + k as i32, + gelu as i32, + self.cuda.stream(), + )) + } + } +} +impl Drop for Blas { + fn drop(&mut self) { + let _ = self.cuda.sync(); + unsafe { + if let Ok(f) = self + .cuda + .symbol:: i32>(b"laya_blas_free\0") + { + f(self.p); + } + } + } +} + +struct Workspace { + // Destruction order matters: destroy the graph before any referenced allocation. + graph: Option, + b: usize, + l: usize, + bytes: usize, + ids: Buffer, + lens: Buffer, + types: Buffer, + x: Buffer, + y: Buffer, + qkv: Buffer, + o: Buffer, + g: Buffer, + ff: Buffer, + indices: Buffer, + offsets: Buffer, + markers: Buffer, + scored: Buffer, + logits: Buffer, + features: Buffer, + action_hidden: Buffer, + actions: Buffer, +} +impl Workspace { + fn new(c: &Cuda, b: usize, l: usize) -> Result { + let m = b * l; + let mut bytes = 0; + let mut alloc = |n| { + bytes += n; + c.alloc(n) + }; + Ok(Self { + graph: None, + b, + l, + ids: alloc(m * 8)?, + lens: alloc(b * 4)?, + types: alloc(b * 8)?, + x: alloc(m * D * 4)?, + y: alloc(m * D * 2)?, + qkv: alloc(m * D * 6)?, + o: alloc(m * D * 2)?, + g: alloc(m * 2624 * 2)?, + ff: alloc(m * 4096 * 2)?, + indices: alloc(2048 * 4)?, + offsets: alloc(17 * 4)?, + markers: alloc(2048 * D * 2)?, + scored: alloc(2048 * D * 2)?, + logits: alloc(2048 * 2)?, + features: alloc(16 * 1028 * 2)?, + action_hidden: alloc(16 * 256 * 2)?, + actions: alloc(16 * 2 * 2)?, + bytes, + }) + } +} + +pub struct Model { + pub config: Config, + cuda: Cuda, + blas: Blas, + weights: HashMap, + cache: VecDeque, + graphs: bool, + original_rope: bool, +} +impl Drop for Model { + fn drop(&mut self) { + let _ = self.cuda.sync(); + self.cache.clear(); + } +} +impl Model { + pub fn load( + checkpoint: &Path, + bundle: &Path, + graphs: bool, + original_rope: bool, + ) -> Result { + let config = Config::load(checkpoint)?; + crate::artifacts::validate_bundle(checkpoint, bundle)?; + // SAFETY: bundle is an explicit trusted build artifact supplied by the operator. + let cuda = unsafe { Cuda::load(&bundle.join("liblaya_cuda.so")) }?; + let blas = Blas::new(&cuda)?; + let source = Weights::open(&checkpoint.join("model.safetensors"))?; + let mut weights = HashMap::new(); + let verify_weights = std::env::var_os("LAYA_VERIFY_WEIGHTS").is_some(); + let upload = |name: &str, data: &[u8]| -> Result { + let buffer = cuda + .upload(data) + .with_context(|| format!("upload {name}"))?; + if verify_weights { + ensure!( + buffer + .read(data.len()) + .with_context(|| format!("read back {name}"))? + == data, + "resident weight bytes mismatch: {name}" + ); + } + Ok(buffer) + }; + let mut add = |name: &str, shape: &[usize], dtype: &str| -> Result<()> { + let data = match dtype { + "f32" => bytes32(&source.f32(name, shape)?), + "f16" => bytes16(&source.f16(name, shape)?), + _ => bytes16(&source.bf16(name, shape)?), + }; + weights.insert(name.to_owned(), upload(name, &data)?); + Ok(()) + }; + for spec in crate::weights::checkpoint_tensors() { + add(&spec.name, &spec.shape, storage_dtype(&spec.name))?; + } + // Check only source tensors here, before adding synthetic buffers/tables. + source.validate_names(weights.keys().map(String::as_str))?; + for n in [D, 3 * D, 4 * D] { + let key = format!("zeros.{n}"); + weights.insert(key.clone(), upload(&key, &vec![0; n * 4])?); + } + for kind in ["full", "local"] { + for part in ["cos", "sin"] { + let key = format!("rope_{kind}_{part}"); + let data = fs::read(bundle.join(format!("{key}.f32")))?; + ensure!(data.len() == 512 * 32 * 4, "invalid rotary table size"); + weights.insert(key.clone(), upload(&key, &data)?); + } + } + if verify_weights { + eprintln!( + "LAYA_VERIFY_WEIGHTS verified {} resident buffers", + weights.len() + ); + } + Ok(Self { + config, + cuda, + blas, + weights, + cache: VecDeque::new(), + graphs, + original_rope, + }) + } + fn w(&self, n: &str) -> &Buffer { + &self.weights[n] + } + fn encode(&self, s: &Workspace) -> Result<()> { + let (b, l) = (s.b, s.l); + let z = self.w("zeros.1024").ptr(); + let attention = |label: &str| { + if l == 512 && (b == 1 || b == 4) { + format!("attn_{label}_b{b}_l512") + } else { + format!("attn_{label}") + } + }; + // All pointers refer to checked fixed-shape, resident allocations in this worker. + let call = |name: &str, args: &[Ptr]| unsafe { self.cuda.launch(name, args, b, l) }; + call( + "embed", + &[ + s.ids.ptr(), + self.w("encoder.embeddings.tok_embeddings.weight").ptr(), + self.w("encoder.embeddings.norm.weight").ptr(), + s.x.ptr(), + s.y.ptr(), + ], + )?; + self.dump("embedding", &s.x, false)?; + for i in 0..28 { + let p = format!("encoder.layers.{i}"); + let w = |n: &str| self.w(&format!("{p}.{n}")).ptr(); + call( + "qkv", + &[ + s.y.ptr(), + w("attn.Wqkv.weight"), + self.w("zeros.3072").ptr(), + s.qkv.ptr(), + ], + )?; + let kind = if i % 3 == 0 { "full" } else { "local" }; + call( + if self.original_rope { + "rope_original" + } else { + "rope" + }, + &[ + s.qkv.ptr(), + self.w(&format!("rope_{kind}_cos")).ptr(), + self.w(&format!("rope_{kind}_sin")).ptr(), + ], + )?; + call( + &attention(if i % 3 == 0 { "full" } else { "local" }), + &[s.qkv.ptr(), s.lens.ptr(), s.o.ptr()], + )?; + call("out", &[s.o.ptr(), w("attn.Wo.weight"), z, s.y.ptr()])?; + call( + "addln", + &[s.x.ptr(), s.y.ptr(), w("mlp_norm.weight"), z, s.y.ptr()], + )?; + call("geglu", &[s.y.ptr(), w("mlp.Wi.weight"), s.g.ptr()])?; + call("down", &[s.g.ptr(), w("mlp.Wo.weight"), z, s.y.ptr()])?; + let next = if i < 27 { + self.w(&format!("encoder.layers.{}.attn_norm.weight", i + 1)) + } else { + self.w("encoder.final_norm.weight") + }; + call("addln", &[s.x.ptr(), s.y.ptr(), next.ptr(), z, s.y.ptr()])?; + if [0, 1, 2, 27].contains(&i) { + self.dump(&format!("encoder{i}_residual"), &s.x, false)?; + self.dump(&format!("encoder{i}_normalized"), &s.y, true)?; + } + } + call( + "type", + &[ + s.y.ptr(), + self.w("type_emb.weight").ptr(), + s.types.ptr(), + s.x.ptr(), + ], + )?; + for i in 0..2 { + let p = format!("head.layers.{i}"); + let w = |n: &str| self.w(&format!("{p}.{n}")).ptr(); + call( + "ln_bias", + &[ + s.x.ptr(), + s.y.ptr(), + w("norm1.weight"), + w("norm1.bias"), + s.y.ptr(), + ], + )?; + call( + "head_in", + &[ + s.y.ptr(), + w("self_attn.in_proj_weight"), + w("self_attn.in_proj_bias"), + s.qkv.ptr(), + ], + )?; + call(&attention("full"), &[s.qkv.ptr(), s.lens.ptr(), s.o.ptr()])?; + call( + "head_out", + &[ + s.o.ptr(), + w("self_attn.out_proj.weight"), + w("self_attn.out_proj.bias"), + s.y.ptr(), + ], + )?; + call( + "addln_bias", + &[ + s.x.ptr(), + s.y.ptr(), + w("norm2.weight"), + w("norm2.bias"), + s.y.ptr(), + ], + )?; + call( + "ffn1", + &[ + s.y.ptr(), + w("linear1.weight"), + w("linear1.bias"), + s.ff.ptr(), + ], + )?; + call( + "ffn2", + &[ + s.ff.ptr(), + w("linear2.weight"), + w("linear2.bias"), + s.y.ptr(), + ], + )?; + call("residual", &[s.x.ptr(), s.y.ptr()])?; + } + Ok(()) + } + fn dump(&self, name: &str, buffer: &Buffer, bf: bool) -> Result<()> { + if !self.graphs + && let Ok(dir) = std::env::var("LAYA_DUMP_DIR") + { + fs::create_dir_all(&dir)?; + let data = buffer.read(buffer.bytes())?; + fs::write( + Path::new(&dir).join(format!("{name}.f32")), + if bf { + bytes32(&decode_bf16(&data)) + } else { + data + }, + )?; + } + Ok(()) + } + pub fn infer(&mut self, batch: &Batch) -> Result { + if batch.markers.is_empty() { + return Ok((Vec::new(), Vec::new())); + } + ensure!( + batch.b <= 16 + && batch.l <= 512 + && batch.input_ids.iter().all(|i| *i >= 0 && *i < 50368), + "invalid packed input" + ); + let n = batch.markers.len(); + ensure!( + batch.b == n.next_power_of_two() + && batch.l >= 16 + && batch.l.is_multiple_of(16) + && batch.input_ids.len() == batch.b * batch.l + && batch.lens.len() == batch.b + && batch.qtypes.len() == batch.b, + "inconsistent packed dimensions" + ); + for i in 0..batch.b { + ensure!((0..=2).contains(&batch.qtypes[i]), "invalid question type"); + if i < n { + ensure!( + batch.lens[i] > 0 + && batch.lens[i] as usize <= batch.l + && !batch.markers[i].is_empty() + && batch.markers[i].iter().all(|m| *m < batch.lens[i] as usize), + "invalid sequence/marker bounds" + ); + } else { + ensure!(batch.lens[i] == 0, "dummy row must have zero length"); + } + } + ensure!( + batch.markers.iter().map(Vec::len).sum::() <= 2048, + "too many markers" + ); + let found = self + .cache + .iter() + .position(|s| s.b == batch.b && s.l == batch.l); + let mut s = if let Some(i) = found { + self.cache.remove(i).unwrap() + } else { + Workspace::new(&self.cuda, batch.b, batch.l)? + }; + s.ids.write(&i64bytes(&batch.input_ids))?; + s.lens.write(&i32bytes(&batch.lens))?; + s.types.write(&i64bytes(&batch.qtypes))?; + if self.graphs { + if s.graph.is_none() { + self.encode(&s)?; + self.encode(&s)?; + self.cuda.sync()?; + // Graph uses weights owned by self and allocations owned by s; self clears cache first on Drop. + s.graph = Some(unsafe { self.cuda.capture(|| self.encode(&s)) }?); + } + s.graph.as_ref().unwrap().replay()?; + } else { + self.encode(&s)?; + } + if let Ok(path) = std::env::var("LAYA_DUMP_HIDDEN") { + fs::write(path, s.x.read(batch.b * batch.l * D * 4)?)?; + } + let mut indices = Vec::new(); + let mut offsets = vec![0i32]; + for (i, markers) in batch.markers.iter().enumerate() { + for &m in markers { + ensure!(m < batch.l, "marker outside sequence"); + indices.push((i * batch.l + m) as i32); + } + offsets.push(indices.len() as i32); + } + let rows = indices.len(); + ensure!(rows <= 2048, "too many markers"); + s.indices.write(&i32bytes(&indices))?; + s.offsets.write(&i32bytes(&offsets))?; + unsafe { + self.cuda.launch_rows( + "gather", + &[ + s.x.ptr(), + s.indices.ptr(), + self.w("scorer.0.weight").ptr(), + self.w("scorer.0.bias").ptr(), + s.markers.ptr(), + ], + 1, + 1, + rows, + )?; + } + self.blas.linear( + &s.markers, + self.w("scorer.1.weight"), + self.w("scorer.1.bias"), + &s.scored, + rows, + D, + D, + true, + )?; + self.blas.linear( + &s.scored, + self.w("scorer.3.weight"), + self.w("scorer.3.bias"), + &s.logits, + rows, + 1, + D, + false, + )?; + let n = batch.markers.len(); + unsafe { + self.cuda.launch_rows( + "features", + &[s.x.ptr(), s.logits.ptr(), s.offsets.ptr(), s.features.ptr()], + n, + batch.l, + rows, + )?; + } + self.blas.linear( + &s.features, + self.w("act_head.0.weight"), + self.w("act_head.0.bias"), + &s.action_hidden, + n, + 256, + 1028, + true, + )?; + self.blas.linear( + &s.action_hidden, + self.w("act_head.2.weight"), + self.w("act_head.2.bias"), + &s.actions, + n, + 2, + 256, + false, + )?; + let raw = decode_bf16(&s.logits.read(rows * 2)?); + let acts = decode_bf16(&s.actions.read(n * 4)?); + let logits = offsets + .windows(2) + .map(|w| raw[w[0] as usize..w[1] as usize].to_vec()) + .collect(); + let actions = acts + .as_chunks::<2>() + .0 + .iter() + .map(|x| [x[0], x[1]]) + .collect(); + while self.cache.len() >= 4 + || self.cache.iter().map(|s| s.bytes).sum::() + s.bytes > 512 * 1024 * 1024 + { + if self.cache.pop_front().is_none() { + break; + } + } + self.cache.push_back(s); + Ok((logits, actions)) + } +} + +#[cfg(test)] +#[path = "../../../../tests/laya/model.rs"] +mod tests; diff --git a/src/models/laya/src/packing.rs b/src/models/laya/src/packing.rs new file mode 100644 index 00000000..68a0601b --- /dev/null +++ b/src/models/laya/src/packing.rs @@ -0,0 +1,65 @@ +//! Assemble one request into the padded layout consumed by the CUDA executor. +use anyhow::{Result, ensure}; +use serde::Serialize; + +use crate::preprocess::Prepared; + +#[derive(Debug, Serialize)] +pub struct Batch { + pub b: usize, + pub l: usize, + pub input_ids: Vec, + pub lens: Vec, + pub qtypes: Vec, + pub markers: Vec>, +} + +pub fn pack(prepared: &Prepared) -> Result { + let n = prepared.questions.len(); + ensure!(n <= 16, "at most 16 questions per CUDA request"); + ensure!( + prepared + .questions + .iter() + .map(|q| q.markers.len()) + .sum::() + <= 2048, + "at most 2048 option markers per CUDA request" + ); + let b = if n == 0 { 0 } else { n.next_power_of_two() }; + let max_l = prepared + .questions + .iter() + .map(|q| q.ids.len()) + .max() + .unwrap_or(0); + let alignment = if max_l <= 256 { 16 } else { 64 }; + let l = max_l.div_ceil(alignment) * alignment; + ensure!(l <= 512, "CUDA sequence length exceeds 512"); + let mut batch = Batch { + b, + l, + input_ids: vec![0; b * l], + lens: vec![0; b], + qtypes: vec![0; b], + markers: Vec::with_capacity(n), + }; + for (i, q) in prepared.questions.iter().enumerate() { + ensure!( + !q.ids.is_empty() + && q.ids.iter().all(|id| *id < 50368) + && (0..=2).contains(&q.qtype) + && !q.markers.is_empty() + && q.markers.iter().all(|m| *m < q.ids.len()), + "invalid prepared sequence" + ); + batch.input_ids[i * l..i * l + max_l].fill(50283); + for (dst, id) in batch.input_ids[i * l..].iter_mut().zip(&q.ids) { + *dst = i64::from(*id); + } + batch.lens[i] = q.ids.len() as i32; + batch.qtypes[i] = q.qtype; + batch.markers.push(q.markers.clone()); + } + Ok(batch) +} diff --git a/src/models/laya/src/preprocess.rs b/src/models/laya/src/preprocess.rs new file mode 100644 index 00000000..cbdf7e20 --- /dev/null +++ b/src/models/laya/src/preprocess.rs @@ -0,0 +1,415 @@ +//! English Laya 0.3.20 token packing, before backend padding or batching. +use anyhow::{Result, anyhow, bail, ensure}; +use serde::de::{self, MapAccess, SeqAccess, Visitor}; +use serde::{Deserializer, Serialize}; +use serde_json::value::RawValue; +use serde_json::{Map, Value}; +use std::path::Path; +use tokenizers::Tokenizer; + +/// Use `from_json` for a top-level JSON request or `from_value` for an existing value. +#[derive(Debug, Serialize)] +pub struct Request { + pub state: Value, + pub model: Option, + pub questions: Map, + pub lang: Option, +} + +impl Request { + /// Decode one JSON request with serde_json's default nesting limit. + pub fn from_json(raw: &str) -> Result { + let raw: Box = serde_json::from_str(raw)?; + Self::from_value(parse_value(&raw, 0)?) + } + + /// Keep existing structured values without reparsing or imposing a JSON depth limit. + pub fn from_value(value: Value) -> Result { + let Value::Object(mut fields) = value else { + bail!("request must be an object"); + }; + let state = fields + .remove("state") + .ok_or_else(|| anyhow!("missing state"))?; + let questions = fields + .remove("questions") + .ok_or_else(|| anyhow!("missing questions"))?; + let Value::Object(questions) = questions else { + bail!("questions must be an object"); + }; + let model = serde_json::from_value(fields.remove("model").unwrap_or(Value::Null))?; + let lang = serde_json::from_value(fields.remove("lang").unwrap_or(Value::Null))?; + ensure!(fields.is_empty(), "unknown request fields"); + Ok(Self { + state, + model, + questions, + lang, + }) + } +} + +fn parse_value(raw: &RawValue, depth: usize) -> serde_json::Result { + let text = raw.get(); + if !matches!(text.as_bytes()[0], b'{' | b'[') { + return serde_json::from_str(text); + } + if depth >= 127 { + return Err(de::Error::custom("recursion limit exceeded")); + } + // Construct containers explicitly: serde_json's private Number/RawValue + // map encodings must not interpret legitimate user object keys. + struct Containers(usize); + impl<'de> Visitor<'de> for Containers { + type Value = Value; + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("a JSON object or array") + } + fn visit_seq>(self, mut seq: A) -> Result { + let mut values = Vec::new(); + while let Some(raw) = seq.next_element::>()? { + values.push(parse_value(&raw, self.0 + 1).map_err(de::Error::custom)?); + } + Ok(Value::Array(values)) + } + fn visit_map>(self, mut map: A) -> Result { + let mut values = Map::new(); + while let Some((key, raw)) = map.next_entry::>()? { + if self.0 == 0 && values.contains_key(&key) { + return Err(de::Error::custom(format!("duplicate field {key}"))); + } + values.insert( + key, + parse_value(&raw, self.0 + 1).map_err(de::Error::custom)?, + ); + } + Ok(Value::Object(values)) + } + } + serde_json::Deserializer::from_str(text).deserialize_any(Containers(depth)) +} + +#[derive(Debug, Serialize)] +pub struct Question { + pub id: String, + pub kind: String, + pub criteria: Value, + pub ids: Vec, + pub markers: Vec, + pub qtype: i64, +} + +#[derive(Debug, Serialize)] +pub struct Prepared { + pub questions: Vec, + pub usage: usize, +} + +pub struct Preprocessor { + tokenizer: Tokenizer, + cls: u32, + sep: u32, + mask: u32, +} + +// Python json.dumps(..., ensure_ascii=False) uses spaces after commas/colons. +// Walk values so punctuation inside strings remains untouched. +pub fn render(value: &Value) -> String { + match value { + Value::String(s) => s.clone(), + _ => spaced_json(value), + } +} +fn spaced_json(value: &Value) -> String { + match value { + Value::Array(a) => format!( + "[{}]", + a.iter().map(spaced_json).collect::>().join(", ") + ), + Value::Object(o) => format!( + "{{{}}}", + o.iter() + .map(|(k, v)| format!("{}: {}", serde_json::to_string(k).unwrap(), spaced_json(v))) + .collect::>() + .join(", ") + ), + Value::Number(n) => python_number(n), + _ => serde_json::to_string(value).unwrap(), + } +} + +impl Preprocessor { + pub fn load(tokenizer_path: &Path) -> Result { + let mut tokenizer = Tokenizer::from_file(tokenizer_path).map_err(|e| anyhow!("{e}"))?; + tokenizer.with_padding(None); + tokenizer + .with_truncation(None) + .map_err(|e| anyhow!("{e}"))?; + let token = |s| { + tokenizer + .token_to_id(s) + .ok_or_else(|| anyhow!("missing token {s}")) + }; + Ok(Self { + cls: token("[CLS]")?, + sep: token("[SEP]")?, + mask: token("[MASK]")?, + tokenizer, + }) + } + fn encode(&self, text: &str) -> Result> { + Ok(self + .tokenizer + .encode(text.replace("[MASK]", " "), false) + .map_err(|e| anyhow!("{e}"))? + .get_ids() + .to_vec()) + } + pub fn prepare(&self, request: &Request) -> Result { + validate_numbers(&request.state)?; + for question in request.questions.values() { + validate_numbers(question)?; + } + ensure!( + request.model.as_deref().is_none_or(|s| s == "english"), + "only model=english is supported" + ); + ensure!( + request + .lang + .as_deref() + .is_none_or(|s| s == "en" || s == "english"), + "only English is supported; use lang=en" + ); + let state = self.encode(&render(&request.state))?; + let mut questions = Vec::new(); + for (id, definition) in &request.questions { + let (kind, criteria, opts) = + options(definition).map_err(|e| anyhow!("question {id:?}: {e}"))?; + let ins = definition + .get("instructions") + .ok_or_else(|| anyhow!("question {id:?}: missing instructions"))?; + let mut head = self.encode(&format!("{kind} question: {}", render(ins)))?; + let mut opt_ids = Vec::new(); + for opt in &opts { + let mut ids = vec![self.mask]; + ids.extend(self.encode(&format!(" {opt}"))?.into_iter().take(48)); + opt_ids.push(ids); + } + let mut budget = 192isize - opt_ids.iter().map(Vec::len).sum::() as isize; + if budget < 16 { + let per = (176 / opt_ids.len()).max(4); + for o in &mut opt_ids { + o.truncate(per); + } + budget = 192 - opt_ids.iter().map(Vec::len).sum::() as isize; + } + head.truncate(budget.max(8) as usize); + let mut ids = vec![self.cls]; + ids.extend(head); + ids.push(self.sep); + let mut markers = Vec::new(); + for opt in opt_ids { + markers.push(ids.len()); + ids.extend(opt); + } + ids.push(self.sep); + let room = 512usize.saturating_sub(ids.len() + 1); + if request.state.is_array() { + ids.extend_from_slice(&state[state.len().saturating_sub(room)..]); + } else { + ids.extend_from_slice(&state[..room.min(state.len())]); + } + ids.push(self.sep); + ids.truncate(512); + ensure!( + markers.iter().all(|&m| m < 512), + "question {id:?}: options exceed head_max_len=192" + ); + let qtype = match kind.as_str() { + "choice" => 0, + "score" => 1, + _ => 2, + }; + questions.push(Question { + id: id.clone(), + kind, + criteria, + ids, + markers, + qtype, + }); + } + let usage = questions.iter().map(|q| q.ids.len()).sum(); + Ok(Prepared { questions, usage }) + } +} + +fn options(q: &Value) -> Result<(String, Value, Vec)> { + ensure!(q.is_object(), "definition must be an object"); + let kind = q["type"].as_str().ok_or_else(|| anyhow!("missing type"))?; + ensure!( + ["choice", "score", "noul"].contains(&kind), + "unknown type {kind}" + ); + ensure!( + kind == "noul" || q.get("labels").is_none(), + "labels only apply to noul" + ); + let mut criteria = q.get("criteria").cloned().unwrap_or(Value::Null); + let opts = match kind { + "choice" => { + if let Some(a) = criteria.as_array() { + let mut o = Map::new(); + for key in a { + o.insert( + key.as_str() + .ok_or_else(|| anyhow!("choice labels must be strings"))? + .to_owned(), + Value::Null, + ); + } + criteria = Value::Object(o); + } + let o = criteria + .as_object() + .ok_or_else(|| anyhow!("choice criteria must be object or list"))?; + ensure!(!o.is_empty(), "at least one choice required"); + o.iter() + .map(|(k, v)| { + if v.is_null() || v.as_str() == Some("") { + k.clone() + } else { + format!("{k}: {}", render(v)) + } + }) + .collect() + } + "score" => { + let a = criteria + .as_array() + .ok_or_else(|| anyhow!("score criteria must be a list"))?; + ensure!(!a.is_empty(), "at least one level required"); + a.iter() + .enumerate() + .map(|(i, v)| format!("level {i}: {}", render(v))) + .collect() + } + _ => { + if criteria.is_null() { + criteria = Value::Object(Map::new()); + } + let o = criteria + .as_object() + .ok_or_else(|| anyhow!("noul criteria must be object"))?; + let mut normalized = Map::new(); + for (k, v) in o { + let key = k.to_lowercase(); + ensure!( + key == "true" || key == "false", + "noul criteria keys must be true/false" + ); + normalized.insert(key, v.clone()); + } + criteria = Value::Object(normalized); + let labels = match q.get("labels") { + None | Some(Value::Null) => ["false", "true"], + Some(Value::Object(o)) if o.len() == 2 => [ + python_strip(o.get("false").and_then(Value::as_str).unwrap_or("")), + python_strip(o.get("true").and_then(Value::as_str).unwrap_or("")), + ], + _ => bail!("noul labels must map true/false to distinct non-empty strings"), + }; + ensure!( + !labels[0].is_empty() && !labels[1].is_empty() && labels[0] != labels[1], + "invalid noul labels" + ); + ["false", "true"] + .iter() + .enumerate() + .map(|(i, k)| { + let v = &criteria[*k]; + let desc = if v.is_null() || v.as_str() == Some("") { + if i == 0 { + "no, the statement does not hold".to_owned() + } else { + "yes, the statement holds".to_owned() + } + } else { + render(v) + }; + format!("{}: {desc}", labels[i]) + }) + .collect() + } + }; + Ok((kind.to_owned(), criteria, opts)) +} + +fn python_strip(value: &str) -> &str { + value.trim_matches(|c: char| c.is_whitespace() || ('\u{1c}'..='\u{1f}').contains(&c)) +} + +// Preserve arbitrary-size integers; floats use Python's shortest decimal and notation rules. +fn python_number(n: &serde_json::Number) -> String { + let raw = n.to_string(); + if !raw.contains(['.', 'e', 'E']) { + return raw; + } + let Some(value) = n.as_f64().filter(|v| v.is_finite()) else { + return raw; + }; + let shortest = serde_json::Number::from_f64(value).unwrap().to_string(); + let (mantissa, exponent) = shortest.split_once('e').unwrap_or((&shortest, "0")); + let sign = if value.is_sign_negative() { "-" } else { "" }; + let mantissa = mantissa.trim_start_matches('-'); + let point = mantissa.find('.').unwrap_or(mantissa.len()); + let digits = mantissa.replace('.', ""); + let significant = digits.trim_start_matches('0'); + if significant.is_empty() { + return format!("{sign}0.0"); + } + let e = exponent.parse::().unwrap() + point as i32 + - (digits.len() - significant.len()) as i32 + - 1; + let significant = significant.trim_end_matches('0'); + if !(-4..16).contains(&e) { + let mut mantissa = significant.to_owned(); + if mantissa.len() > 1 { + mantissa.insert(1, '.'); + } + return format!("{sign}{mantissa}e{e:+03}"); + } + let point = e + 1; + let mut plain = significant.to_owned(); + if point <= 0 { + plain = format!("0.{}{plain}", "0".repeat((-point) as usize)); + } else if point as usize >= plain.len() { + plain.push_str(&"0".repeat(point as usize - plain.len())); + plain.push_str(".0"); + } else { + plain.insert(point as usize, '.'); + } + format!("{sign}{plain}") +} + +fn validate_numbers(value: &Value) -> Result<()> { + match value { + Value::Number(n) if n.to_string().contains(['.', 'e', 'E']) => ensure!( + n.as_f64().is_some_and(f64::is_finite), + "floating point value outside supported finite range" + ), + Value::Array(a) => { + for v in a { + validate_numbers(v)?; + } + } + Value::Object(o) => { + for v in o.values() { + validate_numbers(v)?; + } + } + _ => {} + } + Ok(()) +} diff --git a/src/models/laya/src/processing.rs b/src/models/laya/src/processing.rs new file mode 100644 index 00000000..a05c7737 --- /dev/null +++ b/src/models/laya/src/processing.rs @@ -0,0 +1,60 @@ +//! Request preparation and response reconstruction; no device state or learned heads. +use std::{path::Path, sync::Arc}; + +use anyhow::Result; +use serde_json::{Value, json}; + +use crate::{ + config::{AgentConfig, Config}, + decision, + packing::{self, Batch}, + preprocess::{Prepared, Preprocessor, Request}, +}; + +pub struct Processor { + preprocessor: Preprocessor, + config: Arc, +} + +pub struct PreparedRequest { + pub inputs: Batch, + pub context: ResponseContext, +} + +pub struct ResponseContext { + prepared: Prepared, + config: Arc, +} + +impl Processor { + pub fn load(checkpoint: &Path) -> Result { + Ok(Self { + preprocessor: Preprocessor::load(&checkpoint.join("tokenizer/tokenizer.json"))?, + config: Arc::new(Config::load(checkpoint)?.agent), + }) + } + + pub fn prepare(&self, raw: &[u8]) -> Result { + let request = Request::from_json(std::str::from_utf8(raw)?)?; + let prepared = self.preprocessor.prepare(&request)?; + Ok(PreparedRequest { + inputs: packing::pack(&prepared)?, + context: ResponseContext { + prepared, + config: self.config.clone(), + }, + }) + } +} + +impl ResponseContext { + pub fn finish(self, logits: Vec>, actions: Vec<[f32; 2]>) -> Result { + let answers = decision::decode(&self.prepared, &self.config, &logits, &actions)?; + Ok(json!({ + "model": "laya-rl-agent", "answers": answers, + "usage": {"input_tokens": self.prepared.usage, "output_tokens": 0}, + "routing": {"model": "english", "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", "detection": null, "workflow": null} + })) + } +} diff --git a/src/models/laya/src/serve.rs b/src/models/laya/src/serve.rs new file mode 100644 index 00000000..ce2e6b1d --- /dev/null +++ b/src/models/laya/src/serve.rs @@ -0,0 +1,96 @@ +//! Native worker assembly and HTTP adapter; the public frontend remains a proxy. +use crate::{executor::Executor, processing::Processor}; +use anyhow::Result; +use axum::{ + Json, Router, + body::Bytes, + extract::{DefaultBodyLimit, State, rejection::BytesRejection}, + http::{HeaderMap, StatusCode}, + response::{IntoResponse, Response}, + routing::{get, post}, +}; +use omni_runtime::SerialScheduler; +use serde_json::json; +use std::{path::Path, sync::Arc}; + +pub struct Engine { + pub processor: Processor, + pub scheduler: SerialScheduler, + pub executor: Executor, +} + +impl Engine { + pub async fn load(checkpoint: &Path, bundle: &Path) -> Result { + Ok(Self { + processor: Processor::load(checkpoint)?, + scheduler: SerialScheduler::default(), + executor: Executor::load(checkpoint, bundle).await?, + }) + } + pub async fn decide(&self, raw: &[u8]) -> Response { + let prepared = match self.processor.prepare(raw) { + Ok(prepared) => prepared, + Err(e) => return error(StatusCode::UNPROCESSABLE_ENTITY, e), + }; + let result = async { + let (logits, actions) = self + .executor + .execute(&self.scheduler, prepared.inputs) + .await?; + prepared.context.finish(logits, actions) + } + .await; + match result { + Ok(body) => Json(body).into_response(), + Err(e) => { + eprintln!("inference failed: {e:#}"); + error(StatusCode::INTERNAL_SERVER_ERROR, "model inference failed") + } + } + } +} + +fn error(status: StatusCode, message: impl ToString) -> Response { + (status, Json(json!({"error": message.to_string()}))).into_response() +} + +async fn systemone( + State(engine): State>, + headers: HeaderMap, + body: Result, +) -> Response { + let content_type = headers + .get("content-type") + .and_then(|v| v.to_str().ok()) + .unwrap_or("") + .split(';') + .next() + .unwrap_or("") + .trim(); + if !content_type.eq_ignore_ascii_case("application/json") { + return error( + StatusCode::UNSUPPORTED_MEDIA_TYPE, + "Content-Type must be application/json", + ); + } + match body { + Ok(raw) => engine.decide(&raw).await, + Err(e) => error(e.status(), e.body_text()), + } +} + +async fn health(State(engine): State>) -> Response { + if engine.executor.ready() { + Json(json!({"status":"ready", "model":"laya-rl-agent"})).into_response() + } else { + error(StatusCode::SERVICE_UNAVAILABLE, "CUDA worker unavailable") + } +} + +pub fn router(engine: Arc) -> Router { + Router::new() + .route("/health", get(health)) + .route("/v1/systemone", post(systemone)) + .layer(DefaultBodyLimit::max(4 << 20)) + .with_state(engine) +} diff --git a/src/models/qwen3_5/native/Cargo.toml b/src/models/qwen3_5/native/Cargo.toml index b71c29a5..57c2428f 100644 --- a/src/models/qwen3_5/native/Cargo.toml +++ b/src/models/qwen3_5/native/Cargo.toml @@ -12,7 +12,7 @@ libloading = "0.8" memmap2 = "0.9.9" safetensors = "0.8.0" serde = "1" -serde_json = { version = "1.0.149", features = ["float_roundtrip", "preserve_order"] } +serde_json = { version = "1.0.149", features = ["float_roundtrip", "preserve_order", "raw_value"] } [[test]] name = "config" diff --git a/src/models/qwen3_5/native/src/json.rs b/src/models/qwen3_5/native/src/json.rs index 18529af5..d9f33556 100644 --- a/src/models/qwen3_5/native/src/json.rs +++ b/src/models/qwen3_5/native/src/json.rs @@ -11,14 +11,13 @@ use std::io; use serde::Serialize; use serde::de::{self, Deserializer, MapAccess, SeqAccess, Visitor}; +use serde_json::value::RawValue; use serde_json::{Map, Number, Value}; /// Decode a request body into its top-level object; the error is the 400 message. pub fn parse(raw: &[u8]) -> Result, String> { - let mut de = serde_json::Deserializer::from_slice(raw); - let value = de - .deserialize_any(NoDuplicates) - .and_then(|v| de.end().map(|()| v)) + let value = serde_json::from_slice::>(raw) + .and_then(|raw| parse_value(&raw, 0)) .map_err(|e| format!("request body is not valid JSON: {e}"))?; match value { Value::Object(map) => Ok(map), @@ -26,67 +25,59 @@ pub fn parse(raw: &[u8]) -> Result, String> { } } -/// Builds a `Value` like serde_json does, but fails on a repeated key. -struct NoDuplicates; - -impl<'de> de::Deserialize<'de> for Wrapped { - fn deserialize>(d: D) -> Result { - d.deserialize_any(NoDuplicates).map(Wrapped) - } -} - -struct Wrapped(Value); - -impl<'de> Visitor<'de> for NoDuplicates { - type Value = Value; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("a JSON value") - } - fn visit_unit(self) -> Result { - Ok(Value::Null) - } - fn visit_bool(self, b: bool) -> Result { - Ok(Value::Bool(b)) - } - fn visit_i64(self, n: i64) -> Result { - Ok(Value::Number(n.into())) - } - fn visit_u64(self, n: u64) -> Result { - Ok(Value::Number(n.into())) - } - fn visit_f64(self, x: f64) -> Result { - Number::from_f64(x) - .map(Value::Number) - .ok_or_else(|| E::custom("number out of range")) - } - fn visit_str(self, s: &str) -> Result { - Ok(Value::String(s.to_owned())) - } - fn visit_string(self, s: String) -> Result { - Ok(Value::String(s)) - } - fn visit_seq>(self, mut seq: A) -> Result { - let mut items = Vec::new(); - while let Some(Wrapped(v)) = seq.next_element()? { - items.push(v); +// Read containers as raw JSON so feature unification with arbitrary_precision +// cannot confuse numeric values or legitimate private-marker object keys. +fn parse_value(raw: &RawValue, depth: usize) -> serde_json::Result { + let text = raw.get(); + if !matches!(text.as_bytes()[0], b'{' | b'[') { + let value: Value = serde_json::from_str(text)?; + return if let Value::Number(n) = value { + if n.is_i64() || n.is_u64() { + Ok(Value::Number(n)) + } else { + n.as_f64() + .and_then(Number::from_f64) + .map(Value::Number) + .ok_or_else(|| de::Error::custom("number out of range")) + } + } else { + Ok(value) + }; + } + if depth >= 127 { + return Err(de::Error::custom("recursion limit exceeded")); + } + struct Container(usize); + impl<'de> Visitor<'de> for Container { + type Value = Value; + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("a JSON object or array") } - Ok(Value::Array(items)) - } - fn visit_map>(self, mut map: A) -> Result { - let mut obj = Map::new(); - while let Some(key) = map.next_key::()? { - let Wrapped(v) = map.next_value()?; - if obj.contains_key(&key) { - return Err(de::Error::custom(format_args!( - "duplicate key {}", - quote(&key) - ))); + fn visit_seq>(self, mut seq: A) -> Result { + let mut items = Vec::new(); + while let Some(raw) = seq.next_element::>()? { + items.push(parse_value(&raw, self.0 + 1).map_err(de::Error::custom)?); + } + Ok(Value::Array(items)) + } + fn visit_map>(self, mut map: A) -> Result { + let mut obj = Map::new(); + while let Some((key, raw)) = map.next_entry::>()? { + if obj.contains_key(&key) { + return Err(de::Error::custom(format_args!( + "duplicate key {}", + quote(&key) + ))); + } + obj.insert( + key, + parse_value(&raw, self.0 + 1).map_err(de::Error::custom)?, + ); } - obj.insert(key, v); + Ok(Value::Object(obj)) } - Ok(Value::Object(obj)) } + serde_json::Deserializer::from_str(text).deserialize_any(Container(depth)) } /// A string as a JSON literal, which is also how error messages quote names. @@ -124,6 +115,18 @@ impl serde_json::ser::Formatter for PyFormatter { fn begin_object_value(&mut self, w: &mut W) -> io::Result<()> { w.write_all(b": ") } + fn write_number_str( + &mut self, + w: &mut W, + value: &str, + ) -> io::Result<()> { + if value.contains(['.', 'e', 'E']) { + let x: f64 = value.parse().map_err(io::Error::other)?; + w.write_all(float_repr(x).as_bytes()) + } else { + w.write_all(value.as_bytes()) + } + } fn write_f64(&mut self, w: &mut W, x: f64) -> io::Result<()> { w.write_all(float_repr(x).as_bytes()) } diff --git a/src/runtime/README.md b/src/runtime/README.md index c06c3036..bd571b03 100644 --- a/src/runtime/README.md +++ b/src/runtime/README.md @@ -1,6 +1,6 @@ # Native execution runtime -`omni-runtime` provides `SerialScheduler` for the Cua-S1 and Open-Jev native +`omni-runtime` provides `SerialScheduler` for the Cua-S1, Open-Jev and Laya native workers. Their engines assemble a processor, one scheduler for the loaded executor, and the executor. HTTP handlers still coordinate `prepare` → `execute` → `finish`. @@ -15,6 +15,7 @@ state. Waiting requests no longer occupy blocking threads waiting for that mutex | --- | --- | --- | | Cua-S1 | One question's unpadded Qwen forward. Release before admitting its next question. | Request preparation, CPU letter projection and response finishing. | | Open-Jev | One complete request's independent candidate forwards and CPU scalar heads. | Request preparation and calibrated response finishing. | +| Laya | One complete padded request, including GPU scorer/action head and copyback. | Request preparation/padding and calibrated response finishing. | Models retain weights, heads, device state, scratch buffers and graph caches. The scheduler takes an owned closure and returns its result; it does not know diff --git a/tests/cuda/test_laya_build.py b/tests/cuda/test_laya_build.py new file mode 100644 index 00000000..37cd2036 --- /dev/null +++ b/tests/cuda/test_laya_build.py @@ -0,0 +1,115 @@ +"""Check wrapper arguments and directory ownership without CUDA or TileLang.""" + +import os +from pathlib import Path +import subprocess +import tempfile +import unittest + + +SCRIPT = Path(__file__).resolve().parents[2] / "src/backends/cuda/build.sh" +FAKE_PYTHON = r'''#!/usr/bin/env python3 +import os +from pathlib import Path +import sys + +step = "import" if sys.argv[1] == "-c" else Path(sys.argv[1]).stem +if os.environ.get("FAIL_STEP") == step: + sys.exit(7) +if step == "build" and not os.environ.get("OMIT_LIBRARY"): + stage = Path(sys.argv[2]) + (stage / "liblaya_cuda.so").write_bytes(b"test library") + (stage / "build-manifest.json").write_text('{"arch":"sm_90a"}') +''' + + +class BuildEntryTest(unittest.TestCase): + def setUp(self): + temporary = tempfile.TemporaryDirectory() + self.addCleanup(temporary.cleanup) + self.root = Path(temporary.name) + self.out = self.root / "output dir" + self.python = self.root / "fake python" + self.python.write_text(FAKE_PYTHON) + self.python.chmod(0o755) + self.env = dict(os.environ, PYTHON=str(self.python), TMPDIR=str(self.root)) + for name in ("BUILD_STAGE", "KEEP_STAGE", "CUDA_COMPUTE_CAP", + "FAIL_STEP", "OMIT_LIBRARY"): + self.env.pop(name, None) + + def run_build(self, *args, **env): + return subprocess.run( + ["bash", str(SCRIPT), *map(str, args)], + env=dict(self.env, **env), text=True, capture_output=True, + ) + + def staging_path(self, result): + line = next(line for line in result.stdout.splitlines() + if line.startswith("build.sh: staging in ")) + return Path(line.removeprefix("build.sh: staging in ")) + + def assert_outputs(self): + self.assertEqual((self.out / "liblaya_cuda.so").read_bytes(), b"test library") + self.assertEqual((self.out / "build-manifest.json").read_text(), '{"arch":"sm_90a"}') + + def test_success_copies_outputs_and_removes_automatic_stage(self): + result = self.run_build(self.out, "90") + self.assertEqual(result.returncode, 0, result.stderr) + self.assert_outputs() + self.assertFalse(self.staging_path(result).exists()) + + def test_custom_stage_is_preserved_on_success_and_failure(self): + for step in ("", "export", "build"): + with self.subTest(step=step): + stage = self.root / ("custom " + (step or "success")) + stage.mkdir() + sentinel = stage / "existing.txt" + sentinel.write_text("keep") + result = self.run_build(self.out, BUILD_STAGE=str(stage), FAIL_STEP=step) + self.assertEqual(result.returncode, 7 if step else 0, result.stderr) + self.assertTrue(sentinel.exists(), result.stdout) + self.assertEqual(sentinel.read_text(), "keep") + + def test_automatic_stage_is_removed_on_failure(self): + for step in ("export", "build"): + with self.subTest(step=step): + result = self.run_build(self.out, FAIL_STEP=step) + self.assertEqual(result.returncode, 7, result.stderr) + self.assertFalse(self.staging_path(result).exists()) + self.assertFalse(self.out.exists()) + + def test_keep_stage_preserves_automatic_directory(self): + result = self.run_build(self.out, KEEP_STAGE="1") + self.assertEqual(result.returncode, 0, result.stderr) + self.assertTrue(self.staging_path(result).is_dir()) + self.assert_outputs() + + def test_output_can_be_the_custom_stage(self): + result = self.run_build(self.out, BUILD_STAGE=str(self.out)) + self.assertEqual(result.returncode, 0, result.stderr) + self.assert_outputs() + + def test_invalid_architecture_is_rejected_before_staging(self): + result = self.run_build(self.out, "89") + self.assertEqual(result.returncode, 2) + self.assertIn("sm_90a", result.stderr) + self.assertFalse(self.out.exists()) + self.assertEqual(list(self.root.glob("laya-cuda.*")), []) + + def test_missing_python_or_tilelang_is_reported(self): + for env in ({"PYTHON": str(self.root / "missing")}, {"FAIL_STEP": "import"}): + with self.subTest(env=env): + result = self.run_build(self.out, **env) + self.assertEqual(result.returncode, 2) + self.assertFalse(self.out.exists()) + + def test_missing_library_is_an_error(self): + result = self.run_build(self.out, OMIT_LIBRARY="1") + self.assertEqual(result.returncode, 1) + self.assertIn("did not produce", result.stderr) + self.assertFalse(self.staging_path(result).exists()) + self.assertFalse(self.out.exists()) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/laya/artifacts.rs b/tests/laya/artifacts.rs new file mode 100644 index 00000000..16e261d9 --- /dev/null +++ b/tests/laya/artifacts.rs @@ -0,0 +1,156 @@ +use super::*; +use serde_json::json; +use std::{ + path::PathBuf, + sync::atomic::{AtomicU64, Ordering}, +}; + +static NEXT: AtomicU64 = AtomicU64::new(0); +struct Fixture { + root: PathBuf, + checkpoint: PathBuf, + bundle: PathBuf, +} +impl Fixture { + fn new() -> Self { + let root = std::env::temp_dir().join(format!( + "laya-artifacts-{}-{}", + std::process::id(), + NEXT.fetch_add(1, Ordering::Relaxed) + )); + fs::create_dir(&root).unwrap(); + let checkpoint = root.join("checkpoint"); + let bundle = root.join("bundle"); + fs::create_dir_all(checkpoint.join("encoder")).unwrap(); + fs::create_dir_all(checkpoint.join("tokenizer")).unwrap(); + fs::create_dir(&bundle).unwrap(); + let mut hashes = serde_json::Map::new(); + for name in CHECKPOINT_ARTIFACTS { + // The weight fixture crosses several bounded hash reads; no GPU or real model required. + let data = if name == "model.safetensors" { + vec![42; 192 * 1024 + 1] + } else { + name.as_bytes().to_vec() + }; + fs::write(checkpoint.join(name), &data).unwrap(); + hashes.insert(name.into(), json!(format!("{:x}", Sha256::digest(&data)))); + } + let mut tables = serde_json::Map::new(); + for name in [ + "rope_full_cos.f32", + "rope_full_sin.f32", + "rope_local_cos.f32", + "rope_local_sin.f32", + ] { + fs::write(bundle.join(name), b"table").unwrap(); + tables.insert( + name.into(), + json!(format!("{:x}", Sha256::digest(b"table"))), + ); + } + let table_manifest = json!({ + "abi": 1, + "laya": "0.3.20", + "hidden_size": 1024, + "head_dim": 64, + "max_len": 512, + "tables": tables, + "checkpoint_sha256": hashes, + }); + fs::write( + bundle.join("tables.json"), + serde_json::to_vec(&table_manifest).unwrap(), + ) + .unwrap(); + fs::write(bundle.join("liblaya_cuda.so"), b"not loaded in CPU test").unwrap(); + let build_manifest = json!({ + "abi": 1, + "arch": "sm_90a", + "library_sha256": format!("{:x}", Sha256::digest(b"not loaded in CPU test")), + }); + fs::write( + bundle.join("build-manifest.json"), + serde_json::to_vec(&build_manifest).unwrap(), + ) + .unwrap(); + Self { + root, + checkpoint, + bundle, + } + } + fn validate(&self) -> Result<()> { + validate_bundle(&self.checkpoint, &self.bundle) + } +} +impl Drop for Fixture { + fn drop(&mut self) { + let _ = fs::remove_dir_all(&self.root); + } +} + +#[test] +fn matching_artifacts_pass_without_loading_cuda() { + Fixture::new().validate().unwrap(); +} + +#[test] +fn each_checkpoint_artifact_is_bound_to_the_bundle() { + for name in CHECKPOINT_ARTIFACTS { + let f = Fixture::new(); + let path = f.checkpoint.join(name); + let mut data = fs::read(&path).unwrap(); + data[0] ^= 1; // Same size: shape/file-size checks alone would not catch substitution. + fs::write(path, data).unwrap(); + let error = f.validate().unwrap_err().to_string(); + assert!( + error.contains("hash mismatch") && error.contains(name), + "{error}" + ); + } +} + +#[test] +fn missing_checkpoint_hashes_fail_closed() { + for name in CHECKPOINT_ARTIFACTS { + let f = Fixture::new(); + let path = f.bundle.join("tables.json"); + let mut manifest: serde_json::Value = + serde_json::from_slice(&fs::read(&path).unwrap()).unwrap(); + manifest["checkpoint_sha256"] + .as_object_mut() + .unwrap() + .remove(name); + fs::write(path, serde_json::to_vec(&manifest).unwrap()).unwrap(); + let error = f.validate().unwrap_err().to_string(); + assert!( + error.contains("missing checkpoint hash") && error.contains(name), + "{error}" + ); + } + let f = Fixture::new(); + let path = f.bundle.join("tables.json"); + let mut manifest: serde_json::Value = + serde_json::from_slice(&fs::read(&path).unwrap()).unwrap(); + manifest + .as_object_mut() + .unwrap() + .remove("checkpoint_sha256"); + fs::write(path, serde_json::to_vec(&manifest).unwrap()).unwrap(); + assert!( + f.validate() + .unwrap_err() + .to_string() + .contains("missing checkpoint hash") + ); +} + +#[test] +fn missing_checkpoint_file_fails_closed() { + for name in CHECKPOINT_ARTIFACTS { + let f = Fixture::new(); + fs::remove_file(f.checkpoint.join(name)).unwrap(); + let error = f.validate().unwrap_err().to_string(); + assert!(error.contains(name), "{error}"); + } +} diff --git a/tests/laya/batch.rs b/tests/laya/batch.rs new file mode 100644 index 00000000..92faf922 --- /dev/null +++ b/tests/laya/batch.rs @@ -0,0 +1,65 @@ +use omni_laya::{ + packing::pack, + preprocess::{Prepared, Question}, +}; +use serde_json::Value; + +fn prepared(n: usize) -> Prepared { + Prepared { + questions: (0..n) + .map(|i| Question { + id: i.to_string(), + kind: "noul".into(), + criteria: Value::Null, + ids: vec![1, 2, 3], + markers: vec![1, 2], + qtype: 2, + }) + .collect(), + usage: n * 3, + } +} + +#[test] +fn padding_preserves_order_lengths_and_markers() { + let prepared = prepared(3); + let batch = pack(&prepared).unwrap(); + assert_eq!((batch.b, batch.l), (4, 16)); + assert_eq!(batch.lens, [3, 3, 3, 0]); + assert_eq!(batch.qtypes, [2, 2, 2, 0]); + assert_eq!(batch.markers, vec![vec![1, 2]; 3]); + for i in 0..3 { + assert_eq!(&batch.input_ids[i * 16..i * 16 + 3], &[1, 2, 3]); + } + assert!(batch.input_ids[48..].iter().all(|id| *id == 0)); + assert_eq!(prepared.usage, 9); +} + +#[test] +fn rejects_executor_capacity_and_invalid_markers() { + assert!(pack(&prepared(17)).is_err()); + let mut input = prepared(1); + input.questions[0].markers.push(3); + assert!(pack(&input).is_err()); + input.questions[0].markers = vec![1; 2049]; + assert!(pack(&input).is_err()); +} + +#[test] +fn empty_request_needs_no_device_rows() { + let batch = pack(&prepared(0)).unwrap(); + assert_eq!((batch.b, batch.l), (0, 0)); + assert!(batch.markers.is_empty()); +} + +#[test] +fn padding_matches_native_sequence_alignment() { + let mut input = prepared(3); + input.questions[1].ids = vec![7; 257]; + let batch = pack(&input).unwrap(); + assert_eq!((batch.b, batch.l), (4, 320)); + assert_eq!(batch.lens, [3, 257, 3, 0]); + assert!(batch.input_ids[3..257].iter().all(|id| *id == 50283)); + assert!(batch.input_ids[257..320].iter().all(|id| *id == 0)); + assert!(batch.input_ids[960..].iter().all(|id| *id == 0)); +} diff --git a/tests/laya/data/decisions.json b/tests/laya/data/decisions.json new file mode 100644 index 00000000..aac19db3 --- /dev/null +++ b/tests/laya/data/decisions.json @@ -0,0 +1,18 @@ +{"reference":{"python":"3.12.13","laya":"0.3.20","torch":"2.14.0","numpy":"2.5.3","source_sha256":{"agent.py":"fc63f64fbcbacb3f59a2dbfc93a1712e8d223cb507401b71b3abca7147e5e47b","common.py":"67274dc3115d8b9fc2dcd4228e66a09271cfd081f4e2fd09bab3b85549a5e001"},"config_sha256":"ae287b56bbcf5f8c4f4541ae9dfd00c914c4c48b940b8398c3058af37ba92bbd","scope":"Synthetic boundary logits; official CPU decode parity, not model quality or performance."},"config":{"temperature":[1.6369030475616455,1.2514300346374512,1.983399510383606],"temperature_by_options":{"choice:3-5":1.7601518630981445,"choice:6-10":1.0000158548355103,"score:3-5":1.2514300346374512,"noul:2":1.983399510383606,"choice:11+":0.10058280825614929,"choice:2":1.9063563346862793}},"cases":[ +{"name":"choice-1","questions":[{"id":"q","kind":"choice","criteria":{"option-0":null}}],"logits":[[-1.0]],"action_logits":[[-0.75,0.5]],"answers":{"q":{"type":"choice","choice":"option-0","probabilities":{"option-0":1.0},"confidence":1.0,"answer_confidence":1.0,"action":{"act_probability":0.2227}}}}, +{"name":"choice-2","questions":[{"id":"q","kind":"choice","criteria":{"option-0":null,"option-1":null}}],"logits":[[-1.0,-0.625]],"action_logits":[[-0.75,0.5]],"answers":{"q":{"type":"choice","choice":"option-1","probabilities":{"option-0":0.451,"option-1":0.549},"confidence":0.0069,"answer_confidence":0.549,"action":{"act_probability":0.2227}}}}, +{"name":"choice-3","questions":[{"id":"q","kind":"choice","criteria":{"option-0":null,"option-1":null,"option-2":null}}],"logits":[[-1.0,-0.625,-0.25]],"action_logits":[[-0.75,0.5]],"answers":{"q":{"type":"choice","choice":"option-2","probabilities":{"option-0":0.2653,"option-1":0.3283,"option-2":0.4063},"confidence":0.0136,"answer_confidence":0.4063,"action":{"act_probability":0.2227}}}}, +{"name":"choice-5","questions":[{"id":"q","kind":"choice","criteria":{"option-0":null,"option-1":null,"option-2":null,"option-3":null,"option-4":null}}],"logits":[[-1.0,-0.625,-0.25,0.125,0.5]],"action_logits":[[-0.75,0.5]],"answers":{"q":{"type":"choice","choice":"option-4","probabilities":{"option-0":0.1249,"option-1":0.1545,"option-2":0.1912,"option-3":0.2366,"option-4":0.2928},"confidence":0.0274,"answer_confidence":0.2928,"action":{"act_probability":0.2227}}}}, +{"name":"choice-6","questions":[{"id":"q","kind":"choice","criteria":{"option-0":null,"option-1":null,"option-2":null,"option-3":null,"option-4":null,"option-5":null}}],"logits":[[-1.0,-0.625,-0.25,0.125,0.5,0.875]],"action_logits":[[-0.75,0.5]],"answers":{"q":{"type":"choice","choice":"option-5","probabilities":{"option-0":0.0536,"option-1":0.078,"option-2":0.1135,"option-3":0.1651,"option-4":0.2402,"option-5":0.3496},"confidence":0.1013,"answer_confidence":0.3496,"action":{"act_probability":0.2227}}}}, +{"name":"choice-10","questions":[{"id":"q","kind":"choice","criteria":{"option-0":null,"option-1":null,"option-2":null,"option-3":null,"option-4":null,"option-5":null,"option-6":null,"option-7":null,"option-8":null,"option-9":null}}],"logits":[[-1.0,-0.625,-0.25,0.125,0.5,0.875,1.25,1.625,2.0,2.375]],"action_logits":[[-0.75,0.5]],"answers":{"q":{"type":"choice","choice":"option-9","probabilities":{"option-0":0.011,"option-1":0.0159,"option-2":0.0232,"option-3":0.0338,"option-4":0.0491,"option-5":0.0715,"option-6":0.104,"option-7":0.1513,"option-8":0.2201,"option-9":0.3202},"confidence":0.1868,"answer_confidence":0.3202,"action":{"act_probability":0.2227}}}}, +{"name":"choice-11","questions":[{"id":"q","kind":"choice","criteria":{"option-0":null,"option-1":null,"option-2":null,"option-3":null,"option-4":null,"option-5":null,"option-6":null,"option-7":null,"option-8":null,"option-9":null,"option-10":null}}],"logits":[[-1.0,-0.625,-0.25,0.125,0.5,0.875,1.25,1.625,2.0,2.375,2.75]],"action_logits":[[-0.75,0.5]],"answers":{"q":{"type":"choice","choice":"option-10","probabilities":{"option-0":0.0003,"option-1":0.0006,"option-2":0.0013,"option-3":0.0028,"option-4":0.0059,"option-5":0.0124,"option-6":0.0263,"option-7":0.0556,"option-8":0.1178,"option-9":0.2493,"option-10":0.5278},"confidence":0.4544,"answer_confidence":0.5278,"action":{"act_probability":0.2227}}}}, +{"name":"choice-first-tie","questions":[{"id":"q","kind":"choice","criteria":{"z":null,"a":null}}],"logits":[[2.0,2.0]],"action_logits":[[0.0,0.0]],"answers":{"q":{"type":"choice","choice":"z","probabilities":{"z":0.5,"a":0.5},"confidence":0.0,"answer_confidence":0.5,"action":{"act_probability":0.5}}}}, +{"name":"score-single","questions":[{"id":"q","kind":"score","criteria":["only"]}],"logits":[[-5.0]],"action_logits":[[1.0,-1.0]],"answers":{"q":{"type":"score","score":0.0,"legend":{"0":"only"},"probabilities":{"0":1.0},"confidence":1.0,"answer_confidence":1.0,"action":{"act_probability":0.8808}}}}, +{"name":"score-legend","questions":[{"id":"q","kind":"score","criteria":["low",{"description":"middle"},7]}],"logits":[[0.25,1.5,-0.5]],"action_logits":[[0.3,-0.8]],"answers":{"q":{"type":"score","score":0.8943,"legend":{"0":"low","1":{"description":"middle"},"2":7},"probabilities":{"0":0.2345,"1":0.6367,"2":0.1288},"confidence":0.1885,"answer_confidence":0.6367,"action":{"act_probability":0.7503}}}}, +{"name":"noul-extremes","questions":[{"id":"false","kind":"noul","criteria":null},{"id":"true","kind":"noul","criteria":null}],"logits":[[1e+30,-1e+30],[-1e+30,1e+30]],"action_logits":[[1e+30,-1e+30],[-1e+30,1e+30]],"answers":{"false":{"type":"noul","noul":0.0,"confidence":1.0,"answer_confidence":1.0,"action":{"act_probability":1.0}},"true":{"type":"noul","noul":1.0,"confidence":1.0,"answer_confidence":1.0,"action":{"act_probability":0.0}}}}, +{"name":"temperature-clamps","questions":[{"id":"choice","kind":"choice","criteria":{"a":null,"b":null}},{"id":"score","kind":"score","criteria":["low","mid","high"]}],"logits":[[-0.4,0.6],[-0.4,0.6,1.6]],"action_logits":[[-1.0,1.0],[2.0,-2.0]],"config":{"temperature":[0.01,80.0,1.0],"temperature_by_options":{}},"answers":{"choice":{"type":"choice","choice":"b","probabilities":{"a":0.1192,"b":0.8808},"confidence":0.4729,"answer_confidence":0.8808,"action":{"act_probability":0.1192}},"score":{"type":"score","score":1.1325,"legend":{"0":"low","1":"mid","2":"high"},"probabilities":{"0":0.2693,"1":0.3289,"2":0.4018},"confidence":0.012,"answer_confidence":0.4018,"action":{"act_probability":0.982}}}}, +{"name":"mixed-order","questions":[{"id":"z","kind":"score","criteria":["low","mid","high"]},{"id":"a","kind":"choice","criteria":{"later":"","earlier":""}},{"id":"m","kind":"noul","criteria":null}],"logits":[[-0.5,1.0,0.75],[0.5,-0.5],[0.0,0.0]],"action_logits":[[0.0,1.0],[2.0,-1.0],[-2.0,0.0]],"answers":{"z":{"type":"score","score":1.244,"legend":{"0":"low","1":"mid","2":"high"},"probabilities":{"0":0.1422,"1":0.4716,"2":0.3862},"confidence":0.0904,"answer_confidence":0.4716,"action":{"act_probability":0.2689}},"a":{"type":"choice","choice":"later","probabilities":{"later":0.6282,"earlier":0.3718},"confidence":0.048,"answer_confidence":0.6282,"action":{"act_probability":0.9526}},"m":{"type":"noul","noul":0.5,"confidence":0.5,"answer_confidence":0.5,"action":{"act_probability":0.1192}}}}, +{"name":"score-bucket-override","questions":[{"id":"q","kind":"score","criteria":[0,1,2,3,4,5]}],"logits":[[-2.0,-1.0,0.0,0.5,1.0,3.0]],"action_logits":[[-0.25,0.75]],"config":{"temperature":[1.0,1.0,1.0],"temperature_by_options":{"score:6-10":4.0}},"answers":{"q":{"type":"score","score":3.1649,"legend":{"0":0,"1":1,"2":2,"3":3,"4":4,"5":5},"probabilities":{"0":0.0877,"1":0.1126,"2":0.1445,"3":0.1638,"4":0.1856,"5":0.3059},"confidence":0.0456,"answer_confidence":0.3059,"action":{"act_probability":0.2689}}}}, +{"name":"rounding-boundaries","questions":[{"id":"prob-low","kind":"choice","criteria":{"a":null,"b":null}},{"id":"prob-high","kind":"choice","criteria":{"a":null,"b":null}},{"id":"entropy-low","kind":"choice","criteria":{"a":null,"b":null}},{"id":"entropy-high","kind":"choice","criteria":{"a":null,"b":null}}],"logits":[[1.3866006392615888,0.0],[1.3866131416059737,0.0],[1.3862165,0.0],[1.3862353,0.0]],"action_logits":[[-0.25,0.75],[-0.25,0.75],[-0.25,0.75],[-0.25,0.75]],"config":{"temperature":[1.0,1.0,1.0],"temperature_by_options":{}},"answers":{"prob-low":{"type":"choice","choice":"a","probabilities":{"a":0.8,"b":0.2},"confidence":0.2782,"answer_confidence":0.8,"action":{"act_probability":0.2689}},"prob-high":{"type":"choice","choice":"a","probabilities":{"a":0.8001,"b":0.1999},"confidence":0.2782,"answer_confidence":0.8001,"action":{"act_probability":0.2689}},"entropy-low":{"type":"choice","choice":"a","probabilities":{"a":0.8,"b":0.2},"confidence":0.278,"answer_confidence":0.8,"action":{"act_probability":0.2689}},"entropy-high":{"type":"choice","choice":"a","probabilities":{"a":0.8,"b":0.2},"confidence":0.2781,"answer_confidence":0.8,"action":{"act_probability":0.2689}}}}, +{"name":"empty","questions":[],"logits":[],"action_logits":[],"answers":{}} +],"rounding_probe":{"name":"fp32-reduction-boundary","questions":[{"id":"q","kind":"choice","criteria":{"0":null,"1":null,"2":null,"3":null,"4":null,"5":null,"6":null,"7":null,"8":null,"9":null,"10":null,"11":null,"12":null,"13":null,"14":null,"15":null}}],"logits":[[-1.7411574125289917,-0.19089631736278534,-0.6029739379882812,-0.8184939026832581,0.16066476702690125,-0.4026077389717102,0.343989759683609,-0.600969135761261,0.8842262029647827,-0.26977965235710144,-0.7890094518661499,0.2582162916660309,0.85430908203125,-0.11924569308757782,0.9091809988021851,-0.00020837262854911387]],"action_logits":[[0.0,0.0]],"config":{"temperature":[1.0,1.0,1.0],"temperature_by_options":{}},"answers":{"q":{"type":"choice","choice":"14","probabilities":{"0":0.0101,"1":0.0474,"2":0.0314,"3":0.0253,"4":0.0673,"5":0.0383,"6":0.0809,"7":0.0314,"8":0.1388,"9":0.0438,"10":0.026,"11":0.0742,"12":0.1347,"13":0.0509,"14":0.1423,"15":0.0573},"confidence":0.072,"answer_confidence":0.1423,"action":{"act_probability":0.5}}}}} diff --git a/tests/laya/data/requests.json b/tests/laya/data/requests.json new file mode 100644 index 00000000..44827a11 --- /dev/null +++ b/tests/laya/data/requests.json @@ -0,0 +1 @@ +[{"name":"choice","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds","technical":"Software problems"},"instructions":"Which team should handle this?","type":"choice"}},"state":"I was charged twice for my order. Please refund the duplicate today."}},{"name":"score","request":{"model":"english","questions":{"urgency":{"criteria":["Not urgent","Needs attention soon","Needs attention immediately"],"instructions":"How urgent is the request?","type":"score"}},"state":"I was charged twice for my order. Please refund the duplicate today."}},{"name":"short_1","request":{"model":"english","questions":{"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"}},"state":"I was charged twice for my order. Please refund the duplicate today."}},{"name":"short_3","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds","technical":"Software problems"},"instructions":"Which team should handle this?","type":"choice"},"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"},"urgency":{"criteria":["Not urgent","Needs attention soon","Needs attention immediately"],"instructions":"How urgent is the request?","type":"score"}},"state":"I was charged twice for my order. Please refund the duplicate today."}},{"name":"medium_1","request":{"model":"english","questions":{"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"}},"state":"I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today."}},{"name":"medium_3","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds","technical":"Software problems"},"instructions":"Which team should handle this?","type":"choice"},"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"},"urgency":{"criteria":["Not urgent","Needs attention soon","Needs attention immediately"],"instructions":"How urgent is the request?","type":"score"}},"state":"I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today."}},{"name":"long_1","request":{"model":"english","questions":{"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"}},"state":"I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today."}},{"name":"long_3","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds","technical":"Software problems"},"instructions":"Which team should handle this?","type":"choice"},"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"},"urgency":{"criteria":["Not urgent","Needs attention soon","Needs attention immediately"],"instructions":"How urgent is the request?","type":"score"}},"state":"I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today."}},{"name":"negative_3","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds","technical":"Software problems"},"instructions":"Which team should handle this?","type":"choice"},"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"},"urgency":{"criteria":["Not urgent","Needs attention soon","Needs attention immediately"],"instructions":"How urgent is the request?","type":"score"}},"state":"The software crashes when I open settings. My payment is correct. I do not want a refund."}},{"name":"conversation_3","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds","technical":"Software problems"},"instructions":"Which team should handle this?","type":"choice"},"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"},"urgency":{"criteria":["Not urgent","Needs attention soon","Needs attention immediately"],"instructions":"How urgent is the request?","type":"score"}},"state":[{"content":"I need help with the software.","role":"user"},{"content":"I was charged twice for my order. Please refund the duplicate today.","role":"user"}]}},{"name":"truncated_3","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds","technical":"Software problems"},"instructions":"Which team should handle this?","type":"choice"},"refund":{"instructions":"Does the customer ask for a refund?","type":"noul"},"urgency":{"criteria":["Not urgent","Needs attention soon","Needs attention immediately"],"instructions":"How urgent is the request?","type":"score"}},"state":"I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today. I was charged twice for my order. Please refund the duplicate today."}},{"name":"single_option","request":{"model":"english","questions":{"department":{"criteria":{"billing":"Charges and refunds"},"instructions":"Which team should handle this?","type":"choice"}},"state":"I was charged twice for my order. Please refund the duplicate today."}}] diff --git a/tests/laya/decision.rs b/tests/laya/decision.rs new file mode 100644 index 00000000..4b00730e --- /dev/null +++ b/tests/laya/decision.rs @@ -0,0 +1,207 @@ +use omni_laya::{ + config::AgentConfig, + decision::decode, + preprocess::{Prepared, Question}, +}; +use serde_json::{Value, json}; +use std::collections::HashMap; + +fn config(value: &Value) -> AgentConfig { + AgentConfig { + max_len: 512, + head_max_len: 192, + head_layers: 2, + temperature: serde_json::from_value(value["temperature"].clone()).unwrap(), + temperature_by_options: serde_json::from_value(value["temperature_by_options"].clone()) + .unwrap(), + } +} + +fn prepared(questions: &Value) -> Prepared { + Prepared { + questions: questions + .as_array() + .unwrap() + .iter() + .map(|q| { + let kind = q["kind"].as_str().unwrap(); + let (qtype, count) = match kind { + "choice" => (0, q["criteria"].as_object().unwrap().len()), + "score" => (1, q["criteria"].as_array().unwrap().len()), + "noul" => (2, 2), + _ => panic!("unknown fixture type"), + }; + Question { + id: q["id"].as_str().unwrap().to_owned(), + kind: kind.to_owned(), + criteria: q["criteria"].clone(), + ids: Vec::new(), + markers: (0..count).collect(), + qtype, + } + }) + .collect(), + usage: 0, + } +} + +fn valid() -> (Prepared, AgentConfig) { + ( + prepared(&json!([{"id":"q", "kind":"choice", "criteria":{"z":null,"a":null}}])), + AgentConfig { + max_len: 512, + head_max_len: 192, + head_layers: 2, + temperature: vec![1.0; 3], + temperature_by_options: HashMap::new(), + }, + ) +} + +#[test] +fn matches_official_decode_reference() { + let fixture: Value = serde_json::from_str(include_str!("data/decisions.json")).unwrap(); + assert_eq!(fixture["reference"]["laya"], "0.3.20"); + for case in fixture["cases"].as_array().unwrap() { + let input = prepared(&case["questions"]); + let cfg = config(case.get("config").unwrap_or(&fixture["config"])); + let logits: Vec> = serde_json::from_value(case["logits"].clone()).unwrap(); + let actions: Vec<[f32; 2]> = serde_json::from_value(case["action_logits"].clone()).unwrap(); + let answers = decode(&input, &cfg, &logits, &actions).unwrap(); + assert_eq!( + Value::Object(answers.clone()), + case["answers"], + "{}", + case["name"] + ); + assert_eq!( + answers.keys().collect::>(), + input.questions.iter().map(|q| &q.id).collect::>() + ); + for question in &input.questions { + if question.kind == "choice" { + assert_eq!( + answers[&question.id]["probabilities"] + .as_object() + .unwrap() + .keys() + .collect::>(), + question + .criteria + .as_object() + .unwrap() + .keys() + .collect::>() + ); + } + } + } +} + +#[test] +fn fp32_reduction_boundary_preserves_answer() { + let fixture: Value = serde_json::from_str(include_str!("data/decisions.json")).unwrap(); + let case = &fixture["rounding_probe"]; + let input = prepared(&case["questions"]); + let cfg = config(&case["config"]); + let logits: Vec> = serde_json::from_value(case["logits"].clone()).unwrap(); + let actions: Vec<[f32; 2]> = serde_json::from_value(case["action_logits"].clone()).unwrap(); + let mut actual = Value::Object(decode(&input, &cfg, &logits, &actions).unwrap()); + let expected = &case["answers"]; + let probabilities = actual["q"]["probabilities"].as_object_mut().unwrap(); + let reference = expected["q"]["probabilities"].as_object().unwrap(); + assert_eq!( + probabilities.keys().collect::>(), + reference.keys().collect::>() + ); + for (key, value) in probabilities { + let error = (value.as_f64().unwrap() - reference[key].as_f64().unwrap()).abs(); + assert!(error <= 0.0001 + 1e-12, "option {key}: {error}"); + // Only this probe's probabilities allow one displayed decimal unit. + *value = reference[key].clone(); + } + assert_eq!(&actual, expected); +} + +#[test] +fn rejects_bad_row_counts_and_nonfinite_outputs() { + let (input, cfg) = valid(); + assert!(decode(&input, &cfg, &[], &[]).is_err()); + assert!(decode(&input, &cfg, &[vec![0.0, 1.0]], &[]).is_err()); + for logits in [ + vec![], + vec![1.0], + vec![0.0, f32::NAN], + vec![0.0, f32::INFINITY], + ] { + assert!(decode(&input, &cfg, &[logits], &[[0.0, 0.0]]).is_err()); + } + assert!(decode(&input, &cfg, &[vec![0.0, 1.0]], &[[f32::NEG_INFINITY, 0.0]]).is_err()); +} + +#[test] +fn rejects_inconsistent_question_metadata() { + for mutation in 0..7 { + let (mut input, cfg) = valid(); + let q = &mut input.questions[0]; + match mutation { + 0 => q.qtype = -1, + 1 => q.kind = "unknown".into(), + 2 => q.criteria = json!(["z", "a"]), + 3 => q.criteria = json!({"z":null}), + 4 => { + q.kind = "score".into(); + q.qtype = 1; + } + 5 => { + q.kind = "noul".into(); + q.qtype = 2; + q.markers.push(2); + } + _ => q.markers.clear(), + } + let raw = vec![0.0; q.markers.len()]; + assert!( + decode(&input, &cfg, &[raw], &[[0.0, 0.0]]).is_err(), + "mutation {mutation}" + ); + } + let (mut input, cfg) = valid(); + input.questions.extend(valid().0.questions); + assert!( + decode( + &input, + &cfg, + &[vec![0.0, 1.0], vec![0.0, 1.0]], + &[[0.0, 0.0]; 2] + ) + .is_err() + ); +} + +#[test] +fn rejects_invalid_temperatures_and_scaling_overflow() { + for temperatures in [ + vec![], + vec![1.0; 2], + vec![1.0; 4], + vec![0.0; 3], + vec![f32::NAN; 3], + ] { + let (input, mut cfg) = valid(); + cfg.temperature = temperatures; + assert!(decode(&input, &cfg, &[vec![0.0, 1.0]], &[[0.0, 0.0]]).is_err()); + } + let (input, mut cfg) = valid(); + cfg.temperature_by_options + .insert("choice:2".into(), f32::INFINITY); + assert!(decode(&input, &cfg, &[vec![0.0, 1.0]], &[[0.0, 0.0]]).is_err()); + cfg.temperature_by_options.insert("choice:2".into(), 0.5); + assert!( + decode(&input, &cfg, &[vec![f32::MAX, 0.0]], &[[0.0, 0.0]]) + .unwrap_err() + .to_string() + .contains("overflow") + ); + assert!(decode(&input, &cfg, &[vec![0.0, 1.0]], &[[0.0, 0.0]]).is_ok()); +} diff --git a/tests/laya/model.rs b/tests/laya/model.rs new file mode 100644 index 00000000..12dff82e --- /dev/null +++ b/tests/laya/model.rs @@ -0,0 +1,29 @@ +use super::storage_dtype; + +#[test] +fn resident_precision_matches_cuda_consumers() { + for (name, expected) in [ + ("encoder.embeddings.tok_embeddings.weight", "f16"), + ("encoder.embeddings.norm.weight", "f32"), + ("encoder.layers.1.attn_norm.weight", "f32"), + ("encoder.layers.0.attn.Wqkv.weight", "bf16"), + ("head.layers.0.norm1.bias", "f32"), + ("head.layers.0.self_attn.in_proj_bias", "f32"), + ("head.layers.0.self_attn.in_proj_weight", "bf16"), + ("scorer.0.bias", "f32"), + ("scorer.1.bias", "bf16"), + ("act_head.2.weight", "bf16"), + ("temperature", "f32"), + ] { + assert_eq!(storage_dtype(name), expected, "{name}"); + } + let inventory = crate::weights::checkpoint_tensors(); + assert_eq!(inventory.len(), 206); + assert_eq!( + inventory + .iter() + .filter(|t| storage_dtype(&t.name) == "f16") + .count(), + 1 + ); +} diff --git a/tests/laya/packing.rs b/tests/laya/packing.rs new file mode 100644 index 00000000..bd753d82 --- /dev/null +++ b/tests/laya/packing.rs @@ -0,0 +1,62 @@ +use omni_laya::preprocess::{Preprocessor, Request}; +use serde_json::Value; +use sha2::{Digest, Sha256}; +use std::path::PathBuf; + +fn checked_file(variable: &str, sha256: &str) -> PathBuf { + let path = + PathBuf::from(std::env::var_os(variable).unwrap_or_else(|| panic!("set {variable}"))); + let bytes = std::fs::read(&path).unwrap(); + assert_eq!( + format!("{:x}", Sha256::digest(&bytes)), + sha256, + "{variable}" + ); + path +} + +#[test] +#[ignore = "requires pinned tokenizer and packing oracle; run by CPU CI, no GPU"] +fn official_packing_parity() { + let tokenizer = checked_file( + "LAYA_TOKENIZER", + "6c8aaa9a542084f2457eab775d4eeb51f92a70c0fd9de28d5edb0ddec3c08d30", + ); + let oracle = checked_file( + "LAYA_PACKING_ORACLE", + "8cbaa311a59924ac9f9f2ba6f8438f82dafbd08476f64e86868289c2ede67f60", + ); + let pre = Preprocessor::load(&tokenizer).unwrap(); + let cases: Vec = serde_json::from_slice(&std::fs::read(oracle).unwrap()).unwrap(); + assert_eq!(cases.len(), 17); + for case in cases { + let request: Request = Request::from_value(case["request"].clone()).unwrap(); + let got = pre.prepare(&request).unwrap(); + let expected = &case["expected"]; + let items = expected["items"].as_array().unwrap(); + assert_eq!( + got.questions.len(), + items.len(), + "{} row count", + case["name"] + ); + assert_eq!(got.usage, expected["usage"].as_u64().unwrap() as usize); + for (i, ((question, item), id)) in got + .questions + .iter() + .zip(items) + .zip(request.questions.keys()) + .enumerate() + { + assert_eq!(&question.id, id, "{} row order", case["name"]); + let actual = serde_json::to_value(question).unwrap(); + for key in ["ids", "markers", "qtype"] { + assert_eq!(actual[key], item[key], "{} row {i} {key}", case["name"]); + } + assert_eq!( + question.ids.len(), + expected["lens"][i].as_u64().unwrap() as usize + ); + } + } +} diff --git a/tests/laya/preprocess.rs b/tests/laya/preprocess.rs new file mode 100644 index 00000000..0cbcc058 --- /dev/null +++ b/tests/laya/preprocess.rs @@ -0,0 +1,318 @@ +use omni_laya::preprocess::{Preprocessor, Request, render}; +use serde::Deserialize; +use serde_json::{Map, Value, json}; +use tokenizers::{Tokenizer, models::wordlevel::WordLevel, pre_tokenizers::whitespace::Whitespace}; + +// Small tokenizer for validation and packing boundaries; official parity is in packing.rs. +fn preprocessor() -> (tempfile::TempDir, Preprocessor) { + let dir = tempfile::tempdir().unwrap(); + let mut tokenizer = Tokenizer::new( + WordLevel::builder() + .vocab( + ["[UNK]", "[CLS]", "[SEP]", "[MASK]", "old", "new"] + .into_iter() + .enumerate() + .map(|(i, token)| (token.to_owned(), i as u32)) + .collect(), + ) + .unk_token("[UNK]".to_owned()) + .build() + .unwrap(), + ); + tokenizer.with_pre_tokenizer(Some(Whitespace)); + let path = dir.path().join("tokenizer.json"); + tokenizer.save(&path, false).unwrap(); + let pre = Preprocessor::load(&path).unwrap(); + (dir, pre) +} + +#[test] +fn python_json_numbers_and_order() { + for (input, expected) in [ + ("1e-6", "1e-06"), + ("1e20", "1e+20"), + ("1e16", "1e+16"), + ("1e-4", "0.0001"), + ("1.0", "1.0"), + ("-0.0", "-0.0"), + ("1331752170181752.2", "1331752170181752.2"), + ("-243915020125850.12", "-243915020125850.12"), + ("1e-5", "1e-05"), + ("5e-324", "5e-324"), + ("18446744073709551616000", "18446744073709551616000"), + ] { + assert_eq!(render(&serde_json::from_str(input).unwrap()), expected); + } + let v = serde_json::from_str(r#"{"z":1e-6,"a":"你好,x:y"}"#).unwrap(); + assert_eq!(render(&v), r#"{"z": 1e-06, "a": "你好,x:y"}"#); +} + +#[test] +fn strips_python_whitespace_from_noul_labels() { + let (_dir, pre) = preprocessor(); + let packed = |label| { + let request: Request = Request::from_value(json!({ + "state":"", "questions":{"q":{"type":"noul","instructions":"New?", + "labels":{"false":label,"true":"new"}}} + })) + .unwrap(); + pre.prepare(&request).unwrap().questions.remove(0).ids + }; + assert_eq!(packed("\u{1c}old\u{1f}"), packed("old")); + let invalid: Request = Request::from_value(json!({ + "state":"", "questions":{"q":{"type":"noul","instructions":"New?", + "labels":{"false":"\u{1c}\u{1f}","true":"new"}}} + })) + .unwrap(); + assert!( + pre.prepare(&invalid) + .unwrap_err() + .to_string() + .contains("invalid noul labels") + ); +} + +#[test] +fn validation_names_the_question_and_leaves_preprocessor_usable() { + let (_dir, pre) = preprocessor(); + for definition in [ + json!({"type":"choice","instructions":"Pick","criteria":[]}), + json!({"type":"noul","instructions":"Pick","criteria":{"yes":"ok"}}), + json!({"type":"noul","instructions":"Pick","labels":{"false":"x","true":"x"}}), + json!({"type":"score","criteria":["low","high"]}), + ] { + let request: Request = Request::from_value(json!({ + "state":"new", "questions":{"broken":definition} + })) + .unwrap(); + assert!( + pre.prepare(&request) + .unwrap_err() + .to_string() + .contains("broken") + ); + } + let request: Request = Request::from_value(json!({ + "state":"new", "questions":{"valid":{"type":"noul","instructions":"New?"}} + })) + .unwrap(); + assert_eq!(pre.prepare(&request).unwrap().questions.len(), 1); +} + +#[test] +fn preserves_question_and_choice_order() { + let (_dir, pre) = preprocessor(); + let request: Request = Request::from_json( + r#"{"state":"","questions":{ + "z":{"type":"choice","instructions":"Pick","criteria":["new","old","new"]}, + "a":{"type":"noul","instructions":"New?"} + }}"#, + ) + .unwrap(); + let prepared = pre.prepare(&request).unwrap(); + assert_eq!(prepared.questions[0].id, "z"); + assert_eq!(prepared.questions[1].id, "a"); + let choice = &prepared.questions[0]; + assert_eq!(choice.markers.len(), 2); + assert_eq!(choice.ids[choice.markers[0] + 1], 5); + assert_eq!(choice.ids[choice.markers[1] + 1], 4); + assert_eq!( + prepared.usage, + prepared + .questions + .iter() + .map(|q| q.ids.len()) + .sum::() + ); +} + +#[test] +fn keeps_newest_conversation_and_start_of_plain_text() { + let (_dir, pre) = preprocessor(); + for state in [ + json!(format!("{} new", "old ".repeat(1000))), + json!(["old ".repeat(1000), "new"]), + ] { + let is_conversation = state.is_array(); + let request: Request = Request::from_value(json!({ + "state":state, "questions":{"q":{"type":"noul","instructions":"New?"}} + })) + .unwrap(); + let prepared = pre.prepare(&request).unwrap(); + let ids = &prepared.questions[0].ids; + assert_eq!(ids.len(), 512); + assert_eq!(ids.contains(&5), is_conversation); + } +} + +#[test] +fn rejects_truncated_option_markers() { + let (_dir, pre) = preprocessor(); + let criteria: Vec<_> = (0..300).map(|i| i.to_string()).collect(); + let request: Request = Request::from_value(json!({ + "state":"", "questions":{"q":{"type":"choice","instructions":"Pick","criteria":criteria}} + })) + .unwrap(); + assert!( + pre.prepare(&request) + .unwrap_err() + .to_string() + .contains("options exceed") + ); +} + +#[test] +fn rejects_unsupported_language_and_nonfinite_numbers() { + let (_dir, pre) = preprocessor(); + for input in [ + r#"{"state":"","lang":"de","questions":{}}"#, + r#"{"state":"","model":"multilingual","questions":{}}"#, + r#"{"state":1e400,"questions":{}}"#, + ] { + assert!(pre.prepare(&Request::from_json(input).unwrap()).is_err()); + } +} + +#[test] +fn private_json_keys_stay_objects_in_raw_requests() { + let (_dir, pre) = preprocessor(); + for key in [ + "$serde_json::private::Number", + "$serde_json::private::RawValue", + ] { + let state = json!({"outer": [{(key): "1.5"}]}); + let questions = json!({ + "z": {"type": "choice", "instructions": {(key): "2"}, + "criteria": {"new": [{(key): "3"}], "old": null}}, + "a": {"type": "noul", "instructions": "New?"} + }) + .as_object() + .unwrap() + .clone(); + let expected = Request { + state, + model: None, + questions, + lang: None, + }; + let encoded = serde_json::to_string(&expected).unwrap(); + let request: Request = Request::from_json(&encoded).unwrap(); + assert_eq!(request.state, expected.state, "{key}"); + assert_eq!(request.questions, expected.questions, "{key}"); + assert_eq!(serde_json::to_string(&request).unwrap(), encoded); + assert_eq!( + render(&request.state), + format!(r#"{{"outer": [{{"{key}": "1.5"}}]}}"#) + ); + let packed = pre.prepare(&request).unwrap(); + let expected_packed = pre.prepare(&expected).unwrap(); + assert_eq!( + packed.questions[0].criteria, + expected_packed.questions[0].criteria + ); + assert_eq!(packed.questions[0].ids, expected_packed.questions[0].ids); + assert_eq!(packed.questions[0].id, "z"); + assert_eq!(packed.questions[1].id, "a"); + } +} + +#[test] +fn private_json_keys_stay_objects_from_value() { + for key in [ + "$serde_json::private::RawValue", + "$serde_json::private::Number", + ] { + let value = json!({"state": {(key): "1.5"}, "questions": { + "q": {"type": "score", "instructions": "New?", + "criteria": [{"outer": {(key): "2"}}]} + }}); + let request: Request = Request::from_value(value.clone()).unwrap(); + assert_eq!(request.state, value["state"]); + assert_eq!(Value::Object(request.questions), value["questions"]); + } +} + +#[test] +fn request_numbers_keep_arbitrary_precision_and_syntax() { + for number in [ + "18446744073709551616000", + "-18446744073709551616000", + "1e+03", + "1.2300", + "-0", + "1e400", + ] { + let encoded = + format!(r#"{{"state":[{number}],"questions":{{"q":{{"criteria":[{number}]}}}}}}"#); + let request: Request = Request::from_json(&encoded).unwrap(); + let scalar: Value = serde_json::from_str(number).unwrap(); + assert_eq!(request.state[0], scalar); + assert_eq!(request.questions["q"]["criteria"][0], scalar); + let roundtrip: Request = + Request::from_value(serde_json::to_value(&request).unwrap()).unwrap(); + assert_eq!(roundtrip.state, request.state); + assert_eq!(roundtrip.questions, request.questions); + } +} + +#[test] +fn request_keeps_default_json_recursion_limit() { + #[derive(Deserialize)] + struct Reference { + #[serde(rename = "state")] + _state: Value, + #[serde(rename = "questions")] + _questions: Map, + } + for depth in [124, 125, 126, 127, 128, 200] { + let nested = format!("{}0{}", "[".repeat(depth), "]".repeat(depth)); + for encoded in [ + format!(r#"{{"state":{nested},"questions":{{}}}}"#), + format!(r#"{{"state":null,"questions":{{"q":{{"criteria":{nested}}}}}}}"#), + ] { + let expected = serde_json::from_str::(&encoded).is_ok(); + let actual = Request::from_json(&encoded); + assert_eq!(actual.is_ok(), expected, "depth {depth}: {encoded}"); + if !expected { + assert!(actual.unwrap_err().to_string().contains("recursion limit")); + } + } + } +} + +#[test] +fn request_from_value_preserves_deep_values() { + let mut nested = json!({"$serde_json::private::Number": "1.5"}); + for _ in 0..200 { + nested = Value::Array(vec![nested]); + } + let value = json!({"state": nested.clone(), "questions": { + "q": {"criteria": nested.clone()} + }}); + let request = Request::from_value(value).unwrap(); + assert_eq!(request.state, nested); + assert_eq!(request.questions["q"]["criteria"], nested); + let request = Request::from_value(serde_json::to_value(&request).unwrap()).unwrap(); + assert_eq!(request.state, nested); +} + +#[test] +fn request_rejects_invalid_json_values() { + for state in ["NaN", "01", "[1,]", r#""\ud800""#] { + let encoded = format!(r#"{{"state":{state},"questions":{{}}}}"#); + assert!(Request::from_json(&encoded).is_err(), "{state}"); + } + assert!(Request::from_json(r#"{"state":null,"questions":[]}"#).is_err()); + for encoded in [ + r#"{"state":null,"questions":{},"extra":1}"#, + r#"{"state":null,"state":1,"questions":{}}"#, + r#"{"state":null}"#, + r#"{"questions":{}}"#, + r#"{"state":null,"questions":{},"lang":1}"#, + r#"[{"state":null,"questions":{}}]"#, + ] { + assert!(Request::from_json(encoded).is_err(), "{encoded}"); + } + let request = Request::from_json(r#"{"state":{"x":1,"x":2},"questions":{}}"#).unwrap(); + assert_eq!(request.state["x"], 2); +} diff --git a/tests/laya/unit/decision.rs b/tests/laya/unit/decision.rs new file mode 100644 index 00000000..eb098a8c --- /dev/null +++ b/tests/laya/unit/decision.rs @@ -0,0 +1,8 @@ +use super::round4; + +#[test] +fn rounding_matches_python_at_decimal_boundaries() { + for (value, expected) in [(0.00035, 0.0003), (0.12345, 0.1235), (-0.00035, -0.0003)] { + assert_eq!(round4(value), expected); + } +} diff --git a/tests/qwen3_5/json.rs b/tests/qwen3_5/json.rs index 4a1edc5c..9b17ca0e 100644 --- a/tests/qwen3_5/json.rs +++ b/tests/qwen3_5/json.rs @@ -1,5 +1,16 @@ use super::*; +#[test] +fn precision_features_preserve_numbers_and_private_marker_keys() { + let raw = br#"{"a":1.5,"b":1e-5,"$serde_json::private::Number":"literal","nested":{"$serde_json::private::RawValue":2}}"#; + let values = parse(raw).unwrap(); + assert_eq!(values["a"], serde_json::json!(1.5)); + assert_eq!(values["$serde_json::private::Number"], "literal"); + assert_eq!(values["nested"]["$serde_json::private::RawValue"], 2); + assert!(dumps(&Value::Object(values)).contains("\"b\": 1e-05")); + assert!(err(r#"{"a":{"b":1,"b":2}}"#).contains("duplicate key")); +} + fn err(body: &str) -> String { parse(body.as_bytes()).unwrap_err() } From eea6d7600d9a57d2d1257117c3fecedb9a573eec Mon Sep 17 00:00:00 2001 From: linear3735 Date: Mon, 5 Oct 2026 10:42:05 +0800 Subject: [PATCH 2/4] Document the implemented Laya native worker boundaries --- docs/architecture.md | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index b1988e80..958ce00a 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -8,23 +8,25 @@ design. Concrete input/output types follow each executor's supported layout. The [Rust frontend](../src/frontend/README.md) currently forwards HTTP requests to separately running workers. Cua-S1 and Open-Jev have native Rust/CUDA workers -that share the [Qwen3.5/3.8 executor](../src/models/qwen3_5/native/). Their -model-specific workers coordinate independent processor and executor modules -through `prepare` → `execute` → `finish`. The shared Qwen executor accepts one -prompt per forward call. Both workers use the +that share the [Qwen3.5/3.8 executor](../src/models/qwen3_5/native/), which accepts +one prompt per forward call. [Laya's native worker](../src/models/laya/README.md) +uses a separate Hopper CUDA backend for one complete padded request. All three +coordinate independent processors and executors through +`prepare` → `execute` → `finish` and use the [native runtime](../src/runtime/README.md) for FIFO admission and blocking dispatch per loaded executor. Shared processing orchestration, batch budgets, compatibility grouping and dynamic batching are planned. -The native workers currently compute their decision heads on the CPU after -downloading the final hidden state. GPU head execution belongs to the target -model/backend integration. LAYA's native executor and the Metal backend are -also planned; Python workers retain their documented reference/serving roles. +Qwen workers compute their decision heads on the CPU after downloading the final +hidden state. Laya computes its scorer and action head on CUDA. Its fixed-shape +Graph captures Encoder/Decision; gather, scorer/action head and synchronized +readback remain outside capture. Native Metal remains planned; Python workers +retain their documented reference/serving roles. ## Native worker boundaries -Both native workers separate `processing.rs` from `executor.rs`; `engine.rs` -assembles them with a `SerialScheduler` per loaded executor, and the HTTP handler +The native workers separate `processing.rs` from `executor.rs`; their worker +assembly owns a `SerialScheduler` per loaded executor, and the HTTP handler coordinates the three stages. Preparation validates the entire request before any forward call and returns executor inputs plus a response context. The context retains question and candidate identity, usage, and response metadata outside the executor. @@ -33,13 +35,21 @@ and candidate identity, usage, and response metadata outside the executor. | --- | --- | --- | --- | | Cua-S1 | One unpadded token-ID vector and option count per question, in request order. | One FP32 answer-letter logit vector per question. | Per-question softmax, choice/confidence, ordered answers, and token usage. | | Open-Jev | Token-ID vectors grouped by question, then independent candidate, in request order. | One FP32 learned scalar per candidate in the same grouping. | Add the `noul` false logit of zero, calibrate across each complete question, and restore typed answers, usage, and metadata. | +| Laya | One padded request: token IDs, true lengths, question types and ordered option markers; at most 16 questions, 512 tokens per row and 2048 markers. | Per-question FP32 option logits and two action logits copied back after GPU heads. | Calibrate and decode ordered `choice`, `score` and `noul` answers, usage and metadata. | -These input collections are serial work, not GPU batches. Shared runtime +Qwen input collections are serial work, not GPU batches; Laya batches questions +within one request. Shared runtime admission precedes blocking dispatch: Cua-S1 admits one question forward at a -time; Open-Jev admits one complete request. Cua-S1's CPU letter projection stays -outside admission; Open-Jev's scalar heads remain inside its request unit. The -model mutexes guard mutable state, retaining per-question/request granularity. -Executors own the loaded Qwen model and CPU head weights, preserving FP64 accumulation and +time; Open-Jev and Laya admit one complete request. Cua-S1's CPU letter projection +stays outside admission; Open-Jev's scalar heads and Laya's GPU heads and +synchronized readback remain inside their request unit. Qwen model mutexes guard +mutable state. Laya's dedicated owning thread confines its non-Send CUDA state +and receives admitted work over a rendezvous channel. Cancellation after +dispatch retains the scheduler permit until execution completes. Laya +synchronizes and disposes a failed model before returning an inference error +and reports unavailable health thereafter. + +Qwen executors own loaded models and CPU head weights, preserving FP64 accumulation and the existing FP32 rounding and bias order. Finishing checks output cardinality before reconstruction. HTTP validation, error status/body conventions, and real warmup before readiness remain model-specific and unchanged. @@ -81,7 +91,9 @@ semantics. Cua-S1 prepares one prompt per question and reads option-letter logits. Open-Jev prepares independent candidate prompts and normalizes across the -complete question's candidates. A request, question, and GPU batch therefore +complete question's candidates. Laya pads prepared questions into one request +batch and normalizes each question's complete option set. A request, question, +and GPU batch therefore have different boundaries. Scheduler grouping must preserve those distinctions; probabilities must not be normalized across unrelated questions or requests. From 90f233607a22ef3e53270d342bf978530a90c31a Mon Sep 17 00:00:00 2001 From: linear3735 Date: Mon, 5 Oct 2026 10:45:14 +0800 Subject: [PATCH 3/4] Remove blank context whitespace from the reproduction patch --- recipe/laya/native/optimized-export.patch | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/recipe/laya/native/optimized-export.patch b/recipe/laya/native/optimized-export.patch index 9ee3b3ed..03463df8 100644 --- a/recipe/laya/native/optimized-export.patch +++ b/recipe/laya/native/optimized-export.patch @@ -1,7 +1,7 @@ --- a/src/backends/cuda/tools/export.py +++ b/src/backends/cuda/tools/export.py @@ -17,6 +17,18 @@ - + sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "kernels")) import laya_tilelang as kernels + @@ -16,7 +16,7 @@ + return laya_out_full(p,B,L,M,stream); +} +""" - + SLOT = re.compile( r"\(\(\(TVMFFIAny\*\)stack_ffi_any\)\[(\d+)\]\.v_(?:int64|ptr)\) = (.*);" @@ -48,6 +60,21 @@ @@ -38,8 +38,8 @@ + raise ValueError("long GEGLU register calls changed") + body = body.replace(call, "", 1) + return body - - + + def export(name, kernel): @@ -133,6 +160,8 @@ body = source[source.index('extern "C" __global__') :].replace( From 7b87adcbec0fd4e47779f000f65a9ca696fcbda1 Mon Sep 17 00:00:00 2001 From: linear3735 Date: Mon, 5 Oct 2026 11:02:22 +0800 Subject: [PATCH 4/4] Record fresh Laya CUDA CLI and HTTP acceptance --- recipe/laya/native/VALIDATION.md | 41 +- recipe/laya/native/measurements.json | 1343 +++++++++++++++++++++++++- 2 files changed, 1378 insertions(+), 6 deletions(-) diff --git a/recipe/laya/native/VALIDATION.md b/recipe/laya/native/VALIDATION.md index 39e30939..24232efb 100644 --- a/recipe/laya/native/VALIDATION.md +++ b/recipe/laya/native/VALIDATION.md @@ -43,11 +43,42 @@ not general model quality or all-input agreement with official PyTorch. ## Integration checks The current-main integration retains checkpoint inventory checks and imports the -reviewed CPU parsing/decoding fixes. Its processor/packing and worker scheduling -are new consumers of the same device code. Normal CPU tests do not establish -full-checkpoint CUDA or HTTP parity. Integration-specific Linux/GPU/worker and -frontend checks must bind the actual new build; the table above is historical -engine evidence, not a measurement of the newly integrated HTTP service. +reviewed CPU parsing/decoding fixes. Local checks passed: workspace fmt/clippy, +83 Rust tests (10 fixture/checkpoint/GPU tests ignored), release build, eight +CUDA build-entry tests, eight benchmark tests and strict docs build. + +Linux `laya-run`, `omni-laya` and `omni-jev` were built from commit +`10c14a34c870d9d4a6562e1dcf7ca787a716730f`. Subsequent changes only update docs +and normalize blank context lines in the baseline reproduction patch; execution +source and dependencies are byte-identical. The build used Rust 1.98.1 and the +same pinned CUDA library, checkpoint and fixtures as the engine comparison. + +The new binaries passed actual H800 acceptance with those 12 fixtures: + +- Graph and eager CLI: 24 complete JSON responses exactly match the fixed + official reference; all 24 raw-head results match the original native engine + with exact FP32 bits and request-derived row widths. +- Native worker and frontend proxy: 24 successful HTTP responses exactly match + the same official JSON. Four malformed-JSON/content-type requests return + 422/415, and four health checks report ready before and after rejection. +- All four child processes exit with code 0; the worker and frontend shut down + through SIGINT. Native process maps contain the registered CUDA library and + no Python/Torch runtime. The run's GPU processes and personal lock are released. + +JSON and raw-head comparisons use different references. The official reference +comes from Laya 0.3.20's fast Graph path with selected RoPE and BF16 autocast. +Four action values in `long_3`/`truncated_3` already differed from that reference +in the original native engine; they remain unchanged here. Therefore this check +establishes native implementation equivalence and exact response JSON for the +fixed inputs, not bitwise raw-head agreement with PyTorch or general model quality. +The first runner incorrectly mixed these two references; its failure was retained +and corrected by binding the original native raw outputs, without adding tolerance. + +Complete responses, per-call output digests, test counts, binary/fixture/library +identities and the original native raw reference are in `integration_validation` in +[measurements.json](measurements.json). These are functional checks; current +HTTP latency and inference-failure injection were not measured. The timing table +above remains historical engine evidence. Build and reproduction commands are in the [recipe](README.md). Full model weight/tokenizer oracle checks remain explicit opt-in tests, with their pinned diff --git a/recipe/laya/native/measurements.json b/recipe/laya/native/measurements.json index 109cf35d..cbbd1990 100644 --- a/recipe/laya/native/measurements.json +++ b/recipe/laya/native/measurements.json @@ -12643,5 +12643,1346 @@ } } } - ] + ], + "integration_validation": { + "scope": "Current-main integration functional acceptance only; no performance timings were rerun.", + "build_source_commit": "10c14a34c870d9d4a6562e1dcf7ca787a716730f", + "post_build_changes": "Documentation and reproduction-patch formatting only; all execution source bytes identical.", + "binaries_sha256": { + "cli": "cb7ac0f785b591acbf315f7b16206978e5b8c1927096fe9faff8242bc95513d6", + "worker": "0f3f5c53fab61e0d6316b3de9402b954e0d4086794f956d01a6cb89ffee2e915", + "frontend": "2f51d57ed9148930de5ca9ad4af7d09ab37b46c2bca37fd9e32183b6bab77345" + }, + "cuda_library_sha256": "eeb94478354b5b6f0b26c756263261dd61908a0aafd82f10b04b907c3d46cc36", + "fixtures_sha256": "c083a6ef84ad607307d91fd273ffb8d34c7bc4b5cdb4ddc87507c6be649c0f51", + "official_reference_sha256": "411eeec58f2af247d03eb579d1f5fe954397f65b9f5e1b6fb3d2281d9aeaa363", + "official_reference": "Laya 0.3.20 fast_graph with selected RoPE and BF16 autocast; full response JSON exact.", + "native_raw_reference_sha256": "d1acd7a66a5a4c362bfc99a375905a8e4c1605a195c363f2aac7a36aff137250", + "native_raw_reference_source": { + "original_cli_sha256": "4d31e8593ff67127c5c908c3bdba26db393165036027e58a5554b70567a71c85", + "original_cuda_library_sha256": "a95ee8e50065f2e39d8a6c8ced32e8ff434dd42903bd741040ea9205da79813e", + "original_flags": [ + "--original-rope" + ], + "original_stderr_sha256": "0d179c8e2ad395409bfad3c02d4b1dcf225bfb3d5de8d7c98777d64f8a581771", + "records": [ + { + "name": "choice", + "raw_logits": [ + [ + 4.3125, + -1.375 + ] + ], + "raw_actions": [ + [ + 4512.0, + -3696.0 + ] + ], + "raw_heads_f32_sha256": "ee264a2a968be1203766562677ffd0061347e4974ed15b86b23b912ca17adf47" + }, + { + "name": "score", + "raw_logits": [ + [ + -0.65234375, + 1.8046875, + 3.765625 + ] + ], + "raw_actions": [ + [ + 3952.0, + -3248.0 + ] + ], + "raw_heads_f32_sha256": "b9b8fc225c61fe39c9cfce353b83bebc2229d898bda716cc69585b11af58af8b" + }, + { + "name": "short_1", + "raw_logits": [ + [ + -3.25, + 1.5078125 + ] + ], + "raw_actions": [ + [ + 3984.0, + -3264.0 + ] + ], + "raw_heads_f32_sha256": "ed69244698d62986b43b80e92870f6b406c16c2a928001a18194d6302563e56e" + }, + { + "name": "short_3", + "raw_logits": [ + [ + 4.3125, + -1.375 + ], + [ + -3.25, + 1.5078125 + ], + [ + -0.65234375, + 1.8046875, + 3.765625 + ] + ], + "raw_actions": [ + [ + 4512.0, + -3696.0 + ], + [ + 3984.0, + -3264.0 + ], + [ + 3952.0, + -3248.0 + ] + ], + "raw_heads_f32_sha256": "b85c5724073e1b8ddf4434b2bdabc3a4e8fc887a1cc979912770189d8fae010e" + }, + { + "name": "medium_1", + "raw_logits": [ + [ + -3.234375, + 1.421875 + ] + ], + "raw_actions": [ + [ + 4288.0, + -3520.0 + ] + ], + "raw_heads_f32_sha256": "1a989cf54250bf2d1100c487b534684eeac6372000de256d1ae42cb1811e3e96" + }, + { + "name": "medium_3", + "raw_logits": [ + [ + 3.5, + -0.97265625 + ], + [ + -3.234375, + 1.421875 + ], + [ + 0.90234375, + 2.4375, + 3.15625 + ] + ], + "raw_actions": [ + [ + 4704.0, + -3856.0 + ], + [ + 4288.0, + -3520.0 + ], + [ + 4416.0, + -3616.0 + ] + ], + "raw_heads_f32_sha256": "23ffc6616a15f676a47568f85dc8d26606b9285609905d686059199ac92cc402" + }, + { + "name": "long_1", + "raw_logits": [ + [ + -2.34375, + 1.1953125 + ] + ], + "raw_actions": [ + [ + 4576.0, + -3744.0 + ] + ], + "raw_heads_f32_sha256": "c273945f581723f691ef7d701144e8b99da2d42921c6e4681625fccb822386f9" + }, + { + "name": "long_3", + "raw_logits": [ + [ + 3.28125, + -0.82421875 + ], + [ + -2.34375, + 1.1953125 + ], + [ + 1.4921875, + 2.4375, + 3.0 + ] + ], + "raw_actions": [ + [ + 4736.0, + -3888.0 + ], + [ + 4576.0, + -3744.0 + ], + [ + 4448.0, + -3632.0 + ] + ], + "raw_heads_f32_sha256": "2efd228099418855557996d07e54a2a8624aa86fb5cf46ae2263258a06f62c25" + }, + { + "name": "negative_3", + "raw_logits": [ + [ + 3.34375, + -0.70703125 + ], + [ + -0.50390625, + 0.9140625 + ], + [ + 2.8125, + 2.359375, + 1.7265625 + ] + ], + "raw_actions": [ + [ + 4672.0, + -3824.0 + ], + [ + 4672.0, + -3824.0 + ], + [ + 4064.0, + -3344.0 + ] + ], + "raw_heads_f32_sha256": "5449b562d0a3b34e718e60b6f83dd1a42c1d3ecc4e22bd1eb00a618499303dd0" + }, + { + "name": "conversation_3", + "raw_logits": [ + [ + 5.34375, + -1.796875 + ], + [ + -3.546875, + 1.5234375 + ], + [ + -0.14746094, + 1.3359375, + 3.203125 + ] + ], + "raw_actions": [ + [ + 4048.0, + -3312.0 + ], + [ + 3616.0, + -2960.0 + ], + [ + 4192.0, + -3424.0 + ] + ], + "raw_heads_f32_sha256": "a863be3ed258a2f44ba85074c6318b68fb11514beb03cf3e77bd9222f3894cfe" + }, + { + "name": "truncated_3", + "raw_logits": [ + [ + 3.234375, + -0.80078125 + ], + [ + -2.171875, + 1.1484375 + ], + [ + 1.4296875, + 2.421875, + 2.984375 + ] + ], + "raw_actions": [ + [ + 4736.0, + -3888.0 + ], + [ + 4640.0, + -3808.0 + ], + [ + 4416.0, + -3632.0 + ] + ], + "raw_heads_f32_sha256": "8a6a9bf358c302172536a1d82a5128c49be9f6dbc5579141387d701b8631623d" + }, + { + "name": "single_option", + "raw_logits": [ + [ + 3.109375 + ] + ], + "raw_actions": [ + [ + 4672.0, + -3824.0 + ] + ], + "raw_heads_f32_sha256": "92faee1ff53eb379ce8f43089a30c3a74fe796d52251c28547739f4e1337ee09" + } + ] + }, + "raw_comparison": "Exact f32 bits and request-derived ragged shapes; no numerical tolerance.", + "known_official_raw_action_differences": [ + { + "name": "long_3", + "field": "raw_actions", + "row": 0, + "column": 0, + "native_value": 4736.0, + "official_value": 4768.0, + "native_f32_hex": "00009445", + "official_f32_hex": "00009545", + "already_present_in_all_six_historical_groups": true, + "same_in_current_fresh_cli": true + }, + { + "name": "long_3", + "field": "raw_actions", + "row": 2, + "column": 1, + "native_value": -3632.0, + "official_value": -3648.0, + "native_f32_hex": "000063c5", + "official_f32_hex": "000064c5", + "already_present_in_all_six_historical_groups": true, + "same_in_current_fresh_cli": true + }, + { + "name": "truncated_3", + "field": "raw_actions", + "row": 0, + "column": 0, + "native_value": 4736.0, + "official_value": 4768.0, + "native_f32_hex": "00009445", + "official_f32_hex": "00009545", + "already_present_in_all_six_historical_groups": true, + "same_in_current_fresh_cli": true + }, + { + "name": "truncated_3", + "field": "raw_actions", + "row": 1, + "column": 0, + "native_value": 4640.0, + "official_value": 4672.0, + "native_f32_hex": "00009145", + "official_f32_hex": "00009245", + "already_present_in_all_six_historical_groups": true, + "same_in_current_fresh_cli": true + } + ], + "counts": { + "cli_complete_JSON_exact": 24, + "cli_raw_native_f32_exact": 24, + "HTTP_complete_JSON_exact": 24, + "HTTP_rejection": 4, + "HTTP_health": 4 + }, + "cli": [ + { + "mode": "graph", + "exit_code": 0, + "records": [ + { + "name": "choice", + "complete_response_sha256": "1b81057291839203db4c74ac4102a09a7406b2f0610aca678d9066950fb35bb1", + "raw_heads_f32_sha256": "ee264a2a968be1203766562677ffd0061347e4974ed15b86b23b912ca17adf47" + }, + { + "name": "score", + "complete_response_sha256": "bd3c7d983a54257d7be79208b7cb21d880ec11859eead308d07f836de13ac808", + "raw_heads_f32_sha256": "b9b8fc225c61fe39c9cfce353b83bebc2229d898bda716cc69585b11af58af8b" + }, + { + "name": "short_1", + "complete_response_sha256": "8aec5794b155f220a949017d4196ceeb7df4c8b3b7964db8cf411af44c5f805f", + "raw_heads_f32_sha256": "ed69244698d62986b43b80e92870f6b406c16c2a928001a18194d6302563e56e" + }, + { + "name": "short_3", + "complete_response_sha256": "6092c87796835a0161a810e6f76cc0f4b9601d71c73cadfe01b68d32b3d104e7", + "raw_heads_f32_sha256": "b85c5724073e1b8ddf4434b2bdabc3a4e8fc887a1cc979912770189d8fae010e" + }, + { + "name": "medium_1", + "complete_response_sha256": "964df739da5d27768c2a165913a0e52ae74054583accbb9e25d653674c6e44b6", + "raw_heads_f32_sha256": "1a989cf54250bf2d1100c487b534684eeac6372000de256d1ae42cb1811e3e96" + }, + { + "name": "medium_3", + "complete_response_sha256": "db6fe72709a50d4f399016c53b40658271c74460accc14265c6ecf99970545da", + "raw_heads_f32_sha256": "23ffc6616a15f676a47568f85dc8d26606b9285609905d686059199ac92cc402" + }, + { + "name": "long_1", + "complete_response_sha256": "12e30dade9cc9af48c0cbeaa04e24f227c38867a7ff01cab879c85866b93a648", + "raw_heads_f32_sha256": "c273945f581723f691ef7d701144e8b99da2d42921c6e4681625fccb822386f9" + }, + { + "name": "long_3", + "complete_response_sha256": "2c97d2d18eb24d1ddada69f4a23dffaa2f23ac82ec781ae5199886a2675c351f", + "raw_heads_f32_sha256": "2efd228099418855557996d07e54a2a8624aa86fb5cf46ae2263258a06f62c25" + }, + { + "name": "negative_3", + "complete_response_sha256": "3b0910e9d48d5e025fadbf0968a4f8a183b486d209f88204aa85f6569780b4ec", + "raw_heads_f32_sha256": "5449b562d0a3b34e718e60b6f83dd1a42c1d3ecc4e22bd1eb00a618499303dd0" + }, + { + "name": "conversation_3", + "complete_response_sha256": "84bf8608cf6f3633769beff446e85ee95b9857347aeb1fb756338bdc199e5638", + "raw_heads_f32_sha256": "a863be3ed258a2f44ba85074c6318b68fb11514beb03cf3e77bd9222f3894cfe" + }, + { + "name": "truncated_3", + "complete_response_sha256": "9a762165bd7f0a2b930b80158070490bda0884eb5350879173714ee7169c31ee", + "raw_heads_f32_sha256": "8a6a9bf358c302172536a1d82a5128c49be9f6dbc5579141387d701b8631623d" + }, + { + "name": "single_option", + "complete_response_sha256": "28c445cf42e2387581ea9245b70194a6ea50427aa4584b50b6be11cb51173099", + "raw_heads_f32_sha256": "92faee1ff53eb379ce8f43089a30c3a74fe796d52251c28547739f4e1337ee09" + } + ] + }, + { + "mode": "eager", + "exit_code": 0, + "records": [ + { + "name": "choice", + "complete_response_sha256": "1b81057291839203db4c74ac4102a09a7406b2f0610aca678d9066950fb35bb1", + "raw_heads_f32_sha256": "ee264a2a968be1203766562677ffd0061347e4974ed15b86b23b912ca17adf47" + }, + { + "name": "score", + "complete_response_sha256": "bd3c7d983a54257d7be79208b7cb21d880ec11859eead308d07f836de13ac808", + "raw_heads_f32_sha256": "b9b8fc225c61fe39c9cfce353b83bebc2229d898bda716cc69585b11af58af8b" + }, + { + "name": "short_1", + "complete_response_sha256": "8aec5794b155f220a949017d4196ceeb7df4c8b3b7964db8cf411af44c5f805f", + "raw_heads_f32_sha256": "ed69244698d62986b43b80e92870f6b406c16c2a928001a18194d6302563e56e" + }, + { + "name": "short_3", + "complete_response_sha256": "6092c87796835a0161a810e6f76cc0f4b9601d71c73cadfe01b68d32b3d104e7", + "raw_heads_f32_sha256": "b85c5724073e1b8ddf4434b2bdabc3a4e8fc887a1cc979912770189d8fae010e" + }, + { + "name": "medium_1", + "complete_response_sha256": "964df739da5d27768c2a165913a0e52ae74054583accbb9e25d653674c6e44b6", + "raw_heads_f32_sha256": "1a989cf54250bf2d1100c487b534684eeac6372000de256d1ae42cb1811e3e96" + }, + { + "name": "medium_3", + "complete_response_sha256": "db6fe72709a50d4f399016c53b40658271c74460accc14265c6ecf99970545da", + "raw_heads_f32_sha256": "23ffc6616a15f676a47568f85dc8d26606b9285609905d686059199ac92cc402" + }, + { + "name": "long_1", + "complete_response_sha256": "12e30dade9cc9af48c0cbeaa04e24f227c38867a7ff01cab879c85866b93a648", + "raw_heads_f32_sha256": "c273945f581723f691ef7d701144e8b99da2d42921c6e4681625fccb822386f9" + }, + { + "name": "long_3", + "complete_response_sha256": "2c97d2d18eb24d1ddada69f4a23dffaa2f23ac82ec781ae5199886a2675c351f", + "raw_heads_f32_sha256": "2efd228099418855557996d07e54a2a8624aa86fb5cf46ae2263258a06f62c25" + }, + { + "name": "negative_3", + "complete_response_sha256": "3b0910e9d48d5e025fadbf0968a4f8a183b486d209f88204aa85f6569780b4ec", + "raw_heads_f32_sha256": "5449b562d0a3b34e718e60b6f83dd1a42c1d3ecc4e22bd1eb00a618499303dd0" + }, + { + "name": "conversation_3", + "complete_response_sha256": "84bf8608cf6f3633769beff446e85ee95b9857347aeb1fb756338bdc199e5638", + "raw_heads_f32_sha256": "a863be3ed258a2f44ba85074c6318b68fb11514beb03cf3e77bd9222f3894cfe" + }, + { + "name": "truncated_3", + "complete_response_sha256": "9a762165bd7f0a2b930b80158070490bda0884eb5350879173714ee7169c31ee", + "raw_heads_f32_sha256": "8a6a9bf358c302172536a1d82a5128c49be9f6dbc5579141387d701b8631623d" + }, + { + "name": "single_option", + "complete_response_sha256": "28c445cf42e2387581ea9245b70194a6ea50427aa4584b50b6be11cb51173099", + "raw_heads_f32_sha256": "92faee1ff53eb379ce8f43089a30c3a74fe796d52251c28547739f4e1337ee09" + } + ] + } + ], + "http": [ + { + "role": "worker", + "name": "health", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "2ac56dba8a48e61da7ec9ce1c2f42b83b2205866555cf6f730ca86eebaac533b", + "response": { + "status": "ready", + "model": "laya-rl-agent" + } + }, + { + "role": "frontend", + "name": "health", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "2ac56dba8a48e61da7ec9ce1c2f42b83b2205866555cf6f730ca86eebaac533b", + "response": { + "status": "ready", + "model": "laya-rl-agent" + } + }, + { + "role": "worker", + "name": "choice", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "1b81057291839203db4c74ac4102a09a7406b2f0610aca678d9066950fb35bb1" + }, + { + "role": "frontend", + "name": "choice", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "1b81057291839203db4c74ac4102a09a7406b2f0610aca678d9066950fb35bb1" + }, + { + "role": "worker", + "name": "score", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "bd3c7d983a54257d7be79208b7cb21d880ec11859eead308d07f836de13ac808" + }, + { + "role": "frontend", + "name": "score", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "bd3c7d983a54257d7be79208b7cb21d880ec11859eead308d07f836de13ac808" + }, + { + "role": "worker", + "name": "short_1", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "8aec5794b155f220a949017d4196ceeb7df4c8b3b7964db8cf411af44c5f805f" + }, + { + "role": "frontend", + "name": "short_1", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "8aec5794b155f220a949017d4196ceeb7df4c8b3b7964db8cf411af44c5f805f" + }, + { + "role": "worker", + "name": "short_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "6092c87796835a0161a810e6f76cc0f4b9601d71c73cadfe01b68d32b3d104e7" + }, + { + "role": "frontend", + "name": "short_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "6092c87796835a0161a810e6f76cc0f4b9601d71c73cadfe01b68d32b3d104e7" + }, + { + "role": "worker", + "name": "medium_1", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "964df739da5d27768c2a165913a0e52ae74054583accbb9e25d653674c6e44b6" + }, + { + "role": "frontend", + "name": "medium_1", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "964df739da5d27768c2a165913a0e52ae74054583accbb9e25d653674c6e44b6" + }, + { + "role": "worker", + "name": "medium_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "db6fe72709a50d4f399016c53b40658271c74460accc14265c6ecf99970545da" + }, + { + "role": "frontend", + "name": "medium_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "db6fe72709a50d4f399016c53b40658271c74460accc14265c6ecf99970545da" + }, + { + "role": "worker", + "name": "long_1", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "12e30dade9cc9af48c0cbeaa04e24f227c38867a7ff01cab879c85866b93a648" + }, + { + "role": "frontend", + "name": "long_1", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "12e30dade9cc9af48c0cbeaa04e24f227c38867a7ff01cab879c85866b93a648" + }, + { + "role": "worker", + "name": "long_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "2c97d2d18eb24d1ddada69f4a23dffaa2f23ac82ec781ae5199886a2675c351f" + }, + { + "role": "frontend", + "name": "long_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "2c97d2d18eb24d1ddada69f4a23dffaa2f23ac82ec781ae5199886a2675c351f" + }, + { + "role": "worker", + "name": "negative_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "3b0910e9d48d5e025fadbf0968a4f8a183b486d209f88204aa85f6569780b4ec" + }, + { + "role": "frontend", + "name": "negative_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "3b0910e9d48d5e025fadbf0968a4f8a183b486d209f88204aa85f6569780b4ec" + }, + { + "role": "worker", + "name": "conversation_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "84bf8608cf6f3633769beff446e85ee95b9857347aeb1fb756338bdc199e5638" + }, + { + "role": "frontend", + "name": "conversation_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "84bf8608cf6f3633769beff446e85ee95b9857347aeb1fb756338bdc199e5638" + }, + { + "role": "worker", + "name": "truncated_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "9a762165bd7f0a2b930b80158070490bda0884eb5350879173714ee7169c31ee" + }, + { + "role": "frontend", + "name": "truncated_3", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "9a762165bd7f0a2b930b80158070490bda0884eb5350879173714ee7169c31ee" + }, + { + "role": "worker", + "name": "single_option", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "28c445cf42e2387581ea9245b70194a6ea50427aa4584b50b6be11cb51173099" + }, + { + "role": "frontend", + "name": "single_option", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "28c445cf42e2387581ea9245b70194a6ea50427aa4584b50b6be11cb51173099" + }, + { + "role": "worker", + "name": "malformed-json", + "status": 422, + "request_content_type": "application/json", + "content_type": "application/json", + "complete_response_sha256": "bd1da3aab2ef32c512c5877d52f23d0fb9417c533bccbb5927fd99fd7c2864f7", + "response": { + "error": "EOF while parsing an object at line 1 column 1" + } + }, + { + "role": "worker", + "name": "wrong-content-type", + "status": 415, + "request_content_type": "text/plain", + "content_type": "application/json", + "complete_response_sha256": "73481f2ed035a2888416b59fbe1470b602ac129bf637421fcc880f403496d930", + "response": { + "error": "Content-Type must be application/json" + } + }, + { + "role": "worker", + "name": "health-after-errors", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "2ac56dba8a48e61da7ec9ce1c2f42b83b2205866555cf6f730ca86eebaac533b", + "response": { + "status": "ready", + "model": "laya-rl-agent" + } + }, + { + "role": "frontend", + "name": "malformed-json", + "status": 422, + "request_content_type": "application/json", + "content_type": "application/json", + "complete_response_sha256": "bd1da3aab2ef32c512c5877d52f23d0fb9417c533bccbb5927fd99fd7c2864f7", + "response": { + "error": "EOF while parsing an object at line 1 column 1" + } + }, + { + "role": "frontend", + "name": "wrong-content-type", + "status": 415, + "request_content_type": "text/plain", + "content_type": "application/json", + "complete_response_sha256": "73481f2ed035a2888416b59fbe1470b602ac129bf637421fcc880f403496d930", + "response": { + "error": "Content-Type must be application/json" + } + }, + { + "role": "frontend", + "name": "health-after-errors", + "status": 200, + "content_type": "application/json", + "complete_response_sha256": "2ac56dba8a48e61da7ec9ce1c2f42b83b2205866555cf6f730ca86eebaac533b", + "response": { + "status": "ready", + "model": "laya-rl-agent" + } + } + ], + "execution_identity": { + "native_maps_checked": true, + "only_registered_laya_cuda_library": true, + "libpython_or_libtorch_in_native_maps": false, + "all_four_child_exit_codes": [ + 0, + 0, + 0, + 0 + ], + "all_four_children_reaped": true, + "own_processes_remaining_on_GPU": 0, + "personal_lock_released": true, + "readonly_assets_before_after_identical": true + }, + "original_evidence_sha256": { + "summary.json": "f228db016750649ab01975f49bbe2e0318dafad6e362796804bc541fe7526afb", + "cli-graph.stdout.log": "45ee41219af5f251bfb6042dea9dec2a93d4d3c95e70b945349aa36e55bf539d", + "cli-graph.stderr.log": "1bfc59df5d26de8f3defc8abadbcf05871fddedc69d9d053d59a5c0bce12a0f4", + "cli-eager.stdout.log": "45ee41219af5f251bfb6042dea9dec2a93d4d3c95e70b945349aa36e55bf539d", + "cli-eager.stderr.log": "9db125bfb2cff0d816be5807244d131022d8aa1fc6113f3f354390a58efc2984", + "http-responses.jsonl": "34a365c45994ab931632fa9c01bf1ad88e2aa4d51d4585cbe376a16c4d2c2cf7" + }, + "complete_responses": [ + { + "name": "choice", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 0.7214, + "answer_confidence": 0.9518, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 0.9518, + "technical": 0.0482 + }, + "choice": "billing" + } + }, + "usage": { + "input_tokens": 40, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "score", + "response": { + "model": "laya-rl-agent", + "answers": { + "urgency": { + "type": "score", + "confidence": 0.4892, + "answer_confidence": 0.8078, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "0": 0.0237, + "1": 0.1686, + "2": 0.8078 + }, + "score": 1.7841, + "legend": { + "0": "Not urgent", + "1": "Needs attention soon", + "2": "Needs attention immediately" + } + } + }, + "usage": { + "input_tokens": 49, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "short_1", + "response": { + "model": "laya-rl-agent", + "answers": { + "refund": { + "type": "noul", + "confidence": 0.9167, + "answer_confidence": 0.9167, + "action": { + "act_probability": 1.0 + }, + "noul": 0.9167 + } + }, + "usage": { + "input_tokens": 48, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "short_3", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 0.7214, + "answer_confidence": 0.9518, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 0.9518, + "technical": 0.0482 + }, + "choice": "billing" + }, + "refund": { + "type": "noul", + "confidence": 0.9167, + "answer_confidence": 0.9167, + "action": { + "act_probability": 1.0 + }, + "noul": 0.9167 + }, + "urgency": { + "type": "score", + "confidence": 0.4892, + "answer_confidence": 0.8078, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "0": 0.0237, + "1": 0.1686, + "2": 0.8078 + }, + "score": 1.7841, + "legend": { + "0": "Not urgent", + "1": "Needs attention soon", + "2": "Needs attention immediately" + } + } + }, + "usage": { + "input_tokens": 137, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "medium_1", + "response": { + "model": "laya-rl-agent", + "answers": { + "refund": { + "type": "noul", + "confidence": 0.9127, + "answer_confidence": 0.9127, + "action": { + "act_probability": 1.0 + }, + "noul": 0.9127 + } + }, + "usage": { + "input_tokens": 174, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "medium_3", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 0.5724, + "answer_confidence": 0.9126, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 0.9126, + "technical": 0.0874 + }, + "choice": "billing" + }, + "refund": { + "type": "noul", + "confidence": 0.9127, + "answer_confidence": 0.9127, + "action": { + "act_probability": 1.0 + }, + "noul": 0.9127 + }, + "urgency": { + "type": "score", + "confidence": 0.1751, + "answer_confidence": 0.5786, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "0": 0.0955, + "1": 0.3258, + "2": 0.5786 + }, + "score": 1.4831, + "legend": { + "0": "Not urgent", + "1": "Needs attention soon", + "2": "Needs attention immediately" + } + } + }, + "usage": { + "input_tokens": 515, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "long_1", + "response": { + "model": "laya-rl-agent", + "answers": { + "refund": { + "type": "noul", + "confidence": 0.8562, + "answer_confidence": 0.8562, + "action": { + "act_probability": 1.0 + }, + "noul": 0.8562 + } + }, + "usage": { + "input_tokens": 454, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "long_3", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 0.5185, + "answer_confidence": 0.896, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 0.896, + "technical": 0.104 + }, + "choice": "billing" + }, + "refund": { + "type": "noul", + "confidence": 0.8562, + "answer_confidence": 0.8562, + "action": { + "act_probability": 1.0 + }, + "noul": 0.8562 + }, + "urgency": { + "type": "score", + "confidence": 0.0935, + "answer_confidence": 0.5161, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "0": 0.1547, + "1": 0.3292, + "2": 0.5161 + }, + "score": 1.3614, + "legend": { + "0": "Not urgent", + "1": "Needs attention soon", + "2": "Needs attention immediately" + } + } + }, + "usage": { + "input_tokens": 1355, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "negative_3", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 0.5101, + "answer_confidence": 0.8933, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 0.8933, + "technical": 0.1067 + }, + "choice": "billing" + }, + "refund": { + "type": "noul", + "confidence": 0.6715, + "answer_confidence": 0.6715, + "action": { + "act_probability": 1.0 + }, + "noul": 0.6715 + }, + "urgency": { + "type": "score", + "confidence": 0.0525, + "answer_confidence": 0.4726, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "0": 0.4726, + "1": 0.329, + "2": 0.1984 + }, + "score": 0.7259, + "legend": { + "0": "Not urgent", + "1": "Needs attention soon", + "2": "Needs attention immediately" + } + } + }, + "usage": { + "input_tokens": 155, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "conversation_3", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 0.8416, + "answer_confidence": 0.9769, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 0.9769, + "technical": 0.0231 + }, + "choice": "billing" + }, + "refund": { + "type": "noul", + "confidence": 0.928, + "answer_confidence": 0.928, + "action": { + "act_probability": 1.0 + }, + "noul": 0.928 + }, + "urgency": { + "type": "score", + "confidence": 0.4, + "answer_confidence": 0.773, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "0": 0.0531, + "1": 0.1739, + "2": 0.773 + }, + "score": 1.7199, + "legend": { + "0": "Not urgent", + "1": "Needs attention soon", + "2": "Needs attention immediately" + } + } + }, + "usage": { + "input_tokens": 224, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "truncated_3", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 0.5077, + "answer_confidence": 0.8925, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 0.8925, + "technical": 0.1075 + }, + "choice": "billing" + }, + "refund": { + "type": "noul", + "confidence": 0.8421, + "answer_confidence": 0.8421, + "action": { + "act_probability": 1.0 + }, + "noul": 0.8421 + }, + "urgency": { + "type": "score", + "confidence": 0.0981, + "answer_confidence": 0.519, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "0": 0.1499, + "1": 0.3311, + "2": 0.519 + }, + "score": 1.3692, + "legend": { + "0": "Not urgent", + "1": "Needs attention soon", + "2": "Needs attention immediately" + } + } + }, + "usage": { + "input_tokens": 1536, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + }, + { + "name": "single_option", + "response": { + "model": "laya-rl-agent", + "answers": { + "department": { + "type": "choice", + "confidence": 1.0, + "answer_confidence": 1.0, + "action": { + "act_probability": 1.0 + }, + "probabilities": { + "billing": 1.0 + }, + "choice": "billing" + } + }, + "usage": { + "input_tokens": 35, + "output_tokens": 0 + }, + "routing": { + "model": "english", + "repo": "convaiinnovations/laya", + "reason": "explicit model='english'", + "detection": null, + "workflow": null + } + } + } + ], + "raw_head_digest_encoding": "SHA256: raw_logits then raw_actions; each matrix starts with little-endian u32 row count, each row with little-endian u32 width then f32 little-endian bytes.", + "complete_response_digest_encoding": "SHA256 of UTF-8 JSON with sorted keys, separators comma/colon, ensure_ascii=False, allow_nan=False." + } }