From 9952733bbc75eedfa1308cfed71b8e2694db978b Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Wed, 3 Jun 2026 12:28:10 +0100 Subject: [PATCH 01/17] create plan --- NAVIGATION.md | 783 ++++++++++++++++++++++++++++++++++++++++++++++ PLAN.md | 851 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1634 insertions(+) create mode 100644 NAVIGATION.md create mode 100644 PLAN.md diff --git a/NAVIGATION.md b/NAVIGATION.md new file mode 100644 index 000000000..a713e2dce --- /dev/null +++ b/NAVIGATION.md @@ -0,0 +1,783 @@ +# DS4 Codebase Navigation + +This document is a handoff map for working in this repository, with extra detail around issue #304: distributed prefill with local generation. It is intentionally explicit. Prefer updating this file when new control-flow facts, constraints, or validation entry points are discovered. + +## Quick Orientation + +- `ds4.c` + - Core model loading, weights, engine/session lifecycle, local sync/eval, graph execution, CPU fallback, full `DSV4` payloads, per-layer `DSVL` payloads. +- `ds4.h` + - Public engine/session API, distributed options, payload constants, low-level graph-slice APIs used by distributed inference. +- `ds4_distributed.c` + - Distributed transport, coordinator route planning, pipelined prefill, distributed decode, worker runtime, route failure recovery, remote KV shard save/load. +- `ds4_distributed.h` + - Distributed backend API used by `ds4.c`. +- `ds4_gpu.h` + - Backend-neutral tensor/kernels API implemented by Metal and CUDA. +- `ds4_metal.m` + - Metal backend implementation and graph tensor operations. +- `ds4_cuda.cu` + - CUDA backend implementation of the same `ds4_gpu.h` surface. +- `ds4_kvstore.c` / `ds4_kvstore.h` + - Disk KV cache envelope and store/load integration around engine payloads. +- `ds4_cli.c` + - CLI entry point and user-visible command/flag wiring. +- `ds4_server.c` + - Server runtime, session workflow, persistent KV behavior. +- `README.md` + - User-facing architecture and distributed inference documentation. +- `tests/ds4_test.c` + - Main integration/regression test harness. +- `tests/cuda_long_context_smoke.c` + - CUDA long-context kernel smoke tests. +- `Makefile` + - Primary build and test commands. + +## Top-Level Entry Points + +- CLI binary: + - `ds4_cli.c` + - drives normal chat/generation, distributed coordinator mode, and worker mode through shared engine/session APIs. +- Server binary: + - `ds4_server.c` + - uses normal engine/session APIs and `ds4_kvstore` for persistent session/KV behavior. +- Bench/eval/agent binaries: + - `ds4_bench.c`, `ds4_eval.c`, `ds4_agent.c` + - useful for workflows, but not the core issue #304 implementation surface. +- Distributed standalone path: + - `ds4_distributed.c` + - `ds4_dist_run()` runs coordinator/worker role logic after CLI parsing. + +## Public API Boundary + +Relevant file: + +- `ds4.h` + +Important public types: + +- `ds4_engine` + - Opaque loaded model/backend object. +- `ds4_session` + - Opaque mutable inference state: checkpoint timeline, logits, KV state, optional distributed coordinator state. +- `ds4_engine_options` + - Model/backend configuration. + - Contains explicit load-slice fields: `load_layer_start`, `load_layer_end`. + - Contains `ds4_distributed_options distributed`. +- `ds4_distributed_options` + - Distributed role, route layer range, listen/connect addresses, prefill chunk/window, activation bits, debug/replay options. +- `ds4_distributed_layers` + - Parsed inclusive layer range plus `has_output`. +- `ds4_session_payload_file` + - Temp-file staged payload handle. +- `ds4_session_snapshot` + - In-memory payload buffer; currently not supported for distributed sessions. + +Important public functions: + +- `ds4_engine_open()` + - Opens model, initializes backend, applies layer residency decisions. +- `ds4_engine_close()` + - Releases model/backend resources. +- `ds4_session_create()` + - Allocates mutable inference state. + - Attaches a distributed coordinator session when engine role is coordinator. +- `ds4_session_sync()` + - Synchronizes live session to a prompt token prefix. + - Distributed coordinators delegate to `ds4_dist_session_sync()`. +- `ds4_session_eval()` + - Evaluates one generated token. + - Distributed coordinators delegate to `ds4_dist_session_eval()`. +- `ds4_session_eval_layer_slice()` + - Low-level graph-slice execution primitive used by distributed inference. +- `ds4_session_eval_output_head_from_hc()` + - Computes logits from final hidden state when the output head is local. +- `ds4_session_save_payload()` / `ds4_session_load_payload()` + - Full topology-neutral `DSV4` session save/load. +- `ds4_session_save_layer_payload()` / `ds4_session_load_layer_payload()` + - Per-layer-range `DSVL` shard save/load used by distributed mode. +- `ds4_session_stage_payload()` / `ds4_session_write_staged_payload()` + - File-backed staging around `ds4_session_save_payload()`. +- `ds4_session_save_snapshot()` / `ds4_session_load_snapshot()` + - In-memory wrappers around payload save/load, but explicitly reject distributed sessions today. + +## Core Engine And Session Flow + +Relevant files: + +- `ds4.c` +- `ds4.h` + +Key internal structs: + +- `struct ds4_engine` in `ds4.c` + - Owns model map, weights, vocab, backend, distributed options, MTP state, quality/power settings. +- `struct ds4_session` in `ds4.c` + - Owns engine pointer, optional `ds4_dist_session *distributed`, graph/CPU KV state, checkpoint tokens, logits, prefill cap, context size, checkpoint validity. + +Engine open flow: + +- `ds4_engine_open()` + - Loads GGUF/model metadata and tokenizer. + - Initializes `ds4_weights`. + - Applies distributed layer loading before backend mapping: + - if `opt->distributed.role != DS4_DISTRIBUTED_NONE` and `opt->distributed.layers.set`, `load_layer_start/load_layer_end` are derived from `opt->distributed.layers`. + - `load_output` follows `layers.has_output`. + - coordinator output-head loading may be optional via `load_output_optional`. + - For graph backend: + - calls `ds4_gpu_init()`. + - configures model map with `ds4_gpu_set_model_map_range()` for full mapping or `ds4_gpu_set_model_map_spans()` for sliced mapping. + - slice spans are computed by `weights_model_map_spans()`. + - optional cache/preload work goes through `ds4_engine_preload_pro_q4_expert_tables()` and `accelerator_cache_model_tensors()`. + +Session create flow: + +- `ds4_session_create()` + - CPU sessions are direct, but distributed coordinator sessions require graph backend. + - Graph sessions allocate `ds4_gpu_graph` with `metal_graph_alloc_raw_cap()`. + - `weights_first_bound_layer()` determines available layer shape from loaded weights. + - Allocates logits and optional MTP logits. + - Coordinator sessions attach `ds4_dist_session_create()`. + +Local sync/eval flow: + +- `ds4_session_sync()` + - Distributed coordinator: delegates to `ds4_dist_session_sync()`. + - Local session: if current checkpoint is prompt prefix, extends suffix; otherwise rebuilds from scratch. +- `ds4_session_eval_internal()` / `ds4_session_eval()` + - Distributed coordinator: delegates to `ds4_dist_session_eval()`. + - Local graph: runs full local decode path. + - CPU path exists but does not support distributed graph slices. + +Layer-slice execution: + +- `ds4_session_eval_layer_slice()` + - Requires graph backend. + - Requires requested layers are loaded: `weights_layers_bound()`. + - Requires nonzero layer input hidden state unless `layer_start == 0`. + - Can output logits only when the requested slice ends at final transformer layer. + - This is the key primitive that lets a full-resident engine still execute only a distributed route-owned slice. + +## Model Layer Residency + +Relevant files: + +- `ds4.c` +- `ds4.h` +- `ds4_cli.c` +- `README.md` +- `ds4_gpu.h` +- `ds4_metal.m` +- `ds4_cuda.cu` + +Current behavior: + +- Distributed `--layers` currently affects both: + - distributed route ownership, and + - which model tensor spans are mapped/loaded. +- This coupling is implemented around `ds4_engine_open()`: + - distributed layers become `load_layer_start`, `load_layer_end`, and `load_output`. + - `weights_model_map_spans()` creates tensor spans for that range. + - `ds4_gpu_set_model_map_spans()` restricts backend-visible model mapping. +- `README.md` documents this behavior: `--layers` controls which tensors are mapped. + +Issue #304 consequence: + +- Distributed prefill works well with sliced model residency. +- Local generation after prefill needs full model weights and full KV state on the decode machine. +- Reloading the engine or running two full engines is likely impractical. +- The implementation probably needs to decouple route ownership from weight residency. + +Primary code questions: + +- Can the coordinator map full model weights while advertising/executing only its route-owned prefill slice? +- Does `ds4_session_create()` allocate graph/KV state for all layers when the engine has full weights? +- Does `ds4_session_eval_layer_slice()` already allow sliced execution over a full-resident engine? +- How does output head residency interact with `load_output_optional`? +- Can backend model-map spans be expanded after engine open, or must the decision be made at startup? + +Likely starting points: + +- `ds4_engine_open()` +- `weights_model_map_spans()` +- `weights_layers_bound()` +- `ds4_gpu_set_model_map_spans()` +- `ds4_gpu_set_model_map_range()` +- `ds4_engine_preload_pro_q4_expert_tables()` +- `accelerator_cache_model_tensors()` +- `dist_coordinator_build_route_plan()` +- `ds4_session_eval_layer_slice()` + +## Payloads And KV Persistence + +Relevant files: + +- `ds4.h` +- `ds4.c` +- `ds4_kvstore.h` +- `ds4_kvstore.c` +- `ds4_distributed.c` + +Whole-session payload: + +- Magic/version: + - `DS4_SESSION_PAYLOAD_MAGIC` is `DSV4`. + - `DS4_SESSION_PAYLOAD_VERSION` is `2`. + - `DS4_SESSION_PAYLOAD_U32_FIELDS` is `13`. +- Body includes: + - shape/layout header, + - exact checkpoint tokens, + - last logits, + - per-layer `n_comp`, + - per-layer `n_index_comp`, + - raw SWA rows in logical order, + - compressed attention rows, + - ratio-4 indexer rows, + - compressor/indexer frontier state. + +Layer-shard payload: + +- Magic/version: + - `DS4_SESSION_LAYER_PAYLOAD_MAGIC` is `DSVL`. + - `DS4_SESSION_LAYER_PAYLOAD_VERSION` is `1`. + - `DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS` is `14`. +- Used for a contiguous `[layer_start, layer_end]` shard. +- Graph-only. +- Requires the caller to supply exact tokens and token count on load. + +Important functions: + +- `ds4_session_payload_bytes()` + - Exact local payload size. + - Returns `0` for distributed sessions despite distributed save being supported. +- `ds4_session_stage_payload()` + - Writes temp file through `ds4_session_save_payload()` and records actual byte count. + - Useful for distributed payload sizing. +- `ds4_session_save_payload()` + - Local CPU/GPU full payload save. + - Distributed coordinator delegates to `ds4_dist_session_save_payload()`. +- `ds4_session_load_payload()` + - Local CPU/GPU full payload restore. + - Distributed coordinator delegates to `ds4_dist_session_load_payload()`. +- `ds4_session_save_snapshot()` / `ds4_session_load_snapshot()` + - Memory wrappers that reject distributed sessions today. +- `ds4_session_save_layer_payload()` / `ds4_session_load_layer_payload()` + - Per-layer `DSVL` save/load. + - Used by workers and distributed snapshot paths. + +KV store integration: + +- `ds4_kvstore.c` owns the outer `KVC` envelope. +- Engine/session payload bytes inside the KVC file remain normal `DSV4`. +- `ds4_kvstore_store_live_prefix_text()` + - validates live tokens, + - stages payload, + - writes header + text key + payload + optional trailer. +- `ds4_kvstore_try_load_text()` + - finds best text-prefix cache match, + - validates model/quant/context/hash/text prefix, + - calls `ds4_session_load_payload()`. +- Existing KV store can persist distributed coordinator payloads because staging calls `ds4_session_save_payload()`. + +Issue #304 implications: + +- The lowest-risk correctness proof is distributed prefill -> coordinator staged `DSV4` -> full local non-distributed session load -> local decode. +- If memory-only handoff is required, add or adapt a distributed-capable memory payload API; current snapshot helpers reject distributed sessions. +- If explicit shard merge is required, build it around existing `DSVL` semantics and still restore full checkpoint/logits metadata. + +## Distributed Orchestration + +Relevant files: + +- `ds4_distributed.h` + - Public distributed backend API used by `ds4.c`. +- `ds4_distributed.c` + - Transport, route planning, coordinator orchestration, worker runtime, pipelined prefill, decode dispatch, KV shard save/load. +- `README.md` + - Distributed behavior, layer split examples, pipeline notes, route failure recovery, snapshot save/load semantics. + +Key structs: + +- `ds4_dist_session` + - Coordinator-owned session wrapper. + - Holds coordinator state, listener, active route plan, session id, request id. +- `ds4_dist_coordinator_state` + - Coordinator registry and runtime config. + - Tracks local layer range, model id, worker list, prefill chunk/window, activation transport bits. +- `ds4_dist_worker_entry` + - Registered worker metadata from `HELLO`. + - Includes peer/data endpoint, model id, quant bits, layer range, output-head flag. +- `ds4_dist_route_plan` + - Resolved worker chain. + - Contains executable route entries and serialized route blob sent in `WORK`. +- `ds4_dist_route_entry` + - One remote hop: endpoint, layer range, flags, first-hop fd. +- `ds4_dist_worker_state` + - Worker runtime: local slice metadata and per-session KV state map. +- `ds4_dist_worker_session` + - Worker-side session/KV state keyed by coordinator `session_id`. + - Tracks rolling token hash. +- `ds4_dist_prefill_sender`, `ds4_dist_prefill_send_slot`, `ds4_dist_prefill_result_reader` + - Pipelined prefill sender/result-reader state. +- `ds4_dist_kv_layout`, `ds4_dist_kv_shard_file` + - Shard metadata used to validate/merge/split distributed KV payloads. + +Public distributed API: + +- `ds4_dist_session_create()` + - Creates coordinator distributed session, listener, accept loop. +- `ds4_dist_session_route_ready()` + - Checks if a complete route is available. +- `ds4_dist_session_sync()` + - Distributed prefill/sync entry point. +- `ds4_dist_session_eval()` + - Distributed one-token decode entry point. +- `ds4_dist_session_save_payload()` + - Gathers local and remote shards into one normal `DSV4` payload. +- `ds4_dist_session_load_payload()` + - Splits one normal `DSV4` payload over the current route. +- `ds4_dist_run()` + - Standalone coordinator/worker role runner. + +Coordinator route and prefill functions: + +- `dist_coordinator_build_route_plan()` + - Builds contiguous route from coordinator local layer `0` through workers to final layer/output. +- `dist_route_search_workers()` + - Recursive compatible worker route search. +- `dist_coordinator_ensure_route()` + - Ensures current route is usable. +- `dist_coordinator_prefill_chunk_cap()` + - Chooses prefill chunk size. +- `dist_coordinator_prefill_window()` + - Chooses max in-flight prefill chunks. +- `dist_coordinator_prefill_prompt()` + - Prefill dispatcher. +- `dist_coordinator_prefill_prompt_pipelined()` + - Overlaps coordinator local slice for chunk N+1 with remote processing of chunk N. +- `dist_coordinator_eval_span()` + - Common coordinator evaluator for prefill chunks and decode tokens. +- `dist_coordinator_send_remote_work_on_fd()` + - Builds/sends `WORK` frames with tokens, hashes, hidden state, route blob. +- `dist_coordinator_eval_remote_on_fd()` + - Sends work, receives result, validates hash, copies logits or runs local output head. +- `dist_recv_result_alloc()` + - Reads `RESULT`, telemetry, payload, and decodes compressed activation transport. +- `dist_coordinator_rebuild_from_transcript()` + - Replays token history after route failures/reconnects. + +Coordinator prefill flow: + +- `ds4_dist_session_sync()` ensures route. +- If current checkpoint is a prefix, only suffix is evaluated; otherwise full prompt is rebuilt. +- Pipelined prefill is used when multiple chunks and remote workers are available. +- Coordinator evaluates local slice with `ds4_session_eval_layer_slice()`. +- Sender thread sends hidden state chunks to first worker. +- Reader thread receives ACK/logits/hidden state results. +- Intermediate chunks can be ACK-only. +- Final chunk returns logits, or hidden state if coordinator runs local output head with `ds4_session_eval_output_head_from_hc()`. +- Serial fallback loops chunks through `dist_coordinator_eval_span()`. + +Coordinator decode flow: + +- `ds4_dist_session_eval()` handles one generated token. +- It calls `dist_coordinator_eval_span()` with `n_tokens = 1`. +- Decode is strictly autoregressive: next token cannot start until logits return and sampling chooses the token. +- Distributed decode is expected to be slower because every token traverses the route. + +Distributed save/load flow: + +- Save: + - `ds4_dist_session_save_payload()` + - `dist_kv_route_validate()` + - local shard via `ds4_session_save_layer_payload()` + - remote shards via `dist_save_remote_shard_to_file()` + - parse shards with `dist_kv_parse_layer_payload()` + - write one merged topology-neutral `DSV4`. +- Load: + - `ds4_dist_session_load_payload()` + - read normal `DSV4` + - split by route with `dist_prepare_shard_from_session_payload()` + - local restore via `ds4_session_load_layer_payload()` + - remote restore via `dist_load_remote_shard_from_payload()` + - restore logits with `ds4_session_set_logits()`. + +Worker control flow: + +- `dist_run_worker()` + - Starts data listener, initializes `ds4_dist_worker_state`, connects/reconnects to coordinator, sends `HELLO`. +- `dist_worker_data_listener_main()` + - Accepts coordinator or upstream-worker data connections. +- `dist_worker_read_loop()` / `dist_worker_read_loop_prefetch()` + - Handles frames, optionally with worker prefetch queue. +- `dist_worker_handle_work()` + - Reads `WORK` frame payload. +- `dist_worker_process_work_payload()` + - Validates model, layer range, route blob, token ids, token hash, hidden-state size, output-head legality, context bounds. + - Executes assigned layer range using `ds4_session_eval_layer_slice()`. + - Updates worker session token hash after successful eval. + - Forwards to next worker or sends final `RESULT`. +- `dist_forward_work_to_next()` + - Middle-worker forwarding path. +- `dist_worker_handle_snapshot_save()` + - Serializes worker-owned layer payload. +- `dist_worker_handle_snapshot_load()` + - Restores worker-owned layer payload. +- On coordinator disconnect: + - worker clears sessions and reconnects. + +Protocol concepts: + +- Frame header: + - `DS4_DIST_MAGIC`, message type, byte count. +- Message types: + - `DS4_DIST_MSG_HELLO` + - `DS4_DIST_MSG_ERROR` + - `DS4_DIST_MSG_WORK` + - `DS4_DIST_MSG_RESULT` + - `DS4_DIST_MSG_SNAPSHOT_SAVE_REQ` + - `DS4_DIST_MSG_SNAPSHOT_BEGIN` + - `DS4_DIST_MSG_SNAPSHOT_CHUNK` + - `DS4_DIST_MSG_SNAPSHOT_DONE` + - `DS4_DIST_MSG_SNAPSHOT_LOAD_BEGIN` +- Work flags: + - `DS4_DIST_WORK_F_INPUT_HC` + - `DS4_DIST_WORK_F_OUTPUT_LOGITS` + - `DS4_DIST_WORK_F_RESET_SESSION` + - `DS4_DIST_WORK_F_ACK_ONLY` +- Result kinds: + - `DS4_DIST_RESULT_ACK` + - `DS4_DIST_RESULT_HIDDEN_STATE` + - `DS4_DIST_RESULT_LOGITS` +- Route blob: + - Serialized route entries plus return target. + - Allows middle workers to forward without coordinator relay. +- Telemetry: + - Layer range, route index, token span, eval time, downstream wait, forward-send time, input bytes, output bytes. + +Current distributed assumptions: + +- Coordinator route starts at layer `0`. +- Worker slices are contiguous and cover later layers through final layer. +- Final route either owns output head or returns hidden state for coordinator output-head evaluation. +- Each worker owns its slice of KV cache. +- Coordinator/workers must match model id, layer count, context compatibility, quant profile, and route metadata. +- Rolling token hash guards against stale worker KV. +- Prefill can pipeline; decode cannot. +- Persistent distributed KV save/load is topology-neutral `DSV4`, but APIs are file-oriented. +- Protocol has no authentication/encryption and is not release-stable. + +Issue #304 starting points: + +- Start at `ds4_dist_session_sync()`, because distributed prefill completes there. +- Use `ds4_dist_session_save_payload()` as the reference implementation for gathering remote KV into one normal `DSV4`. +- Use `dist_worker_handle_snapshot_save()` as the current worker-side "return my KV shard" primitive. +- Use `dist_kv_parse_layer_payload()` and `dist_kv_layout` fields to validate shard compatibility. +- Validate handoff by comparing: + - distributed prefill + distributed decode, + - distributed prefill + merged `DSV4` load into local session, + - single-node local prefill/decode when feasible. + +## Backend Portability, Graph/Tensor API, And Validation + +Relevant files: + +- `ds4_gpu.h` + - Backend-neutral GPU tensor and kernel API. +- `ds4_metal.m` + - Metal implementation. +- `ds4_cuda.cu` + - CUDA implementation. +- `ds4.c` + - Graph/session owner and payload serializer. +- `tests/ds4_test.c` + - Main integration/regression harness. +- `tests/cuda_long_context_smoke.c` + - CUDA-only smoke tests. +- `Makefile` + - Build/test entry points. + +Key tensor APIs: + +- `ds4_gpu_init()` / `ds4_gpu_cleanup()` + - Backend lifecycle. +- `ds4_gpu_set_model_map_range()` + - Full contiguous model tensor mapping. +- `ds4_gpu_set_model_map_spans()` + - Sliced/non-contiguous model tensor mapping. +- `ds4_gpu_cache_model_range()` + - Optional model tensor cache. +- `ds4_gpu_preload_q4_expert_tables()` + - PRO Q4 expert-table preload. +- `ds4_gpu_tensor_alloc()` / `ds4_gpu_tensor_alloc_managed()` + - Backend tensor allocation. +- `ds4_gpu_tensor_view()` + - Subviews of backend tensors. +- `ds4_gpu_tensor_read()` / `ds4_gpu_tensor_write()` + - Primary backend-neutral serialization boundary. +- `ds4_gpu_tensor_copy()` + - Backend-local tensor copy. +- `ds4_gpu_synchronize()` + - Required before snapshot reads and after restores. +- `ds4_gpu_store_raw_kv_tensor()` / `ds4_gpu_store_raw_kv_batch_tensor()` + - Raw sliding-window KV writes. +- `ds4_gpu_kv_fp8_store_raw_tensor()` + - Decode fused KV finalizer and raw cache write. +- `ds4_gpu_compressor_store_batch_tensor()` + - Rolling compressor frontier update. +- `ds4_gpu_compressor_prefill_tensor()` + - Compressed KV rows/frontier for prefill spans. +- `ds4_gpu_compressor_prefill_ratio4_replay_tensor()` + - Ratio-4 replay path. +- `ds4_gpu_compressor_prefill_state_ratio4_tensor()` + - Ratio-4 frontier reconstruction. +- Attention consumers: + - `ds4_gpu_attention_decode_heads_tensor()` + - `ds4_gpu_attention_decode_raw_batch_heads_tensor()` + - `ds4_gpu_attention_decode_mixed_batch_heads_tensor()` + - `ds4_gpu_attention_indexed_mixed_batch_heads_tensor()` + - `ds4_gpu_attention_prefill_raw_heads_tensor()` + - `ds4_gpu_attention_prefill_static_mixed_heads_tensor()` + - `ds4_gpu_attention_prefill_masked_mixed_heads_tensor()` + +Metal/CUDA responsibilities: + +- Metal: + - `ds4_metal.m` + - `ds4_gpu_tensor` backed by `MTLBuffer` plus offsets/views. + - `ds4_gpu_tensor_read()` / `ds4_gpu_tensor_write()` use host `memcpy` through shared buffer contents. +- CUDA: + - `ds4_cuda.cu` + - `ds4_gpu_tensor` backed by CUDA device pointers. + - `ds4_gpu_tensor_read()` / `ds4_gpu_tensor_write()` use `cudaMemcpy`. +- Shared assumption: + - graph/session code should interact only through `ds4_gpu.h`, not backend-native handles. + +Serialization portability risks: + +- Full payloads and layer payloads stream tensor bytes through `ds4_gpu_tensor_read()` / `ds4_gpu_tensor_write()`. +- Metal can store compressed attention KV as F16 internally when `DS4_GPU_ATTN_COMP_CACHE_F16` is enabled. +- CUDA compressed attention KV is F32 from the serializer's point of view. +- Cross-backend checks should be semantic, not byte-exact. +- Expected drift sources: + - F16 compressed-cache storage, + - FP8 KV round-trip, + - RoPE, + - compressor pooling, + - backend math differences. +- Raw KV rows are serialized in logical token order and restored into destination physical ring using `pos % raw_cap`. +- Ratio-4 compressed layers require frontier/indexer state, not just completed compressed rows: + - `index_comp_cache`, + - `index_state_kv`, + - `index_state_score`, + - attention compressor state. +- Incremental KV return must preserve `ds4_gpu_synchronize()` safety currently provided by snapshot export/restore paths. + +Validation commands: + +- `make test` +- `make cuda-regression` +- `./ds4_test --metal-short-prefill` +- `./ds4_test --metal-kernels` +- `./ds4_test --metal-tensor-equivalence` +- `./ds4_test --local-golden-vectors` +- `./ds4_test --long-context` + +Issue #304 validation additions: + +- Add local full-payload save/load resume tests. +- Add representative `DSVL` layer-shard save/load tests: + - uncompressed layers, + - compressed layers, + - ratio-4 layers, + - final/output-adjacent layers. +- Add distributed gather/load smoke: + - coordinator + worker prefill, + - save merged `DSV4`, + - load into non-distributed full local session, + - compare logits and greedy tokens. +- Add cross-backend manual smoke where hardware allows: + - CUDA worker/shard -> Metal local load/decode, + - Metal shard -> CUDA local load/decode. +- Compare: + - top1 match, + - top5/top20 overlap, + - max absolute logit drift, + - RMS logit drift, + - first 16 greedy tokens. + +## User-Facing Workflow And Documentation + +Relevant files: + +- `README.md` + - Distributed setup, current `--layers` meaning, snapshot persistence format, limitations. +- `ds4_cli.c` + - CLI command/flag integration. +- `ds4_distributed.c` + - Distributed CLI parsing and help for role/layers/listen/coordinator/prefill options. +- `ds4_server.c` + - Server sessions and persistent KV behavior. +- `ds4_web.c` / `ds4_web.h` + - Web/server support utilities. +- `ds4_help.c` / `ds4_help.h` + - Help text utilities. + +Current distributed CLI concepts: + +- `--role coordinator` + - Coordinator owns prompt/session/sampling/control plane and currently owns initial layer range. +- `--role worker` + - Worker connects to coordinator and owns a later layer slice. +- `--layers A:B` + - Inclusive distributed layer slice. + - Currently also affects which tensors are mapped. +- `--layers N:output` + - Worker owns final transformer layers plus output head. +- `--layers N:42` + - Worker owns later transformer layers only; coordinator computes output head/logits. +- `--listen HOST PORT` + - Coordinator control listener. +- `--coordinator HOST PORT` + - Worker connects to coordinator. +- `--dist-prefill-chunk` + - Coordinator prefill chunk size. +- `--dist-prefill-window` + - Coordinator in-flight prefill chunks. +- `--dist-activation-bits` + - Activation transport compression width. + +Documentation areas likely affected by issue #304: + +- `README.md` distributed section: + - explain local generation after distributed prefill, + - document any new residency/loading option, + - document whether `--layers` still maps tensors or only describes route ownership, + - document output-head/logit ownership, + - document KV return cost and limitations. +- CLI help: + - new flags or changed `--layers` semantics. +- Server docs: + - persistent sessions and local-decode handoff behavior if server uses it. + +## Tests, Build, And Validation Map + +Primary commands: + +- `make` + - default build. +- `make test` + - main regression suite. +- `make cuda-regression` + - CUDA long-context smoke. + +Useful test binary modes: + +- `./ds4_test --metal-short-prefill` +- `./ds4_test --metal-kernels` +- `./ds4_test --metal-tensor-equivalence` +- `./ds4_test --local-golden-vectors` +- `./ds4_test --long-context` + +Relevant test files: + +- `tests/ds4_test.c` + - Local/Metal/session regression surface. + - Best place for focused payload save/load and layer-shard tests. +- `tests/cuda_long_context_smoke.c` + - CUDA-specific kernel smoke surface. +- `tests/long_context_story_prompt.txt` + - Long-context prompt fixture. +- `tests/long_context_security_prompt.txt` + - Long-context security prompt fixture. +- `tests/test_q4k_dot.c` + - Quant/kernel test surface. + +Issue #304 expected validation artifacts: + +- `artifacts/issue-304/compatibility-matrix.md` +- `artifacts/issue-304/logit-comparisons.md` +- `artifacts/issue-304/shard-metadata.md` +- `artifacts/issue-304/perf-breakdown.md` +- `artifacts/issue-304/decision-log.md` +- `artifacts/issue-304/runbook.md` +- `artifacts/issue-304/failure-cases.md` +- `artifacts/issue-304/engine-residency.md` +- `artifacts/issue-304/topology-decoupling.md` + +## Issue #304 Starting Guide + +Immediate code reading order: + +- `PLAN.md` + - Current research/implementation plan and phase gates. +- `ds4.h` + - API and payload boundaries. +- `ds4.c` + - Engine residency, session lifecycle, payload formats, layer-slice execution. +- `ds4_distributed.h` + - Distributed backend API. +- `ds4_distributed.c` + - Distributed prefill/decode/save/load orchestration. +- `ds4_gpu.h` + - Tensor serialization/backend abstraction. +- `ds4_metal.m` / `ds4_cuda.cu` + - Inspect only when backend portability or mapping behavior is in question. +- `tests/ds4_test.c` + - Add focused correctness tests here first where possible. + +Minimal correctness proof: + +- Run distributed prefill with current coordinator/worker topology. +- Stage or save distributed coordinator payload: + - `ds4_session_stage_payload()`, or + - `ds4_session_save_payload()`. +- Load merged `DSV4` into a full local non-distributed graph session: + - `ds4_session_load_payload()`. +- Decode locally for 1-3 tokens. +- Compare against current distributed decode and single-node local decode where feasible. + +Known blockers to analyze before user-facing implementation: + +- Distributed coordinator currently often maps only its `--layers` slice. +- Local decode needs full model weights plus full KV state. +- `ds4_session_save_snapshot()` rejects distributed sessions. +- `ds4_session_payload_bytes()` returns `0` for distributed sessions. +- Existing distributed save/load is file-oriented. +- Current route model assumes coordinator-first layer execution. +- Output/logit production is coupled to `N:output` versus `N:42`. + +Primary implementation decision points: + +- Whole `DSV4` handoff versus in-memory payload versus explicit `DSVL` shard merge. +- One full-resident engine with sliced distributed execution versus dynamic residency expansion. +- Whether route ownership and weight residency must be decoupled before the first production implementation. +- Whether topology decoupling is required now or can be deferred after the first safe local-generation handoff. + +Failure cases to preserve: + +- Token hash mismatch. +- Layer range mismatch. +- Context/raw-window/compression-cap mismatch. +- Model id or quant profile mismatch. +- Missing output head when logits are requested. +- Worker reconnect before shard fetch. +- Stale worker session after route rebuild. +- Cross-backend payload load drift outside accepted tolerance. + +## Search Tips + +- Find public API declarations: + - `rg -n "ds4_session_|ds4_engine_|ds4_dist_" ds4.h ds4_distributed.h` +- Find distributed protocol messages: + - `rg -n "DS4_DIST_MSG|DS4_DIST_WORK|DS4_DIST_RESULT" ds4_distributed.c` +- Find distributed prefill path: + - `rg -n "prefill_prompt|prefill_sender|prefill_result" ds4_distributed.c` +- Find distributed save/load path: + - `rg -n "save_payload|load_payload|snapshot|dist_kv" ds4_distributed.c ds4.c` +- Find model residency path: + - `rg -n "load_layer|model_map_spans|set_model_map|weights_layers_bound" ds4.c ds4_gpu.h ds4_metal.m ds4_cuda.cu` +- Find tensor serialization boundary: + - `rg -n "payload_write_tensor_span|payload_read_tensor_span|tensor_read|tensor_write" ds4.c ds4_gpu.h ds4_metal.m ds4_cuda.cu` +- Find CLI distributed parsing/help: + - `rg -n "role|layers|dist-prefill|coordinator|listen" ds4_cli.c ds4_distributed.c` diff --git a/PLAN.md b/PLAN.md new file mode 100644 index 000000000..6812cd923 --- /dev/null +++ b/PLAN.md @@ -0,0 +1,851 @@ +# Local generation with distributed prefill + +## Goal + +Use distributed prefill, but allow token generation to run on a single local node after prefill completes. + +## Research Notes From Issue #304 + +Source: and its comment thread. + +### Feasibility notes + +- Existing distributed prefill already pipelines chunks between workers. The proposed extra work is returning KV cache chunks for the layers prefetched on the remote node back to the local decode node. +- With the current 4096-token distributed chunk size and the README estimate of about 26 GB KV for a 1M-token context, a full context is about 244 chunks and about 106 MB of KV per chunk. +- Activation transfer for one chunk is about 64 MB (`4096 tokens * hidden size 4096 * 4 bytes`), so shipping activation plus KV would raise the per-chunk payload from about 64 MB to about 170 MB. +- On a practical 2.5 GbE link at about 280 MB/s with about 1-2 ms RTT, that larger payload adds about 0.4-0.5 s of transfer latency. +- Because prefill is feed-forward and already pipelined, the working assumption is that efficient KV return pipelining would add that latency roughly once per prefill, not once per chunk. +- Based on this rough model, the feature looks feasible over commodity Ethernet and is unlikely to require Thunderbolt to be useful. +- The issue notes that reducing `--dist-activation-bits` reportedly does not materially improve performance even when the payload is halved, which suggests the current distributed path is not primarily bandwidth-bound at this scale. + +### Direct-link test notes + +- Test date from issue comments: June 1, 2026. +- Tested on `main@ba00a8a`. +- Model: `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf`. +- Topology: + - DGX Spark worker: `./ds4 --role worker --layers 22:output --coordinator 10.77.0.1 1234` + - MacBook M5 Max 128GB coordinator: `./ds4 --role coordinator --layers 0:21 --listen 10.77.0.1 1234 --prompt-file README.md --nothink -n 100` +- Measured result with Spark on `22:output`: prefill about `598.73 t/s`, generation about `14.98 t/s`. +- Measured result with Spark on `22:42`: prefill about `592.16 t/s`, generation about `15.81 t/s`. + +### Conclusions from current testing + +- Heterogeneous distributed inference already works across CUDA and Metal. +- Prefill benefits from splitting work across the two devices even over a direct 5 GbE link with about 1-2 ms ping. +- Decode remains slow when generation stays distributed, which preserves the case for "distributed prefill, local decode". +- If KV return and local resume work as intended, the target outcome is to keep about `600 t/s` prefill while improving generation to `30+ t/s` by decoding entirely on the Mac. + +## Remaining unknowns + +- Whether CUDA-produced KV/session payloads are backend-neutral and can be loaded by Metal without format or numeric mismatches. +- How to merge local-layer KV and remote-layer KV into one complete session state on the decode node before generation starts. +- Whether KV payload transfer should happen strictly after prefill or be pipelined chunk-by-chunk during prefill to avoid stalls. +- What API or file format changes are needed so a worker can export only its owned-layer KV/session slice and a coordinator can import it deterministically. + +## Implementation direction + +- Add a way for remote workers to serialize and stream owned-layer KV/session chunks back to the coordinator. +- Keep the transfer aligned with existing distributed prefill chunk boundaries so activation and KV movement can share the current pipeline structure. +- Validate cross-backend session portability first with a minimal save/load test between CUDA and Metal before committing to the full feature. +- Once portability is confirmed, add a coordinator-side resume path that reconstructs a complete local session and switches decode to the single-node fast path. + +## Relevant Code Module Map + +### 1. Public session and distributed API boundary + +- `ds4.h` + - Defines the public `ds4_session` and `ds4_engine` API surface. + - Distributed configuration lives in `ds4_distributed_options`. + - The low-level distributed execution seam is already exposed via: + - `ds4_session_eval_layer_slice()` + - `ds4_session_eval_output_head_from_hc()` + - `ds4_session_save_layer_payload()` + - `ds4_session_load_layer_payload()` + - The full-session payload ABI is defined here: + - `DS4_SESSION_PAYLOAD_MAGIC` / `DS4_SESSION_PAYLOAD_VERSION` + - `DS4_SESSION_LAYER_PAYLOAD_MAGIC` / `DS4_SESSION_LAYER_PAYLOAD_VERSION` +- Why it matters: + - Any local-generation handoff should preserve these payload boundaries or extend them carefully. + - This is the main header to consult when deciding whether the feature can be expressed as a normal session save/load versus a new distributed-only mechanism. + +### 2. Core session implementation and KV payload format + +- `ds4.c` + - Owns normal session lifecycle, checkpoint timeline, prefill/decode execution, and serialized KV payloads. + - Important functions for this effort: + - `ds4_session_sync()` and `ds4_session_eval()`: normal prefill/decode entry points. + - `ds4_session_save_payload()` / `ds4_session_load_payload()`: full topology-neutral session serialization. + - `ds4_session_save_layer_payload()` / `ds4_session_load_layer_payload()`: per-layer-slice serialization used by distributed mode. + - `ds4_session_payload_bytes()`: current payload sizing helper. + - `ds4_session_save_snapshot()` / `ds4_session_load_snapshot()`: in-memory snapshot helpers. + - `ds4_session_eval_layer_slice()`: executes a contiguous layer range and is the core primitive used by distributed inference. + - Current constraint: + - In-memory snapshots explicitly reject distributed sessions. + - File payload save/load does support distributed sessions by delegating into `ds4_distributed.c`. +- Why it matters: + - The local-decode handoff probably needs one of two things: + - extend distributed sessions so they can produce an in-memory merged payload or snapshot, or + - create a new handoff path that builds a local `ds4_session` from remote layer payloads without going through current snapshot helpers. + +### 3. Distributed transport, routing, and shard orchestration + +- `ds4_distributed.c` + - This is the main implementation file for distributed inference. + - It already states the intended model clearly: workers execute contiguous slices, save gathers worker-owned tensors into a normal DSV4 payload, and load splits a normal payload back across the route. + - Important coordinator-side pieces: + - `ds4_dist_session_create()`: sets up the coordinator session runtime. + - `ds4_dist_session_route_ready()`: route completeness check. + - `ds4_dist_session_sync()`: distributed prefill and prefix extension. + - `ds4_dist_session_eval()`: distributed decode of one token. + - `dist_coordinator_build_route_plan()` / `dist_coordinator_ensure_route()`: build the active worker chain. + - `dist_coordinator_prefill_prompt_pipelined()`: pipelined prefill path. + - `dist_coordinator_eval_span()`: coordinator-issued layer-slice work over one span. + - `dist_coordinator_rebuild_from_transcript()`: replay/recovery path after route changes or transport failure. + - Important save/load pieces: + - `ds4_dist_session_save_payload()`: gathers local shard plus remote shards, then writes one normal session payload. + - `ds4_dist_session_load_payload()`: reads one normal session payload and fans shards back out across the route. + - `dist_kv_route_validate()` and the `dist_kv_*` helpers: verify shard layout compatibility and copy tensor sections. + - Important worker-side pieces: + - `dist_worker_handle_snapshot_save()`: serializes the worker-owned layer shard. + - `dist_worker_handle_snapshot_load()`: restores the worker-owned layer shard. + - `dist_send_snapshot_file_chunks()`: chunked wire transfer of snapshot payload data. + - Important protocol pieces: + - `DS4_DIST_MSG_SNAPSHOT_SAVE_REQ` + - `DS4_DIST_MSG_SNAPSHOT_BEGIN` + - `DS4_DIST_MSG_SNAPSHOT_CHUNK` + - `DS4_DIST_MSG_SNAPSHOT_DONE` + - `DS4_DIST_MSG_SNAPSHOT_LOAD_BEGIN` +- Why it matters: + - This is the most likely place to implement "return KV during prefill" because it already owns: + - per-worker KV shard save/load + - chunked transport + - route planning + - pipelined prefill orchestration + - The existing snapshot messages are request/response oriented around whole shard save/load, not incremental per-prefill-chunk KV return. That is the main architectural gap. + +### 4. GPU backend abstraction used by both Metal and CUDA + +- `ds4_gpu.h` + - Defines the tensor-resident GPU API shared by the backend implementations. + - Relevant categories: + - command lifetime: `ds4_gpu_begin_commands()`, `ds4_gpu_end_commands()`, `ds4_gpu_synchronize()` + - tensor I/O: `ds4_gpu_tensor_write()`, `ds4_gpu_tensor_read()`, `ds4_gpu_tensor_copy()` + - prefill/decode attention and compressor kernels + - Why it matters: + - Cross-backend compatibility depends on whether the serialized layer payloads truly represent backend-neutral tensor state, not backend-private handles or layouts. + - If local handoff fails only on one backend pair, the root cause will likely be below the distributed layer but above raw model logic. + +### 5. Backend-specific graph/runtime implementations + +- `ds4_metal.m` + - Primary Metal runtime and graph executor. + - Allocates the live GPU graph state, raw KV ring, compressed KV buffers, and scratch tensors. + - Implements the actual prefill/decode graph encoding used by `ds4_session_eval_layer_slice()` and normal local inference. +- `ds4_cuda.cu` + - CUDA backend implementation of the same tensor/runtime surface. +- Why they matter: + - The issue’s key unknown is cross-backend cache portability, specifically whether CUDA-produced layer payloads can be loaded and resumed by Metal. + - If the serialized layer payload format is correct but behavior still diverges, the bug will likely be in backend read/write conventions, tensor dtype conversions, or cache-state assumptions here. + +### 6. Disk KV cache and staged payload persistence + +- `ds4_kvstore.c` and `ds4_kvstore.h` + - Manage on-disk KV cache files used by the CLI/server path. + - `ds4_session_stage_payload()` and `ds4_session_write_staged_payload()` are used when persisting session payloads. + - Load uses the same session payload ABI through `ds4_session_load_payload()`. +- Why it matters: + - If the handoff is first implemented as "distributed prefill -> merged payload file -> local session load", these files are directly relevant. + - They are less central if the goal is a zero-copy or in-memory chunked transfer path, but still define the durable payload contract. + +### 7. CLI/server entry points and user-visible workflow + +- `ds4_cli.c` + - Normal CLI path that drives local sessions and can expose coordinator/worker mode options. +- `ds4_server.c` + - Server runtime and persistent session/KV behavior. + - Distributed mode is wired through the normal engine/session path rather than a separate application stack. +- `README.md` + - Documents current distributed assumptions: + - each worker owns its KV slice + - prefill is pipelined + - generation remains slower when distributed + - save/load already uses the same normal KV file format by gathering and splitting shards +- Why they matter: + - After implementation, these are the places that will need the workflow and operator guidance updated. + - The README also documents the current conceptual model and is useful for checking whether the code still matches the intended design. + +### 8. Existing validation surface + +- `tests/ds4_test.c` + - Broad regression coverage for session sync/eval, logits, and long-prefill behavior. +- `tests/cuda_long_context_smoke.c` + - CUDA-side long-context kernel regression coverage. +- Why they matter: + - There does not appear to be dedicated coverage yet for: + - distributed shard portability across backends + - distributed prefill followed by local-only decode resume + - incremental remote KV return during pipelined prefill + - New tests for this feature likely belong in `tests/ds4_test.c`, with at least one focused serialization/resume test before attempting a full distributed integration test. + +## Most Relevant Files To Start In + +- `ds4_distributed.c`: add or prototype KV-return/handoff orchestration here first. +- `ds4.c`: adapt snapshot/payload/session construction boundaries for the handoff. +- `ds4.h`: update public/internal API declarations only after the control flow is clear. +- `ds4_metal.m` and `ds4_cuda.cu`: inspect only if payload portability or restore correctness breaks across backends. + +## Research And Implementation Plan + +This change should be run as an iterative research project, not as a straight feature implementation. The priority is to compound learning: each step should produce an artifact that either validates the next step, rejects an assumption, or narrows the design space. + +### Operating principles + +- Prefer the existing `DSV4` full-session payload as the first correctness boundary. The code already knows how to gather distributed shards into a topology-neutral session stream. +- Treat chunk-by-chunk KV return as an optimization, not the first milestone. Prove that "distributed prefill -> merged payload -> full local session load -> local decode" is correct before changing the prefill pipeline. +- Keep implementation changes small until a validation artifact says the next abstraction is justified. +- Capture every surprising result in this plan or a linked artifact before moving on. This includes failures, mismatched logits, transport timings, and rejected API options. +- Measure correctness before throughput. A fast handoff is not useful until the resumed local session is demonstrably equivalent enough to continue generation. +- Treat model weight residency as a separate correctness and feasibility problem. Local decode needs full-layer weights available, while distributed prefill benefits from loading only a slice; switching engines or running two engines may be too expensive to be viable. + +### Required research artifacts + +- `artifacts/issue-304/compatibility-matrix.md` + - Records `Metal -> Metal`, `CUDA -> CUDA`, `CUDA -> Metal`, and `Metal -> CUDA` payload load/resume outcomes. + - Include commit SHA, model filename/hash, backend, context size, prefill chunk size, layer split, token count, payload byte count, and pass/fail notes. +- `artifacts/issue-304/logit-comparisons.md` + - Captures next-token comparison between single-node prefill, distributed prefill + distributed decode, and distributed prefill + local decode after payload load. + - Include top1 match, top5/top20 overlap, max absolute drift, RMS drift, and first 16 greedy tokens. +- `artifacts/issue-304/shard-metadata.md` + - Captures route coverage and KV shape metadata: `layer_start`, `layer_end`, `token_count`, `token_hash`, `raw_live`, `raw_window`, `raw_cap`, `comp_cap`, per-layer `n_comp`, and per-layer `n_index_comp`. +- `artifacts/issue-304/perf-breakdown.md` + - Captures prefill t/s, remote shard save time, KV bytes returned, merge/write time, local payload load time, and local decode t/s. +- `artifacts/issue-304/decision-log.md` + - Records decisions with date, evidence, alternatives rejected, and follow-up questions. +- `artifacts/issue-304/runbook.md` + - Records exact commands, host roles, environment variables, model paths, ports, and reproduction notes for every validation run. +- `artifacts/issue-304/failure-cases.md` + - Records failures that should remain rejected, including stale worker state, bad token hash, layer range mismatch, context mismatch, and unsupported backend combinations. +- `artifacts/issue-304/engine-residency.md` + - Records how model layer residency currently works, memory implications of each candidate design, and the chosen strategy for letting a local decode-capable engine participate in distributed prefill. +- `artifacts/issue-304/topology-decoupling.md` + - Records follow-on design notes for decoupling coordinator/worker roles, prefill pipeline layer ownership, output-head/logit production, and local decode placement. + +### Artifact conventions + +- Create or update artifacts before moving to the next phase. If a phase is blocked, write down the blocker and the smallest next experiment. +- Include enough run context to reproduce results: commit SHA, branch, host names, OS, backend, model path/hash, layer split, context size, prefill chunk, activation bits, command line, and relevant environment variables. +- Prefer tables for measured data and short dated entries for decisions. +- If a code change adds a new flag, mode, or test, document both the intended command and one known-good invocation in `artifacts/issue-304/runbook.md`. +- If a validation result changes the implementation direction, update `artifacts/issue-304/decision-log.md` and the relevant phase notes in this plan. + +### Phase 0: Baseline and instrumentation + +Goal: + +- Why: establish a factual baseline before changing behavior, so later regressions, speedups, memory costs, and correctness differences are attributable instead of guessed. +- What: produce reproducible commands, route/payload metadata, and timing measurements for current distributed prefill, distributed decode, and distributed payload save behavior. + +Expected artifacts: + +- Update `artifacts/issue-304/runbook.md` with exact baseline commands for the issue topology and one smaller reproducible topology. +- Update `artifacts/issue-304/shard-metadata.md` with the current distributed route, layer ownership, token counts, token hash, and payload metadata. +- Update `artifacts/issue-304/perf-breakdown.md` with current distributed prefill t/s, distributed decode t/s, and distributed payload save timing. +- Update `artifacts/issue-304/decision-log.md` only if the current save/stage behavior disproves the assumed `DSV4` first path. + +Code touchpoints: + +- `ds4_distributed.c` + - `ds4_dist_session_sync()`: distributed prefill entry. + - `dist_coordinator_prefill_prompt_pipelined()`: pipelined prefill behavior and completion point. + - `dist_coordinator_eval_span()`: fallback prefill and current distributed decode path. + - `ds4_dist_session_eval()`: one-token distributed decode. + - `ds4_dist_session_save_payload()`: distributed gather into a normal `DSV4` payload. + - `dist_kv_route_validate()`: shard coverage/layout validation before save/load. + - `dist_save_remote_shard_to_file()`: coordinator-side remote shard request. + - `dist_worker_handle_snapshot_save()`: worker-side shard export. +- `ds4.c` + - `ds4_session_sync()`: public prefill entry and distributed delegation. + - `ds4_session_eval_internal()`: public decode path and distributed delegation. + - `ds4_session_stage_payload()`: tempfile-backed payload staging. + - `ds4_session_save_payload()`: distributed save delegation. +- `ds4.h` + - `ds4_distributed_options`: route/prefill/activation settings to record. + - `ds4_session_payload_file`: staged payload handle to inspect. + +Other entry points: + +- CLI coordinator/worker commands from `README.md`. +- Existing issue topology: + - worker: `./ds4 --role worker --layers 22:output --coordinator 10.77.0.1 1234` + - coordinator: `./ds4 --role coordinator --layers 0:21 --listen 10.77.0.1 1234 --prompt-file README.md --nothink -n 100` +- Local or loopback topology for faster iteration, if supported by available hardware. +- `make test` only as a sanity check; it does not validate the distributed handoff by itself. + +Work items: + +- Capture the current distributed prefill/decode route for the issue topology and at least one smaller local topology. +- Add or script metadata dumps for route layer coverage, payload header fields, per-shard layer ranges, token count/hash, and raw/compressed row counts. +- Confirm whether `ds4_session_stage_payload()` already works on a distributed coordinator immediately after pipelined prefill. +- Record exact timings for distributed prefill, current distributed decode, and current distributed payload save. + +Exit gate: + +- The current system can produce a merged `DSV4` payload from a distributed coordinator after prefill, or the failure mode is captured with a concrete call stack/error. + +### Phase 1: Prove whole-payload resume locally + +Goal: + +- Why: avoid inventing a distributed handoff mechanism before proving the existing durable session format can faithfully suspend and resume local graph state. +- What: demonstrate that a normal non-distributed session can save `DSV4`, load it into a fresh non-distributed session, and continue with measured logit/token equivalence across important cache boundary cases. + +Expected artifacts: + +- Update `artifacts/issue-304/compatibility-matrix.md` with local same-backend payload resume results, starting with `Metal -> Metal` on Mac and `CUDA -> CUDA` where CUDA is available. +- Update `artifacts/issue-304/logit-comparisons.md` with local save/load top-k, drift, and short greedy continuation results. +- Update `artifacts/issue-304/shard-metadata.md` with `DSV4` header fields and `DSVL` representative shard metadata. +- Update `artifacts/issue-304/runbook.md` with test commands and model/context settings. + +Code touchpoints: + +- `tests/ds4_test.c` + - Add or extend focused save/load resume tests. + - Add a representative per-layer `DSVL` save/load smoke if the existing test harness can create a graph session with the required model. +- `ds4.c` + - `ds4_session_save_payload()` / `ds4_session_load_payload()`: full `DSV4` save/load. + - `ds4_session_save_layer_payload()` / `ds4_session_load_layer_payload()`: per-layer `DSVL` save/load. + - `payload_write_tensor_span()` / `payload_read_tensor_span()`: tensor serialization boundary if drift or corruption appears. + - `ds4_session_payload_bytes()`: payload sizing behavior; note distributed currently returns `0`. + - `ds4_session_save_snapshot()` / `ds4_session_load_snapshot()`: memory snapshot helpers, but distributed sessions are currently rejected. +- `ds4_gpu.h` + - `ds4_gpu_tensor_read()` / `ds4_gpu_tensor_write()` / `ds4_gpu_synchronize()`: backend-neutral tensor byte transfer boundary. +- `ds4_metal.m` and `ds4_cuda.cu` + - Only inspect if payload bytes load but logits diverge unexpectedly. + +Other entry points: + +- `make test` +- `./ds4_test --metal-short-prefill` +- `./ds4_test --metal-tensor-equivalence` +- `./ds4_test --local-golden-vectors` +- `make cuda-regression` and `tests/cuda_long_context_smoke.c` for CUDA-side validation where available. + +Work items: + +- Add a focused local save/load resume test: prefill prompt in one local graph session, save `DSV4`, load into a fresh non-distributed graph session, then compare logits and a short greedy continuation. +- Add a per-layer `DSVL` save/load smoke for representative ranges: first layers, middle compressed layers, ratio-4 compressed layers, and final/output-adjacent layers. +- Run boundary prompts around likely cache transition points: `1`, `3`, `4`, `5`, `4095`, `4096`, `4097`, `raw_window - 1`, `raw_window`, and `raw_window + 1`. + +Exit gate: + +- A non-distributed local session can load a normal `DSV4` payload and continue with acceptable logit/token equivalence. +- Any numeric drift is measured and classified as expected backend precision drift or a correctness bug. + +### Phase 2: Prove distributed prefill to local decode via existing payload path + +Goal: + +- Why: get the fastest end-to-end correctness signal for issue #304 by reusing the existing distributed shard gather and normal `DSV4` load path. +- What: prove or disprove that distributed prefill state can be saved as one merged `DSV4`, loaded into a full local non-distributed session, and decoded locally with measured equivalence, while recording whether the two-session/two-engine shape is only a proof harness. + +Expected artifacts: + +- Update `artifacts/issue-304/compatibility-matrix.md` with distributed prefill to local decode results for every tested backend pair. +- Update `artifacts/issue-304/logit-comparisons.md` with three-way comparisons: single-node local, distributed prefill + distributed decode, and distributed prefill + local decode after payload load. +- Update `artifacts/issue-304/perf-breakdown.md` with distributed prefill time, distributed save/stage time, payload bytes, local load time, and local decode t/s. +- Update `artifacts/issue-304/shard-metadata.md` with route coverage and all shard metadata from the handoff run. +- Update `artifacts/issue-304/failure-cases.md` for any mismatch that correctly rejects a handoff. +- Update `artifacts/issue-304/engine-residency.md` with peak memory observed for the proof path and whether running two engines is feasible only as a test harness. + +Code touchpoints: + +- `ds4_distributed.c` + - `ds4_dist_session_save_payload()`: main distributed gather path to validate. + - `dist_kv_parse_layer_payload()`: shard header parsing. + - `dist_kv_write_session_header()`: merged `DSV4` header creation. + - `dist_prepare_shard_from_session_payload()`: useful reference for the reverse split. + - `dist_worker_handle_snapshot_save()`: worker export and token hash validation. + - `dist_send_snapshot_file_chunks()`: existing chunk transfer mechanism. +- `ds4.c` + - `ds4_session_stage_payload()` and `ds4_session_write_staged_payload()`: tempfile-backed export path. + - `ds4_session_load_payload()`: local full-session import. + - `ds4_session_create()`: determine whether a separate full local session is needed. + - `ds4_engine_open()`: current place where distributed `--layers` constrains model map spans. + - `weights_model_map_spans()`: computes tensor spans for a layer slice. + - `weights_layers_bound()`: verifies whether a requested layer range has loaded weights. +- `ds4_cli.c` + - Candidate place for a temporary/manual CLI experiment if the current CLI cannot exercise save/load handoff directly. +- `ds4_kvstore.c` + - Reference for staged payload persistence and load path if the prototype uses a KV cache file rather than a raw temp payload. + +Other entry points: + +- Manual coordinator/worker CLI commands. +- A temporary harness or test binary if the CLI cannot perform the handoff without invasive user-facing changes. +- Existing `ds4_session_stage_payload()` temp files under `/tmp/ds4-session-payload.XXXXXX`. +- Existing KV store path if testing through server/session persistence is easier. +- Memory reporting from OS tools and backend diagnostics to capture peak resident memory/accelerator VM pressure. + +Work items: + +- Run distributed prefill normally. +- Immediately stage/save the distributed coordinator session payload using the existing `ds4_session_save_payload()` or `ds4_session_stage_payload()` path. +- Create a separate full local, non-distributed graph session. +- Load the merged `DSV4` payload into that local session. +- Decode locally for at least 1-3 tokens. +- Compare against continuing distributed decode from the original distributed session and single-node local prefill/decode when feasible. +- Treat this two-session shape as a correctness experiment unless `artifacts/issue-304/engine-residency.md` proves memory is acceptable. + +Key questions: + +- Does the coordinator have enough local model state loaded to create the full local session, or is a second full engine/session required? +- Does `--layers` imply partial model loading that conflicts with local decode? +- Does `ds4_dist_session_save_payload()` safely run immediately after `dist_coordinator_prefill_prompt_pipelined()` completes? +- Are worker session IDs and token hashes stable between prefill completion and shard fetch? + +Exit gate: + +- The existing payload path can hand off distributed prefill state into a local-only decode session, or a specific blocker is captured with enough detail to choose the next implementation step. +- If the path works only by running two engines or reloading an engine, it must not proceed directly to user-facing implementation; Phase 3 must choose a viable layer-residency design first. + +### Phase 3: Engine layer residency and local decode feasibility + +Goal: + +- Why: the feature is not practical if it requires reloading the model or keeping two full model-weight copies in memory after prefill. +- What: choose a viable layer-residency design that lets the decode machine have full local generation capability while still participating efficiently in distributed prefill, and document the memory/performance tradeoff with evidence. + +Expected artifacts: + +- Update `artifacts/issue-304/engine-residency.md` with the current layer-loading model, observed memory behavior, and candidate designs. +- Update `artifacts/issue-304/perf-breakdown.md` with any measured cost of wider model mapping, lazy layer activation, or switching between slice/full execution modes. +- Update `artifacts/issue-304/decision-log.md` with the chosen residency design and rejected alternatives. +- Update `artifacts/issue-304/failure-cases.md` with expected failures for missing full-decode layers, invalid layer range transitions, and memory-budget rejection. +- Update `artifacts/issue-304/runbook.md` with commands and environment settings used to measure memory. + +Code touchpoints: + +- `ds4.h` + - `ds4_engine_options.load_layer_start` / `load_layer_end`: explicit model slice loading knobs. + - `ds4_distributed_options.layers`: distributed route ownership, currently also influences local loaded layer range. + - Potential future option fields if route ownership and local weight residency need to be decoupled. +- `ds4.c` + - `ds4_engine_open()`: currently maps distributed `--layers` into `load_layer_start`, `load_layer_end`, `load_output`, and `load_output_optional`. + - `weights_model_map_spans()`: computes model map spans for a sliced layer range. + - `ds4_gpu_set_model_map_spans()` call site: constrains the backend-visible model mapping. + - `ds4_gpu_set_model_map_range()` call site: maps the full model tensor data range. + - `ds4_engine_preload_pro_q4_expert_tables()`: layer-sliced preload behavior that may need to match the selected residency strategy. + - `accelerator_cache_model_tensors()`: optional model tensor cache behavior and memory pressure point. + - `weights_layers_bound()`: runtime check that requested layer execution has weights. + - `ds4_session_create()`: session graph allocation is based on the engine's loaded/bound weights. + - `ds4_session_eval_layer_slice()`: distributed prefill slice execution must remain able to run only the route-owned layers even if more weights are resident. + - `ds4_session_eval_internal()` and local graph decode path: local decode needs all transformer layers plus output head. +- `ds4_distributed.c` + - `dist_coordinator_build_route_plan()`: route ownership should stay independent from local weight residency if the final design decouples them. + - `dist_coordinator_prefill_prompt_pipelined()` and `dist_coordinator_eval_span()`: must continue issuing only the coordinator-owned distributed slice during prefill. +- `ds4_cli.c` + - `--layers` parsing and help text if the meaning splits into "distributed route slice" and "model residency/load slice". +- `README.md` + - Distributed docs currently state that `--layers` controls which tensors are mapped; this must be updated if route ownership and residency are decoupled. +- Backend files: + - `ds4_gpu.h`, `ds4_metal.m`, and `ds4_cuda.cu` if the selected design requires dynamic mapping, lazy mapping, or remapping backend tensor views. + +Candidate designs to analyze: + +- Decouple route ownership from weight residency: + - Keep `--layers` as the distributed route slice, but allow the coordinator to map full local decode weights at startup. + - During distributed prefill, call `ds4_session_eval_layer_slice()` only for the coordinator route slice even though more weights are resident. + - After KV handoff, continue local decode in the same engine/session shape if full-layer KV has been loaded. +- Full-resident coordinator with sliced distributed execution: + - Load the full model once on the coordinator, but still advertise/execute only the coordinator-owned distributed layer range for prefill. + - This avoids reloads and two engines, but may reduce the memory savings that made distributed prefill useful. +- Lazy or expandable residency: + - Start with route-slice mapping, then expand to full mapping before local decode without closing the engine. + - This is only viable if backend model map spans and cached/preloaded tensors can be expanded safely and fast enough. +- Dual session over one engine: + - Use one full-resident engine with separate distributed-prefill and local-decode sessions. + - This may avoid duplicate weights but still duplicates KV/session graph memory; measure before selecting. +- Two engines or reload: + - Keep only as a correctness harness or fallback diagnostic. Assume this is not the final design unless memory measurements prove otherwise. + +Work items: + +- Trace exactly how distributed `--layers` becomes loaded model spans today. +- Measure memory for route-slice engine, full engine, dual-session-over-one-engine, and two-engine proof harness where feasible. +- Verify whether a full-resident coordinator can still execute only its distributed slice during prefill by using the existing layer-slice APIs. +- Determine whether session graph allocation assumes only a subset of layers is bound, or whether it can safely hold KV for all layers when the engine has full weights. +- Determine whether output head residency is required on the coordinator for local decode and how `load_output_optional` interacts with that. +- Decide whether the implementation should decouple "route layer range" from "loaded layer range" in `ds4_engine_options` / `ds4_distributed_options`. + +Exit gate: + +- A final implementation path exists that does not require loading/unloading the whole engine at handoff time and does not require two full model-weight copies in memory. +- The chosen strategy is captured in `artifacts/issue-304/engine-residency.md` and `artifacts/issue-304/decision-log.md`. +- If no viable strategy is found, stop before Phase 4 and record the smallest code experiment needed to test dynamic/expanded residency. + +### Phase 4: Choose the public/internal API shape + +Goal: + +- Why: API shape should follow validated behavior and residency constraints, not a speculative design that may encode the wrong abstraction. +- What: choose the smallest public/internal API that supports the proven handoff path, records rejected alternatives, and keeps room for later in-memory, incremental, or topology-flexible improvements. + +Expected artifacts: + +- Update `artifacts/issue-304/decision-log.md` with the selected API shape, alternatives rejected, and evidence from Phase 2. +- Update `artifacts/issue-304/runbook.md` with the expected developer/operator workflow for the selected API. +- Update `artifacts/issue-304/engine-residency.md` if the chosen API requires new residency semantics or new CLI options. +- Update this `PLAN.md` if the chosen path changes later phases. + +Code touchpoints: + +- `ds4.h` + - Public/internal declarations if a new session handoff helper is needed. + - `ds4_distributed_options` if the feature becomes an option rather than an explicit helper call. +- `ds4.c` + - Session-level implementation if handoff is expressed as a normal session operation. + - Snapshot/payload helpers if in-memory handoff is chosen. +- `ds4_distributed.h` + - Distributed-specific declarations if the API remains internal to coordinator sessions. +- `ds4_distributed.c` + - Distributed gather/stage implementation and any coordinator state transition. +- `ds4_cli.c` and `ds4_server.c` + - User-visible wiring only after the core API is validated. + +Other entry points: + +- CLI flags and documented workflow. +- Server request/session persistence behavior. +- Existing `ds4_session_save_payload()` / `ds4_session_load_payload()` API if handoff remains a composition of existing primitives. +- Existing `ds4_session_stage_payload()` if the first API is file-backed. + +Work items: + +- Decide whether the first implementation should be whole-payload, in-memory payload, or explicit shard merge. +- Record the decision and evidence before adding user-facing wiring. +- Update the phase sequence if the chosen API invalidates any later assumptions. + +Likely options: + +- Whole-payload handoff: + - expose a helper that saves/stages a distributed session payload and loads it into a provided local session. + - This aligns with the existing `DSV4` topology-neutral contract. +- In-memory payload handoff: + - extend distributed sessions so `ds4_session_save_snapshot()` or a new memory-backed payload helper can gather remote shards. + - This avoids temp files, but requires solving the current distributed snapshot restriction. +- Explicit shard merge: + - expose a multi-`DSVL` merge path that reconstructs a local session from layer shards. + - This is more invasive and should only be chosen if whole `DSV4` handoff proves too slow or too rigid. + +Decision criteria: + +- Correctness equivalence after resume. +- Compatibility with the chosen single-engine residency strategy. +- Operator complexity in CLI/server workflows. +- Ability to support cross-backend handoff. +- Measured handoff overhead relative to prefill speedup. +- Amount of new protocol surface in `ds4_distributed.c`. + +Exit gate: + +- `artifacts/issue-304/decision-log.md` records the chosen API shape and rejected alternatives with evidence. + +### Phase 5: Implement local-generation handoff + +Goal: + +- Why: convert the proven research path into a real workflow that users or higher-level server/CLI code can execute without manual payload surgery. +- What: implement the selected handoff mechanism, wire it through the appropriate session/CLI/server entry points, and verify that distributed prefill can transition to local-only decode with correctness and performance artifacts. + +Expected artifacts: + +- Update `artifacts/issue-304/runbook.md` with the user-visible invocation. +- Update `artifacts/issue-304/logit-comparisons.md` with post-implementation correctness results. +- Update `artifacts/issue-304/perf-breakdown.md` with prefill, handoff, load, and local decode timing from the implemented path. +- Update `artifacts/issue-304/failure-cases.md` with negative tests and observed diagnostics. +- Update `README.md` only once the workflow is stable enough to describe to users. + +Code touchpoints: + +- `ds4.h` + - New helper declaration or option fields, if selected in Phase 4. +- `ds4.c` + - Core handoff flow. + - Local session creation/load boundaries. + - Any changes to distributed snapshot restriction if memory handoff is selected. +- `ds4_distributed.c` + - Coordinator gather/handoff path. + - Route validation and worker shard fetch. + - Failure diagnostics for stale/missing shards. +- `ds4_cli.c` + - CLI mode/flag for "distributed prefill, local decode" if the feature is exposed in CLI. +- `ds4_server.c` + - Server/session workflow if local decode handoff must work for served sessions. +- `ds4_kvstore.c` + - Only if the feature routes through persisted/staged KV payloads. +- `tests/ds4_test.c` + - Regression coverage for local handoff behavior where feasible. + +Other entry points: + +- CLI command line. +- Server session persistence/load path. +- KV store files if the handoff uses persisted payloads. +- Manual distributed coordinator/worker runbook for cross-host validation. + +Work items: + +- Add the minimal session-level handoff mechanism selected in Phase 4. +- Keep the distributed prefill session and local decode session distinct unless evidence shows same-session mutation is safer. +- Ensure the local session receives full token timeline, logits, raw SWA KV rows in logical order, compressed KV rows, compressor frontier state, and indexer state. +- Add CLI/server wiring only after the core session path works. +- Document the operator requirement for full local decode weights if the coordinator's distributed `--layers` setting does not load them. + +Exit gate: + +- A user-visible path can run distributed prefill and then local-only decode with measured speedup and correctness artifacts. + +### Phase 6: Optimize with pipelined KV return + +Goal: + +- Why: once correctness is established, the remaining risk is that post-prefill shard fetch/merge/load latency erases the practical benefit of faster distributed prefill. +- What: measure handoff overhead, then add incremental or pipelined KV return only if it materially reduces latency while preserving token/hash ordering, backend synchronization, and resume equivalence. + +Expected artifacts: + +- Update `artifacts/issue-304/perf-breakdown.md` with before/after handoff latency and transfer byte counts. +- Update `artifacts/issue-304/logit-comparisons.md` with correctness results for incremental KV return. +- Update `artifacts/issue-304/shard-metadata.md` with per-chunk or per-window KV state metadata if chunked return is implemented. +- Update `artifacts/issue-304/decision-log.md` with protocol decisions and why existing snapshot framing was or was not sufficient. +- Update `artifacts/issue-304/failure-cases.md` with in-flight/race/stale chunk rejection cases. + +Code touchpoints: + +- `ds4_distributed.c` + - `dist_coordinator_prefill_prompt_pipelined()`: main place to coordinate pipelined prefill and KV return. + - `dist_prefill_sender_main()`: sends queued hidden states to workers. + - `dist_prefill_result_reader_main()`: receives chunk ACKs/final result; likely place to coordinate returned KV state. + - `dist_worker_process_work_payload()`: worker receives/evaluates prefill work. + - `dist_worker_handle_snapshot_save()`: existing shard export reference. + - `dist_send_snapshot_file_chunks()`: existing chunked transfer reference. + - `dist_write_frame_header()` / `dist_read_frame_header()`: protocol framing if new messages are required. + - `DS4_DIST_MSG_SNAPSHOT_*`: existing protocol message family to reuse or extend. +- `ds4.c` + - `ds4_session_save_layer_payload()`: current whole-shard export; may need range/window-aware variant if incremental return is not expressible through existing payloads. + - `ds4_session_load_layer_payload()`: current layer-shard restore. + - Graph synchronization points before tensor reads. +- `ds4_gpu.h` + - `ds4_gpu_synchronize()` and tensor read APIs if chunk export must avoid racing kernels. +- `ds4_metal.m` and `ds4_cuda.cu` + - Only if incremental reads need backend-specific synchronization or buffer layout fixes. + +Other entry points: + +- Distributed coordinator/worker wire protocol. +- Network timing measurements on 2.5 GbE, 5 GbE, and any Thunderbolt/direct-link setup available. +- Existing `--dist-activation-bits`, `--dist-prefill-chunk`, and `--dist-prefill-window` flags. + +Work items: + +- Extend `ds4_distributed.c` only after Phase 5 shows payload save/load overhead is material. +- Investigate returning worker-owned KV alongside prefill chunk boundaries. +- Define when a chunk's KV is safe to export relative to in-flight kernels and worker forwarding. +- Preserve ratio-4 compressor/indexer frontier state; do not return only completed compressed rows. +- Reuse existing snapshot chunk framing where possible: `DS4_DIST_MSG_SNAPSHOT_SAVE_REQ`, `DS4_DIST_MSG_SNAPSHOT_BEGIN`, `DS4_DIST_MSG_SNAPSHOT_CHUNK`, and `DS4_DIST_MSG_SNAPSHOT_DONE`. +- Add new protocol messages only if existing request/response snapshot framing cannot express incremental return cleanly. + +Exit gate: + +- Incremental KV return reduces measured handoff latency without changing resumed logits/tokens beyond the accepted drift envelope. + +### Phase 7: Failure handling and recovery + +Goal: + +- Why: a local decode handoff turns distributed worker KV into trusted local generation state, so stale, incomplete, or mismatched shards must fail closed. +- What: validate and harden rejection paths for token/hash, model, route, layer range, context, output-head, reconnect, and shard metadata mismatches, with reproducible negative artifacts. + +Expected artifacts: + +- Update `artifacts/issue-304/failure-cases.md` with each negative case, expected rejection, observed error text, and reproduction command. +- Update `artifacts/issue-304/runbook.md` with fault-injection or manual failure procedures. +- Update `artifacts/issue-304/decision-log.md` if a failure mode forces an API or protocol change. + +Code touchpoints: + +- `ds4_distributed.c` + - `dist_kv_route_validate()`: route/layer coverage validation. + - `dist_worker_handle_snapshot_save()`: token hash and worker session validation. + - `dist_worker_handle_snapshot_load()`: load rejection behavior. + - `dist_coordinator_rebuild_from_transcript()`: route rebuild behavior before/after handoff. + - `dist_coordinator_ensure_route()` and route planning helpers. + - Error propagation through coordinator save/load and eval paths. +- `ds4.c` + - `ds4_session_load_payload()`: normal payload rejection behavior. + - `ds4_session_load_layer_payload()`: shard metadata validation. +- `tests/ds4_test.c` + - Add focused negative tests where they can run without full distributed hardware. + +Other entry points: + +- Worker restart/reconnect workflow. +- Mismatched coordinator/worker layer split. +- Mismatched context size or model id. +- Token transcript mutation between prefill completion and shard fetch. + +Work items: + +- Reject shard fetches when token count/hash, model id, layer range, context, raw window, or compression capacity do not match. +- Test worker reconnect or route rebuild before shard fetch. +- Test final-worker/output-head ownership cases. +- Capture failure artifacts: exact load error, shard header dump, route plan, and first mismatching layer/range. + +Exit gate: + +- Known stale/missing/mismatched shard cases fail closed with useful diagnostics. + +### Phase 8: Topology decoupling follow-on + +Goal: + +- Why: practical deployments may want GPU-rich machines to do prefill and memory-rich machines to do generation, so control-plane role, prefill layer ownership, output-head/logit ownership, KV return destination, and decode owner should not remain permanently coupled. +- What: document the current coordinator-first topology constraints, determine whether topology decoupling is required for the first production implementation or can be deferred, and outline a route/protocol direction if it must be solved. + +This is intentionally after Phase 7 because the immediate feature can be proven with the current route model. Do not let this phase block the first correct local-generation handoff unless the chosen Phase 3 residency design makes topology decoupling unavoidable. + +Expected artifacts: + +- Update `artifacts/issue-304/topology-decoupling.md` with the current topology constraints, desired future topologies, and candidate protocol/API changes. +- Update `artifacts/issue-304/decision-log.md` with whether topology decoupling is deferred, partially required, or required for the first production implementation. +- Update `artifacts/issue-304/perf-breakdown.md` with measurements that motivate topology changes, especially GPU-prefill throughput versus memory-bandwidth-local decode throughput. +- Update `artifacts/issue-304/runbook.md` with any topology experiments and command lines. + +Current constraints to capture: + +- The coordinator route must currently start at layer `0`. +- The coordinator runs the early layer slice during distributed prefill. +- Workers cover later contiguous slices. +- `--layers N:output` makes the final worker own the output head and return logits. +- `--layers N:42` keeps the output head/logit production on the coordinator, but the worker still owns the later transformer slice up to layer 42. +- Coordinator/worker roles currently imply control-plane ownership, prompt/session ownership, route construction, and a position in the layer pipeline. + +Desired future topology properties: + +- Control-plane coordinator should be separable from prefill execution role. +- The machine that performs local decode should be separable from the machine that runs the earliest prefill layers. +- Prefill pipeline stages should be assignable to the machines with the best GPU throughput, not necessarily to the decode/sampling machine. +- Decode/sampling should be placeable on the machine with the best memory bandwidth and enough resident full-model/KV state. +- Output-head/logit production should be an explicit route property rather than an implicit consequence of `N:output` versus `N:42`. +- KV ownership and KV return destination should be explicit enough to support "GPU prefill workers -> memory-rich local decoder" without forcing awkward layer ownership. + +Code touchpoints: + +- `ds4_distributed.c` + - `dist_coordinator_build_route_plan()`: currently enforces route coverage and coordinator-first execution. + - `dist_coordinator_ensure_route()`: route readiness and rebuild entry point. + - `dist_coordinator_prefill_prompt_pipelined()`: assumes coordinator local slice starts the pipeline. + - `dist_coordinator_eval_span()`: current span execution over the route. + - `dist_coordinator_send_remote_work_on_fd()`: work dispatch format and first remote hop. + - `dist_prefill_sender_main()` / `dist_prefill_result_reader_main()`: current pipelined prefill sender/result coupling. + - `dist_worker_process_work_payload()`: worker route validation, forwarding, output-logits handling, and final-result behavior. + - `dist_route_validate_blob()`, `dist_route_get_entry()`, and return-target helpers: current route representation and result destination constraints. + - Worker `HELLO` registration structs and parsing: advertised layer range and output-head ownership. +- `ds4_distributed.h` + - Coordinator/worker API boundary if roles become more specific than control-plane coordinator and execution worker. +- `ds4.h` + - `ds4_distributed_options.layers`: currently combines route layer ownership and local model loading concerns. + - Future option shapes if route ownership, output-head ownership, KV return destination, and decode destination are split. +- `ds4_cli.c` + - CLI flag parsing and help text for future topology descriptions. +- `README.md` + - Distributed docs currently describe `A -> B -> C -> back to A`, coordinator early layers, and final-worker output-head behavior. + +Other entry points: + +- Existing CLI forms: + - `--role coordinator --layers 0:M` + - `--role worker --layers N:output` + - `--role worker --layers N:42` +- Future topology experiments: + - control coordinator with no prefill layers + - GPU-prefill node owns early layers while decode node owns full local generation state + - final prefill worker returns hidden state or KV to a separate decode destination + - output head computed on a non-final/non-prefill participant + +Candidate directions to analyze: + +- Split roles into control role and execution role: + - coordinator owns prompt/session/control plane but may not execute layer `0`. + - execution participants advertise layer ranges and capabilities independently. +- Make the route graph explicit: + - represent ordered prefill stages, output/logit stage, return target, and KV return target separately. + - keep contiguous layer coverage initially, but do not hard-code coordinator-first. +- Add an explicit decode owner: + - define which participant will receive merged KV and run local decode. + - this may be the coordinator, but should not be required forever. +- Add explicit output-head ownership: + - replace `N:output`/`N:42` as the only mechanism with a capability/route field. + - preserve the current flags as shorthand for the simple topology. +- Keep current topology for Phases 5 and 6: + - use this option if local-generation handoff works and topology flexibility can be deferred without compromising correctness. + +Work items: + +- Document exactly where the current route requires the coordinator to own layer `0`. +- Document how output logits are requested and validated today. +- Identify which protocol fields would need to change to support a route whose first execution stage is remote. +- Identify whether hidden-state return, logits return, and KV return need separate destinations. +- Determine whether topology changes are necessary for the first production implementation or should be split into a later issue. +- Preserve compatibility with existing `--layers 0:M` / `N:output` workflows as shorthand if new topology controls are added. + +Exit gate: + +- The follow-on topology problem is documented with a concrete design direction or explicitly deferred. +- If deferred, the plan records why the current coordinator-first topology is acceptable for the first local-generation implementation. +- If required, Phases 4 and 5 must be revisited before user-facing implementation. + +### Phase 9: Documentation and durable learnings + +Goal: + +- Why: this change crosses distributed transport, backend serialization, model residency, KV persistence, and user workflow; undocumented learnings will be expensive to rediscover. +- What: update user docs, runbooks, decision logs, performance notes, failure cases, and this plan so the final implementation state and remaining deferred work are clear to the next engineer. + +Expected artifacts: + +- Update `README.md` with the final user-visible workflow, constraints, and expected performance behavior. +- Update `artifacts/issue-304/runbook.md` with final known-good commands. +- Update `artifacts/issue-304/decision-log.md` with final architecture and remaining deferred work. +- Update `artifacts/issue-304/perf-breakdown.md` with final benchmark numbers. +- Update `artifacts/issue-304/topology-decoupling.md` if topology flexibility is deferred or partially implemented. +- Keep this `PLAN.md` accurate if parts of the staged plan were skipped or invalidated. + +Code/documentation touchpoints: + +- `README.md` + - Distributed inference documentation. + - Any new CLI/server workflow. +- `ds4_cli.c` + - Help text and flag descriptions if CLI flags were added. +- `ds4_server.c` + - API/session documentation if server behavior changed. +- Tests added in prior phases. + +Other entry points: + +- GitHub issue #304 follow-up comment or PR description. +- Any local scripts/harnesses created for validation. +- Artifact files under `artifacts/issue-304/`. + +Work items: + +- Update `README.md` once the user-visible workflow exists. +- Keep issue-specific research notes in `artifacts/issue-304/`. +- Keep this plan current as decisions are made. +- If an unknown unknown changes the direction, add the new fact, the decision it invalidated, and the replacement hypothesis before continuing implementation. + +### Initial recommended path + +Start with Phase 1 and Phase 2 using the existing `DSV4` payload path. This gives the fastest correctness signal with the least new code. Only after that should the work move into API design or pipelined KV return. From 116e35881679c99cbe33454f95d2b4c96448761b Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Wed, 3 Jun 2026 17:35:02 +0100 Subject: [PATCH 02/17] phase 0 and phase 1 completed --- Makefile | 37 +- PLAN.md | 10 + artifacts/issue-304/compatibility-matrix.md | 32 + artifacts/issue-304/decision-log.md | 31 + artifacts/issue-304/logit-comparisons.md | 86 +++ artifacts/issue-304/perf-breakdown.md | 74 +++ artifacts/issue-304/research-notes.md | 212 ++++++ artifacts/issue-304/runbook.md | 166 +++++ artifacts/issue-304/shard-metadata.md | 95 +++ ds4.c | 21 + ds4.h | 8 + ds4_distributed.c | 235 +++++-- ds4_distributed.h | 8 + serve.sh | 4 + tests/ds4_test.c | 675 ++++++++++++++++++++ tests/issue304_phase0_dgx.c | 433 +++++++++++++ tests/issue304_phase0_local.c | 436 +++++++++++++ tests/issue304_phase1_matrix.c | 585 +++++++++++++++++ 18 files changed, 3109 insertions(+), 39 deletions(-) create mode 100644 artifacts/issue-304/compatibility-matrix.md create mode 100644 artifacts/issue-304/decision-log.md create mode 100644 artifacts/issue-304/logit-comparisons.md create mode 100644 artifacts/issue-304/perf-breakdown.md create mode 100644 artifacts/issue-304/research-notes.md create mode 100644 artifacts/issue-304/runbook.md create mode 100644 artifacts/issue-304/shard-metadata.md create mode 100755 serve.sh create mode 100644 tests/issue304_phase0_dgx.c create mode 100644 tests/issue304_phase0_local.c create mode 100644 tests/issue304_phase1_matrix.c diff --git a/Makefile b/Makefile index 795f8cbe1..310e98f7e 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ CUDA_LDLIBS ?= -lm -Xcompiler -pthread -L$(CUDA_HOME)/targets/sbsa-linux/lib -L$ METAL_LDLIBS := $(LDLIBS) endif -.PHONY: all help clean test cpu cuda cuda-spark cuda-generic cuda-regression +.PHONY: all help clean test cpu cuda cuda-spark cuda-generic cuda-regression issue304-phase0-local ifeq ($(UNAME_S),Darwin) all: ds4 ds4-server ds4-bench ds4-eval ds4-agent @@ -190,6 +190,39 @@ ds4_cuda.o: ds4_cuda.cu ds4_gpu.h ds4_iq2_tables_cuda.inc tests/cuda_long_context_smoke: tests/cuda_long_context_smoke.o ds4_cuda.o $(NVCC) $(NVCCFLAGS) -o $@ $^ $(CUDA_LDLIBS) +tests/issue304_phase0_local.o: tests/issue304_phase0_local.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase0_local.c + +tests/issue304_phase0_local: tests/issue304_phase0_local.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase0_local.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase0_local.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + +tests/issue304_phase0_dgx.o: tests/issue304_phase0_dgx.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase0_dgx.c + +tests/issue304_phase0_dgx: tests/issue304_phase0_dgx.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase0_dgx.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase0_dgx.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + +tests/issue304_phase1_matrix.o: tests/issue304_phase1_matrix.c ds4.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase1_matrix.c + +tests/issue304_phase1_matrix: tests/issue304_phase1_matrix.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase1_matrix.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase1_matrix.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + +issue304-phase0-local: ds4 tests/issue304_phase0_local + ./tests/issue304_phase0_local + ds4_test: ds4_test.o ds4_help.o ds4_kvstore.o rax.o $(CORE_OBJS) ifeq ($(UNAME_S),Darwin) $(CC) $(CFLAGS) -o $@ ds4_test.o ds4_help.o ds4_kvstore.o rax.o $(CORE_OBJS) $(METAL_LDLIBS) @@ -206,4 +239,4 @@ q4k-dot-test: tests/test_q4k_dot.c ./tests/test_q4k_dot clean: - rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o + rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o diff --git a/PLAN.md b/PLAN.md index 6812cd923..552bd0978 100644 --- a/PLAN.md +++ b/PLAN.md @@ -252,6 +252,7 @@ Expected artifacts: - Update `artifacts/issue-304/shard-metadata.md` with the current distributed route, layer ownership, token counts, token hash, and payload metadata. - Update `artifacts/issue-304/perf-breakdown.md` with current distributed prefill t/s, distributed decode t/s, and distributed payload save timing. - Update `artifacts/issue-304/decision-log.md` only if the current save/stage behavior disproves the assumed `DSV4` first path. +- Update `artifacts/issue-304/research-notes.md` with the current pre-implementation findings, surviving assumptions, and any invalidated hypotheses. Code touchpoints: @@ -306,6 +307,7 @@ Expected artifacts: - Update `artifacts/issue-304/logit-comparisons.md` with local save/load top-k, drift, and short greedy continuation results. - Update `artifacts/issue-304/shard-metadata.md` with `DSV4` header fields and `DSVL` representative shard metadata. - Update `artifacts/issue-304/runbook.md` with test commands and model/context settings. +- Update `artifacts/issue-304/research-notes.md` with Phase 1 findings, what the results rule out, and the remaining unknowns carried into Phase 2. Code touchpoints: @@ -357,6 +359,7 @@ Expected artifacts: - Update `artifacts/issue-304/shard-metadata.md` with route coverage and all shard metadata from the handoff run. - Update `artifacts/issue-304/failure-cases.md` for any mismatch that correctly rejects a handoff. - Update `artifacts/issue-304/engine-residency.md` with peak memory observed for the proof path and whether running two engines is feasible only as a test harness. +- Update `artifacts/issue-304/research-notes.md` with the Phase 2 outcome, the current best explanation for any mismatch, and whether the payload-first path remains viable. Code touchpoints: @@ -423,6 +426,7 @@ Expected artifacts: - Update `artifacts/issue-304/decision-log.md` with the chosen residency design and rejected alternatives. - Update `artifacts/issue-304/failure-cases.md` with expected failures for missing full-decode layers, invalid layer range transitions, and memory-budget rejection. - Update `artifacts/issue-304/runbook.md` with commands and environment settings used to measure memory. +- Update `artifacts/issue-304/research-notes.md` with the residency conclusions and the decision impact on later implementation phases. Code touchpoints: @@ -496,6 +500,7 @@ Expected artifacts: - Update `artifacts/issue-304/decision-log.md` with the selected API shape, alternatives rejected, and evidence from Phase 2. - Update `artifacts/issue-304/runbook.md` with the expected developer/operator workflow for the selected API. - Update `artifacts/issue-304/engine-residency.md` if the chosen API requires new residency semantics or new CLI options. +- Update `artifacts/issue-304/research-notes.md` with the API-shape conclusion and the reasoning that selected it over the other candidates. - Update this `PLAN.md` if the chosen path changes later phases. Code touchpoints: @@ -564,6 +569,7 @@ Expected artifacts: - Update `artifacts/issue-304/logit-comparisons.md` with post-implementation correctness results. - Update `artifacts/issue-304/perf-breakdown.md` with prefill, handoff, load, and local decode timing from the implemented path. - Update `artifacts/issue-304/failure-cases.md` with negative tests and observed diagnostics. +- Update `artifacts/issue-304/research-notes.md` with implementation-phase findings and any deltas from the earlier hypotheses. - Update `README.md` only once the workflow is stable enough to describe to users. Code touchpoints: @@ -620,6 +626,7 @@ Expected artifacts: - Update `artifacts/issue-304/shard-metadata.md` with per-chunk or per-window KV state metadata if chunked return is implemented. - Update `artifacts/issue-304/decision-log.md` with protocol decisions and why existing snapshot framing was or was not sufficient. - Update `artifacts/issue-304/failure-cases.md` with in-flight/race/stale chunk rejection cases. +- Update `artifacts/issue-304/research-notes.md` with the optimization-phase findings and whether chunked return is justified versus whole-payload handoff. Code touchpoints: @@ -672,6 +679,7 @@ Expected artifacts: - Update `artifacts/issue-304/failure-cases.md` with each negative case, expected rejection, observed error text, and reproduction command. - Update `artifacts/issue-304/runbook.md` with fault-injection or manual failure procedures. - Update `artifacts/issue-304/decision-log.md` if a failure mode forces an API or protocol change. +- Update `artifacts/issue-304/research-notes.md` with any failure findings that materially change the implementation direction. Code touchpoints: @@ -721,6 +729,7 @@ Expected artifacts: - Update `artifacts/issue-304/decision-log.md` with whether topology decoupling is deferred, partially required, or required for the first production implementation. - Update `artifacts/issue-304/perf-breakdown.md` with measurements that motivate topology changes, especially GPU-prefill throughput versus memory-bandwidth-local decode throughput. - Update `artifacts/issue-304/runbook.md` with any topology experiments and command lines. +- Update `artifacts/issue-304/research-notes.md` with topology-related findings and whether they affect the first implementation scope. Current constraints to capture: @@ -820,6 +829,7 @@ Expected artifacts: - Update `artifacts/issue-304/decision-log.md` with final architecture and remaining deferred work. - Update `artifacts/issue-304/perf-breakdown.md` with final benchmark numbers. - Update `artifacts/issue-304/topology-decoupling.md` if topology flexibility is deferred or partially implemented. +- Update `artifacts/issue-304/research-notes.md` with a final phase-by-phase summary of what was learned and what remains deferred. - Keep this `PLAN.md` accurate if parts of the staged plan were skipped or invalidated. Code/documentation touchpoints: diff --git a/artifacts/issue-304/compatibility-matrix.md b/artifacts/issue-304/compatibility-matrix.md new file mode 100644 index 000000000..772625043 --- /dev/null +++ b/artifacts/issue-304/compatibility-matrix.md @@ -0,0 +1,32 @@ +# Issue 304 Compatibility Matrix + +## Phase 0: Distributed merged payload stage + +| Date | Commit | Model | Route | Worker ctx | Coordinator ctx | Backend pair | Result | Notes | +| --- | --- | --- | --- | ---: | ---: | --- | --- | --- | +| 2026-06-03 | `9952733bbc75eedfa1308cfed71b8e2694db978b` local / `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` DGX | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output` | 32768 | 16384 | Metal -> CUDA distributed route, merged `DSV4` save on Metal | Fail | Inference route was healthy, but merged save rejected mismatched shard layout: `field=ctx local=16384 remote=32768 remote_layers=22:42`. | +| 2026-06-03 | `9952733bbc75eedfa1308cfed71b8e2694db978b` local / `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` DGX | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output` | 16384 | 16384 | Metal -> CUDA distributed route, merged `DSV4` save on Metal | Pass | Immediate `ds4_session_stage_payload()` succeeded after distributed prefill; staged payload bytes `221,006,660`. | + +## Phase 1: Whole-payload local resume + +| Date | Commit | Model | Save backend | Load backend | Result | Notes | +| --- | --- | --- | --- | --- | --- | --- | +| 2026-06-03 | `9952733bbc75eedfa1308cfed71b8e2694db978b` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | Metal | Metal | Pass | New `./ds4_test --local-payload-resume` path passed at frontiers `1, 3, 4, 5, 127, 128, 129`; logits and greedy continuation matched exactly. | +| 2026-06-03 | save on `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` DGX, load on local `9952733bbc75eedfa1308cfed71b8e2694db978b` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | CUDA | CUDA | Pass | `tests/issue304_phase1_matrix` at `ctx=192`, `frontier=129`, prompt `tests/long_context_story_prompt.txt`: top1 matched, top5 overlap `5/5`, top20 overlap `20/20`, `rms=0`, greedy continuation matched for 8 tokens. | +| 2026-06-03 | save on local `9952733bbc75eedfa1308cfed71b8e2694db978b`, load on `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` DGX | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | Metal | CUDA | Pass | `tests/issue304_phase1_matrix` at `ctx=192`, `frontier=129`: top1 matched, top5 overlap `5/5`, top20 overlap `20/20`, `rms=0`, greedy continuation matched for 8 tokens. | +| 2026-06-03 | save on `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` DGX, load on local `9952733bbc75eedfa1308cfed71b8e2694db978b` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | CUDA | Metal | Fail | `tests/issue304_phase1_matrix` at `ctx=192`, `frontier=129`: restore-point logits matched exactly (`top1`, top5/top20, `rms=0`, `max_abs=0`), but 8-token greedy continuation diverged at step `2` with saved token `5655` vs restored token `305`. | + +## Representative `DSVL` shard smoke + +| Date | Commit | Backend | Layer | Result | Notes | +| --- | --- | --- | --- | --- | --- | +| 2026-06-03 | `9952733bbc75eedfa1308cfed71b8e2694db978b` | Metal | `0` | Pass | Single-layer `DSVL` save/load/save round trip was byte-identical. | +| 2026-06-03 | `9952733bbc75eedfa1308cfed71b8e2694db978b` | Metal | `21` | Pass | Single-layer `DSVL` save/load/save round trip was byte-identical. | +| 2026-06-03 | `9952733bbc75eedfa1308cfed71b8e2694db978b` | Metal | `2` | Pass | Single-layer `DSVL` save/load/save round trip was byte-identical; representative ratio-4/indexer layer. | +| 2026-06-03 | `9952733bbc75eedfa1308cfed71b8e2694db978b` | Metal | `42` | Pass | Single-layer `DSVL` save/load/save round trip was byte-identical; final/output-adjacent layer. | + +## Matrix status + +- Every planned Phase 1 backend pair has now been exercised at least once. +- The only failing cell is `CUDA -> Metal`, and the current failure is narrower than a restore-point logit mismatch: the loaded Metal session starts from identical logits but diverges during subsequent greedy decode. +- Forced-token follow-up on the same failing cell shows that logits already diverge after the first identical post-load eval token, so the failure is not explained by token-selection branching alone. diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md new file mode 100644 index 000000000..8895e9eae --- /dev/null +++ b/artifacts/issue-304/decision-log.md @@ -0,0 +1,31 @@ +# Issue 304 Decision Log + +## 2026-06-03: Correct the earlier Phase 0 save-path conclusion + +Decision: + +- Do not treat the earlier `distributed KV shards use different layouts` result as evidence that mixed Metal/CUDA immediate merged-`DSV4` staging is broken. +- Treat that earlier result as an invalid baseline caused by mismatched worker/coordinator session context. + +Evidence: + +- The earlier failing run used: + - coordinator `ctx=16384` + - worker default `ctx=32768` + - and now reports the exact mismatch: + - `distributed KV shards use different layouts: field=ctx local=16384 remote=32768 remote_layers=22:42` +- The route code accepts this for inference because worker admission only requires `worker_ctx >= coordinator_ctx`. +- Re-running the same Metal/CUDA topology with worker `--ctx 16384` produced: + - successful route formation + - successful prefill on `README.md` + - successful immediate `ds4_session_stage_payload()` + - payload bytes: `221,006,660` + - parsed merged `DSV4` header with `ctx_size=16384` + +Why this changes the notes: + +- The original decision overgeneralized from an invalid reproduction. +- The precise constraint is narrower: + - distributed generation tolerates worker `ctx >= coordinator ctx` + - merged shard save requires exact layout equality, so `ctx` must match across participants +- The Phase 2 `DSV4`-first path remains viable if the runbook pins matching `--ctx` on all distributed participants. diff --git a/artifacts/issue-304/logit-comparisons.md b/artifacts/issue-304/logit-comparisons.md new file mode 100644 index 000000000..de85c410c --- /dev/null +++ b/artifacts/issue-304/logit-comparisons.md @@ -0,0 +1,86 @@ +# Issue 304 Logit Comparisons + +## Phase 1 local `DSV4` resume + +The new `./ds4_test --local-payload-resume` path compares: + +1. local session A after prefill +2. fresh local session B after `DSV4` load +3. short greedy continuation from both sessions + +### Summary + +- Backend pair: Metal -> Metal +- Result: exact match on all tested frontiers +- Non-finite logits: none +- Top-1 mismatches: none +- Greedy continuation mismatches: none + +### Frontier results + +| Frontier | Payload bytes | Top-1 match | Top-5 overlap | Top-20 overlap | RMS drift | Max abs drift | +| --- | ---: | --- | ---: | ---: | ---: | ---: | +| 1 | 12,811,664 | Yes | 5/5 | 20/20 | 0 | 0 | +| 3 | 12,987,800 | Yes | 5/5 | 20/20 | 0 | 0 | +| 4 | 13,129,628 | Yes | 5/5 | 20/20 | 0 | 0 | +| 5 | 13,217,696 | Yes | 5/5 | 20/20 | 0 | 0 | +| 127 | 25,574,792 | Yes | 5/5 | 20/20 | 0 | 0 | +| 128 | 25,757,580 | Yes | 5/5 | 20/20 | 0 | 0 | +| 129 | 25,757,584 | Yes | 5/5 | 20/20 | 0 | 0 | + +### Greedy continuation + +- Continuation length checked: 8 tokens +- Result: identical token sequence from the saved session and the restored session at every tested frontier + +## Phase 1 cross-backend matrix spot check + +The focused cross-backend helper used: + +- prompt: `tests/long_context_story_prompt.txt` +- `ctx=192` +- frontier `129` +- greedy continuation length `8` + +### Results + +| Save backend | Load backend | Top-1 match | Top-5 overlap | Top-20 overlap | RMS drift | Max abs drift | Greedy continuation | +| --- | --- | --- | ---: | ---: | ---: | ---: | --- | +| CUDA | CUDA | Yes | 5/5 | 20/20 | 0 | 0 | Match | +| Metal | CUDA | Yes | 5/5 | 20/20 | 0 | 0 | Match | +| CUDA | Metal | Yes | 5/5 | 20/20 | 0 | 0 | Diverged at step 2 (`5655` vs `305`) | + +### Interpretation + +- The current `CUDA -> Metal` problem is subtler than a bad immediate restore. +- The restored Metal session reproduces the CUDA reference logits exactly at the handoff point, then diverges only after subsequent token evaluation. + +## Forced-token trace follow-up + +To separate token-selection drift from post-load decode evolution, the same `CUDA -> Metal` payload was loaded on both backends and then advanced with the exact same forced token sequence from the CUDA reference continuation. + +### Result + +| Compared traces | First bad step | Forced token before bad step | Top-1 at bad step | Top-5 overlap | Top-20 overlap | RMS drift | Max abs drift | +| --- | ---: | ---: | --- | ---: | ---: | ---: | ---: | +| CUDA ref vs Metal candidate | 1 | `3737` | same (`14`) | 5/5 | 19/20 | 0.304555088 | 1.55702209 | + +### Interpretation + +- The traces are identical at restore step `0`. +- After one identical forced eval token (`3737`), the logits already diverge. +- This rules out “the backends only diverge because they sampled different next tokens” for the current failure. +- The remaining likely causes are: + - backend-specific interpretation of restored state used by the next decode step, or + - backend-specific decode-state evolution from the same restored state. + +## Baseline surrounding checks + +These were rerun after the Phase 1 changes to confirm the new harness did not perturb existing local correctness surfaces. + +| Check | Result | Notes | +| --- | --- | --- | +| `./ds4_test --local-golden-vectors` | Pass | `top1=4371`, `top20_overlap=16/20`, `top64_overlap=56/64`, `top20_max_abs=3.2229` | +| `./ds4_test --metal-short-prefill` | Pass | Existing short prefill regression remained green | +| `./ds4_test --metal-tensor-equivalence` | Pass | Worst observed `rms=0.024882`, `max_abs=0.105766`, `top20_max_abs=0.0233078` on `long_code_audit` | +| `make test` | Pass | Full default test target passed with the new resume test included | diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md new file mode 100644 index 000000000..8071abe67 --- /dev/null +++ b/artifacts/issue-304/perf-breakdown.md @@ -0,0 +1,74 @@ +# Issue 304 Performance Breakdown + +## Phase 0 baseline + +### Historical local loopback topology + +Local loopback baseline tooling is implemented, but the actual run is currently blocked on the same host. + +Attempted command: + +```sh +./tests/issue304_phase0_local +``` + +Observed result: + +| Item | Result | +| --- | --- | +| Tool build | Pass | +| Worker launch | Fail on same-host second-process startup | +| Route formation | Not reached | +| Distributed prefill timing | Not collected | +| Distributed payload stage timing | Not collected | +| Distributed decode timing | Not collected | +| Blocker | single-instance lock in `ds4_engine_open()` refuses a second `ds4` process on the same host | + +Planned fields once a second host is used: + +- prompt file +- prompt token count +- distributed prefill chunk count +- distributed prefill seconds / t/s +- distributed payload stage seconds / bytes +- distributed decode seconds / t/s +- activation transport bits +- coordinator layer range +- worker layer range + +### Issue topology on DGX + Mac + +Authoritative command pair: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./ds4 -m /home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --coordinator 10.77.0.1 1234' +./tests/issue304_phase0_dgx --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --listen-host 10.77.0.1 --listen-port 1234 --prompt-file README.md --ctx 16384 --gen-tokens 1 --prefill-chunk 256 --activation-bits 32 --coordinator-layers 0:21 --worker-layers 22:output +``` + +Observed result: + +| Item | Result | +| --- | --- | +| Link / addresses | Mac coordinator `10.77.0.1:1234`, DGX worker `10.77.0.2:34949` | +| Prompt file | `README.md` | +| Prompt tokens | 14,318 | +| Context | 16,384 | +| Activation transport bits | 32 | +| Distributed prefill | 38.061 s, 376.19 tok/s | +| Distributed payload stage | 0.569 s | +| Staged payload bytes | 221,006,660 | +| Payload stage status | Success | +| Distributed decode | Not re-measured authoritatively after the `ctx` fix; only a 1-token probe was used to keep the save-path validation focused | +| Route stability | Route formed cleanly and merged payload staging completed | + +Notes: + +- `ctx=8192` was insufficient for the README prompt in chat format; `ctx=16384` was required. +- The authoritative conclusion from this pass is about merged save viability and payload metadata, not decode throughput. +- The earlier stage failure was not a generic Metal/CUDA incompatibility. It was a context-layout mismatch: + - coordinator helper used `ctx=16384` + - worker was left at CLI default `ctx=32768` + - route formation still succeeded because the worker only needs `ctx >= coordinator ctx` + - merged `DSV4` stage failed because shard headers require exact layout equality +- Reproduced earlier failure signature: + - `distributed KV shards use different layouts: field=ctx local=16384 remote=32768 remote_layers=22:42` diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md new file mode 100644 index 000000000..bd0ecbed0 --- /dev/null +++ b/artifacts/issue-304/research-notes.md @@ -0,0 +1,212 @@ +# Issue 304 Research Notes + +This file tracks phase-wise findings for the staged investigation in `PLAN.md`. + +## Phase status + +| Phase | Status | Summary | +| --- | --- | --- | +| Phase 0 | Complete | The DGX/Mac baseline ran end-to-end, and the earlier merged-`DSV4` stage failure was narrowed to a worker/coordinator `ctx` mismatch rather than a backend or route-format incompatibility. | +| Phase 1 | Complete | The payload resume matrix is now filled: `Metal -> Metal`, `CUDA -> CUDA`, and `Metal -> CUDA` passed, while `CUDA -> Metal` preserved restore-point logits but diverged during subsequent greedy decode. | +| Phase 2 | Not started | The merged `DSV4` save path is still viable once distributed participants use the same session context. | +| Phase 3 | Not started | Engine residency and same-process local decode feasibility are still open. | +| Later optimization phases | Not started | No work yet on pipelined KV return or user-facing workflow. | + +## Phase 0: Establish distributed baseline + +### What was completed + +- Added a dedicated local baseline tool: `tests/issue304_phase0_local`. +- Added a DGX/Mac coordinator helper: `tests/issue304_phase0_dgx`. +- Added a build/run target in `Makefile` for the tool. +- Defined the local smaller reproducible topology and the DGX issue topology in the runbook. +- Created `perf-breakdown.md` so Phase 0 timing results have a fixed home before DGX runs start. +- Ran the authoritative DGX worker + Mac coordinator issue-topology baseline on `README.md`. + +### Findings + +1. The current CLI/API surface is enough for a narrow two-host baseline harness. + - Route readiness, distributed prefill, distributed decode, and staged payload save are all reachable through existing APIs. + - A small helper binary was enough to exercise the route and record the relevant timings. + +2. Same-host loopback distributed baseline is still blocked by current process policy. + - The local tool launches a worker process and then opens a coordinator engine. + - The worker exits before route formation because `ds4_engine_open()` refuses a second `ds4` process on the same host. + - Observed worker-side failure: `another ds4 process is already running ... refusing to start`. + +3. The DGX/Mac route formed cleanly and produced stable distributed timings on the issue topology. + - Route: `local 0:21 -> 10.77.0.2: Q2 22:output`. + - Output owner: worker. + - Prompt: `README.md`, 14,318 tokens after chat formatting. + - Prefill: about `38 s`, about `376 tok/s`. + - Decode was measured before the `ctx` mismatch was diagnosed, and that earlier distributed decode number should be treated as route-performance context only, not as part of the corrected save-path validation run. + +4. The earlier immediate post-prefill merged `DSV4` stage failure was caused by mismatched `ctx`, not by Metal/CUDA shard incompatibility. + - The failing rerun used coordinator `ctx=16384` and worker default `ctx=32768`. + - The save path now reports the first mismatching header field explicitly: + - `distributed KV shards use different layouts: field=ctx local=16384 remote=32768 remote_layers=22:42` + - This is consistent with current route admission logic, which accepts `worker_ctx >= coordinator_ctx` for execution. + - It is also consistent with the merged save path, which requires exact equality of shard layout metadata. + +5. Immediate post-prefill merged `DSV4` staging works on the mixed Metal/CUDA route when `ctx` matches. + - Re-running the worker with `--ctx 16384` made immediate `ds4_session_stage_payload()` succeed. + - The staged payload size was `221,006,660` bytes. + - Parsed `DSV4` header: + - `ctx_size=16384` + - `prefill_cap=4096` + - `raw_cap=4352` + - `raw_window=128` + - `comp_cap=4098` + - `saved_tokens=14318` + - `n_layer=43` + - `head_dim=512` + - `indexer_head_dim=128` + - `vocab=129280` + - `raw_live=128` + +### Implication + +The original broad conclusion was too strong. The mixed Metal/CUDA route does support immediate merged `DSV4` staging, but only when the worker session context matches the coordinator session context. The real actionable constraint is: Phase 2 reproductions must set the same `--ctx` on every distributed participant. + +### Remaining caution + +- The DGX worker repo was not updated during this pass. The local helper/build and the DGX worker binary were behaviorally compatible for the tested Phase 0 path, but the exact authoritative evidence here is: + - route formation across those revisions worked, + - immediate merged save worked once `ctx` matched, + - not that every later Phase 2/3 path is already proven safe across revision skew. + +## Phase 1: Prove whole-payload resume locally + +### What was tested + +- Added `./ds4_test --local-payload-resume`. +- Verified local `DSV4` save -> load -> resume on Metal. +- Verified 8-token greedy continuation equivalence after restore. +- Ran boundary frontiers at `1`, `3`, `4`, `5`, `127`, `128`, `129`. +- Added representative single-layer `DSVL` save/load/save byte-roundtrip smoke cases. + +### Findings + +1. Local same-backend `DSV4` resume is a valid correctness boundary. + - Metal -> Metal resume matched exactly on every tested frontier. + - Logit drift was `0` for all tested cases. + - Greedy continuation matched exactly for all tested cases. + +2. Raw-window boundary behavior is not the immediate blocker. + - Resume remained exact at `raw_window - 1`, `raw_window`, and `raw_window + 1`. + - That reduces the chance that later handoff failures will come from raw-ring reconstruction or cache-frontier serialization on the local path. + +3. `DSVL` shard helpers appear healthy enough to use as building blocks. + - Representative layer cases passed save -> load -> save byte identity checks. + - Sampled layers: + - `0` first layer + - `21` middle compressed layer + - `2` representative ratio-4/indexer layer + - `42` final/output-adjacent layer + +4. The current payload metadata is internally coherent on this backend. + - Probe run observed: + - `ctx_size=16384` + - `prefill_cap=4096` + - `raw_cap=4352` + - `raw_window=128` + - `comp_cap=4098` + - `n_layer=43` + - `head_dim=512` + - `indexer_head_dim=128` + - `vocab=129280` + +5. Cross-backend whole-payload portability is asymmetric in the current evidence. + - `CUDA -> CUDA`: pass. + - `Metal -> CUDA`: pass. + - `CUDA -> Metal`: fail. + - The `CUDA -> Metal` failure is not a restore-point logit mismatch: + - top1 matched + - top5 overlap was `5/5` + - top20 overlap was `20/20` + - `rms=0` + - `max_abs=0` + - The first observed divergence happened during continued greedy decode at step `2`: + - saved token `5655` + - restored token `305` + +6. Forced-token comparison narrows the `CUDA -> Metal` failure to post-load decode evolution, not token-selection branching. + - The same CUDA-produced payload was loaded on CUDA and Metal. + - Both sessions were then advanced with the exact same forced token sequence from the CUDA reference run. + - The first logits divergence appeared immediately after the first forced eval step: + - bad step: `1` + - forced token before bad step: `3737` + - top1 still matched (`14`) + - top20 overlap dropped to `19/20` + - `rms=0.304555088` + - `max_abs=1.55702209` + - This rules out the narrow explanation that the earlier divergence was only caused by each backend choosing a different token after load. + +### What Phase 1 rules out + +- “Local `DSV4` resume is fundamentally broken” is no longer a leading hypothesis. +- “Boundary frontiers immediately corrupt local resume state” is not supported by the current Metal results. +- “Representative `DSVL` helpers are obviously unusable” is not supported by the current local shard smoke. + +### What Phase 1 does not prove + +- Why `CUDA -> Metal` diverges immediately after the first identical forced post-load eval +- Distributed shard gather correctness +- Coordinator-side local decode after distributed prefill +- Whether a practical implementation can avoid a second full engine or model reload + +### Implication for the goal + +The goal is distributed prefill with local generation after handoff. Phase 1 reduces the problem to the real remaining unknowns: + +- distributed gather/load correctness, +- the root cause of `CUDA -> Metal` post-restore decode divergence, +- and engine residency / local decode feasibility. + +That means Phase 2 can use merged `DSV4` handoff as the first end-to-end correctness experiment with much lower ambiguity. + +## Phase 2: Prove distributed prefill to local decode via existing payload path + +### Current status + +Not run yet. + +### Current working hypothesis + +The intended correctness check was: + +1. run distributed prefill, +2. stage the coordinator session as merged `DSV4`, +3. create a fresh full local non-distributed session, +4. load the merged payload, +5. compare local decode against continued distributed decode. + +### Updated prerequisite + +- Keep worker and coordinator session context sizes identical before treating any merged-save failure as a true shard-format bug. + +### Open question carried forward + +- `CUDA -> Metal` restores the immediate logits exactly, but diverges after the first identical forced post-load eval token. +- This remains unresolved and should be treated as a later investigation into post-load decode evolution, not as a blocker for considering Phases 0 and 1 complete. + +## Phase 3: Engine layer residency and local decode feasibility + +### Current status + +Not run yet. + +### What Phase 1 suggests + +If Phase 2 succeeds only by creating a second full local engine, the remaining work is probably not payload correctness. It is likely a residency and execution-shape problem. + +### Main decision to resolve later + +Whether the coordinator can keep full local decode weights resident while still participating in distributed prefill using only its owned layer slice. + +## Pointers + +- [runbook.md](/Users/lobanov/Projects/ds4/artifacts/issue-304/runbook.md) +- [compatibility-matrix.md](/Users/lobanov/Projects/ds4/artifacts/issue-304/compatibility-matrix.md) +- [logit-comparisons.md](/Users/lobanov/Projects/ds4/artifacts/issue-304/logit-comparisons.md) +- [shard-metadata.md](/Users/lobanov/Projects/ds4/artifacts/issue-304/shard-metadata.md) diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md new file mode 100644 index 000000000..5800bf26b --- /dev/null +++ b/artifacts/issue-304/runbook.md @@ -0,0 +1,166 @@ +# Issue 304 Runbook + +## Phase 0 baseline + +### Historical localhost preparation + +Build the local loopback baseline tool: + +```sh +make tests/issue304_phase0_local +``` + +Run it with the default smaller reproducible topology: + +```sh +./tests/issue304_phase0_local +``` + +Default local topology baked into the tool: + +- coordinator host: `127.0.0.1` +- coordinator layers: `0:21` +- worker layers: `22:output` +- prompt file: `README.md` +- context: `8192` +- distributed prefill chunk: `256` +- distributed activation bits: `32` +- generation sample window for baseline decode timing: `16` greedy tokens + +What this tool attempts to verify: + +- a distributed coordinator can form a route, +- a multi-chunk distributed prefill can complete, +- `ds4_session_stage_payload()` can run immediately after prefill, +- a staged merged `DSV4` payload exposes normal header metadata, +- current distributed decode can be timed on the same session. + +Current local result: + +- build: pass +- run: blocked locally +- blocker: the worker is a second `ds4` process on the same host, and `ds4_engine_open()` currently refuses a second process with the single-instance lock before route formation begins +- observed error: `ds4: another ds4 process is already running ... refusing to start` + +Implication: + +- same-host loopback is not currently a viable Phase 0 baseline path without changing instance-lock policy +- local Phase 0 work can still prepare the tool, artifact schema, and exact command set +- authoritative distributed measurements still need a second host, which in practice means moving on to the DGX/Mac topology + +### DGX + Mac authoritative baseline + +Build the coordinator helper locally: + +```sh +make tests/issue304_phase0_dgx +``` + +Start the DGX worker over SSH: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./ds4 -m /home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --coordinator 10.77.0.1 1234' +``` + +Run the local coordinator helper on the Mac: + +```sh +./tests/issue304_phase0_dgx --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --listen-host 10.77.0.1 --listen-port 1234 --prompt-file README.md --ctx 16384 --gen-tokens 100 --prefill-chunk 256 --activation-bits 32 --coordinator-layers 0:21 --worker-layers 22:output +``` + +Observed requirements and results: + +- `ctx=8192` was too small for the `README.md` issue prompt after chat formatting; the authoritative run used `ctx=16384`. +- The worker `--ctx` must match the coordinator session `--ctx` for merged `DSV4` staging to succeed. Route formation alone only requires worker `ctx >= coordinator ctx`. +- Route formed successfully with worker `10.77.0.2:34949`. +- Distributed prefill completed on the README prompt. +- Immediate `ds4_session_stage_payload()` succeeded when both sides used `ctx=16384`. +- Earlier failure with `distributed KV shards use different layouts` was reproduced and narrowed to `field=ctx local=16384 remote=32768`, caused by leaving the worker at its CLI default `--ctx 32768`. + +## Environment + +- Date: 2026-06-03 15:54:57Z +- Local repo commit: `9952733bbc75eedfa1308cfed71b8e2694db978b` +- DGX worker repo commit: `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` +- Coordinator host: Apple M5 Max / Metal +- Worker host: NVIDIA GB10 / CUDA +- Model: `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` +- Local model path: `/Users/lobanov/Projects/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` +- DGX model path: `/home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` +- Model hash: not recorded in this pass; `shasum -a 256` was skipped because the file is too large for a short verification loop + +## Commands + +### Phase 1 build + +```sh +make ds4_test +``` + +### Phase 1 focused path + +```sh +./ds4_test --local-payload-resume +``` + +### Phase 1 cross-backend matrix helper + +Local Metal save/reference: + +```sh +./tests/issue304_phase1_matrix --mode save --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --payload /private/tmp/issue304-phase1/metal-frontier129.dsv4 --logits /private/tmp/issue304-phase1/metal-frontier129.logits.f32 --tokens /private/tmp/issue304-phase1/metal-frontier129.tokens.txt +``` + +Local Metal load-check from CUDA reference: + +```sh +./tests/issue304_phase1_matrix --mode load-check --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --payload /private/tmp/issue304-phase1/cuda-frontier129.dsv4 --logits /private/tmp/issue304-phase1/cuda-frontier129.logits.f32 --tokens /private/tmp/issue304-phase1/cuda-frontier129.tokens.txt +``` + +DGX CUDA save/reference: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./tests/issue304_phase1_matrix --mode save --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --payload /tmp/issue304-phase1/cuda-frontier129.dsv4 --logits /tmp/issue304-phase1/cuda-frontier129.logits.f32 --tokens /tmp/issue304-phase1/cuda-frontier129.tokens.txt' +``` + +DGX CUDA load-check from Metal reference: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./tests/issue304_phase1_matrix --mode load-check --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --payload ./tests/metal-frontier129.dsv4 --logits ./tests/metal-frontier129.logits.f32 --tokens ./tests/metal-frontier129.tokens.txt' +``` + +### Phase 1 surrounding regression checks + +```sh +./ds4_test --metal-short-prefill --metal-tensor-equivalence --local-golden-vectors +make test +``` + +## Runtime knobs used by `--local-payload-resume` + +- `DS4_METAL_PREFILL_CHUNK=4096` +- `DS4_METAL_DISABLE_METAL4=1` +- `DS4_METAL_MOE_TILE_MAX` unset + +## Observed payload probe + +The Phase 1 probe creates a session with `ctx=16384` and saves a 1-token local checkpoint to inspect the durable `DSV4` layout. + +- `ctx_size=16384` +- `prefill_cap=4096` +- `raw_cap=4352` +- `raw_window=128` +- `comp_cap=4098` +- `saved_tokens=1` +- `n_layer=43` +- `head_dim=512` +- `indexer_head_dim=128` +- `vocab=129280` +- `raw_live=1` + +## Notes + +- The actual resume cases run with `ctx=192` (`raw_window + 64`) after the probe discovers `raw_window=128`. +- The original focused Phase 1 harness is same-backend only: Metal save -> Metal load. +- The cross-backend matrix helper used the same `ctx=192`, `frontier=129` boundary case and `tests/long_context_story_prompt.txt` prompt on both hosts. +- `CUDA -> Metal` is currently the only failing Phase 1 whole-payload matrix cell. diff --git a/artifacts/issue-304/shard-metadata.md b/artifacts/issue-304/shard-metadata.md new file mode 100644 index 000000000..bdcaf4ad3 --- /dev/null +++ b/artifacts/issue-304/shard-metadata.md @@ -0,0 +1,95 @@ +# Issue 304 Shard Metadata + +## Phase 0 planned distributed topology + +### Historical local smaller reproducible topology + +Planned local topology for `tests/issue304_phase0_local`: + +| Role | Layers | Host | +| --- | --- | --- | +| coordinator | `0:21` | `127.0.0.1` | +| worker | `22:output` | `127.0.0.1` | + +Current local result: + +- route metadata not collected +- blocker: second `ds4` process on same host is refused by the current single-instance lock before route formation + +### DGX issue topology + +| Role | Layers | Host | +| --- | --- | --- | +| coordinator | `0:21` | `10.77.0.1` | +| worker | `22:output` | `10.77.0.2` | + +Live route metadata from the authoritative Phase 0 run: + +| Field | Value | +| --- | --- | +| route hops | 1 | +| route summary | `local 0:21 -> 10.77.0.2:34949 Q2 22:output` | +| output owner | worker | +| prompt tokens | 14,318 | +| immediate staged payload bytes | 221,006,660 | +| immediate stage result | success | +| token count at staged checkpoint | 14,318 | +| token hash at staged checkpoint | `0xa34307b6aaa8f956` | +| note | This row captures the merged-save checkpoint immediately after prefill, before any meaningful decode-window measurement rerun | + +Reproduced failure mode from the earlier invalid run: + +| Field | Value | +| --- | --- | +| failing route summary | `local 0:21 -> 10.77.0.2:42211 Q2 22:output` | +| coordinator `ctx` | 16,384 | +| worker `ctx` | 32,768 | +| stage result | fail | +| stage error | `distributed KV shards use different layouts: field=ctx local=16384 remote=32768 remote_layers=22:42` | + +## Full `DSV4` payload probe + +Observed from the new local Phase 1 probe (`ctx=16384`, saved token count `1`): + +| Field | Value | +| --- | ---: | +| magic | `DSV4` | +| version | `2` | +| `ctx_size` | 16384 | +| `prefill_cap` | 4096 | +| `raw_cap` | 4352 | +| `raw_window` | 128 | +| `comp_cap` | 4098 | +| `saved_tokens` | 1 | +| `n_layer` | 43 | +| `head_dim` | 512 | +| `indexer_head_dim` | 128 | +| `vocab` | 129280 | +| `raw_live` | 1 | + +## Resume-case `DSV4` metadata + +The actual Phase 1 resume checks run with `ctx=192`. For frontiers `127`, `128`, and `129`, the saved local payloads reported: + +| Frontier | Payload bytes | `raw_window` | `raw_cap` | `prefill_cap` | +| --- | ---: | ---: | ---: | ---: | +| 127 | 25,574,792 | 128 | 192 | 192 | +| 128 | 25,757,580 | 128 | 192 | 192 | +| 129 | 25,757,584 | 128 | 192 | 192 | + +## Representative `DSVL` shard metadata + +Single-layer shard round trips captured from `./ds4_test --local-payload-resume`: + +| Layer | Payload bytes | `raw_window` | `comp_cap` | `n_comp` | `n_index_comp` | Notes | +| --- | ---: | ---: | ---: | ---: | ---: | --- | +| 0 | 262,208 | 128 | 50 | 0 | 0 | first layer | +| 21 | 788,544 | 128 | 50 | 1 | 0 | middle compressed layer | +| 2 | 426,048 | 128 | 50 | 32 | 32 | representative ratio-4/indexer layer | +| 42 | 426,048 | 128 | 50 | 32 | 32 | final/output-adjacent layer | + +## Notes + +- These shard values come from the stable same-backend Metal run only. +- The single-layer smoke validates `save -> load -> save` byte identity for the sampled layers. +- The DGX/Mac mixed Metal/CUDA Phase 0 run did produce a merged `DSV4` header once the worker `ctx` matched the coordinator `ctx`. diff --git a/ds4.c b/ds4.c index c60c72547..7221203e0 100644 --- a/ds4.c +++ b/ds4.c @@ -20319,6 +20319,27 @@ int ds4_session_distributed_route_ready(ds4_session *s, char *err, size_t errlen return ds4_dist_session_route_ready(s->distributed, err, errlen); } +int ds4_session_distributed_route_summary( + ds4_session *s, + char *summary, + size_t summary_len, + uint32_t *route_hops, + bool *output_on_coordinator, + char *err, + size_t errlen) { + if (!s || !s->distributed) { + if (errlen) snprintf(err, errlen, "session is not a distributed coordinator"); + return -1; + } + return ds4_dist_session_describe_route(s->distributed, + summary, + summary_len, + route_hops, + output_on_coordinator, + err, + errlen); +} + int ds4_session_power(ds4_session *s) { if (!s || !s->engine) return 100; return s->engine->power_percent; diff --git a/ds4.h b/ds4.h index fb47bed13..56a487d10 100644 --- a/ds4.h +++ b/ds4.h @@ -213,6 +213,14 @@ void ds4_session_report_progress(ds4_session *s, const char *event, int current, /* Distributed coordinator sessions return 1 when the full layer route is * available, 0 when it is still incomplete, and -1 for a local API error. */ int ds4_session_distributed_route_ready(ds4_session *s, char *err, size_t errlen); +int ds4_session_distributed_route_summary( + ds4_session *s, + char *summary, + size_t summary_len, + uint32_t *route_hops, + bool *output_on_coordinator, + char *err, + size_t errlen); typedef enum { DS4_SESSION_REWRITE_ERROR = -1, diff --git a/ds4_distributed.c b/ds4_distributed.c index 62b11845c..f6cceac19 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -1972,8 +1972,26 @@ static bool dist_route_search_workers( return false; } -static void dist_coordinator_report_plan(ds4_dist_coordinator_state *state) { - if (!dist_coordinator_debug_enabled(state)) return; +static bool dist_coordinator_format_route_summary( + ds4_dist_coordinator_state *state, + char *summary, + size_t summary_len, + uint32_t *route_hops, + bool *output_on_coordinator, + uint32_t *missing_layer, + bool *ready, + char *err, + size_t errlen) { + if (summary_len != 0 && summary) summary[0] = '\0'; + if (route_hops) *route_hops = 0; + if (output_on_coordinator) *output_on_coordinator = false; + if (missing_layer) *missing_layer = 0; + if (ready) *ready = false; + if (!state) { + if (errlen) snprintf(err, errlen, "missing distributed coordinator state"); + return false; + } + pthread_mutex_lock(&state->mu); uint32_t n = 0; for (ds4_dist_worker_entry *it = state->workers; it; it = it->next) n++; @@ -1983,17 +2001,18 @@ static void dist_coordinator_report_plan(ds4_dist_coordinator_state *state) { free(workers); free(path); pthread_mutex_unlock(&state->mu); - fprintf(stderr, "ds4: distributed coordinator: out of memory building route plan\n"); - return; + if (errlen) snprintf(err, errlen, "out of memory building route summary"); + return false; } uint32_t i = 0; for (ds4_dist_worker_entry *it = state->workers; it; it = it->next) workers[i++] = it; qsort(workers, n, sizeof(workers[0]), dist_worker_route_cmp); const uint32_t last = state->n_layers - 1u; + const bool local_has_output = state->local_has_output; bool complete = state->local_start == 0; bool has_output = state->local_end == last && - (state->local_has_output || state->local_can_output_head); + (local_has_output || state->local_can_output_head); uint32_t next = state->local_end + 1u; if (state->local_end >= last) next = state->n_layers; uint32_t path_len = 0; @@ -2014,52 +2033,88 @@ static void dist_coordinator_report_plan(ds4_dist_coordinator_state *state) { } } - char plan[1024]; - size_t used = 0; + if (route_hops) *route_hops = path_len; + char local_end[32]; - if (state->local_has_output) snprintf(local_end, sizeof(local_end), "output"); + if (local_has_output) snprintf(local_end, sizeof(local_end), "output"); else snprintf(local_end, sizeof(local_end), "%u", state->local_end); - used += (size_t)snprintf(plan + used, used < sizeof(plan) ? sizeof(plan) - used : 0, - "local %u:%s", - state->local_start, - local_end); + size_t used = 0; + if (summary && summary_len != 0) { + used += (size_t)snprintf(summary + used, summary_len - used, + "local %u:%s", + state->local_start, + local_end); + } for (i = 0; i < path_len; i++) { ds4_dist_worker_entry *w = path[i]; - if (used < sizeof(plan)) { - char end[32]; - if (w->has_output) snprintf(end, sizeof(end), "output"); - else snprintf(end, sizeof(end), "%u", w->layer_end); - used += (size_t)snprintf(plan + used, sizeof(plan) - used, - " -> %s:%u Q%u %u:%s", - w->peer_host, - w->listen_port, - w->quant_bits, - w->layer_start, - end); - } - } + if (!summary || used >= summary_len) continue; + char end[32]; + if (w->has_output) snprintf(end, sizeof(end), "output"); + else snprintf(end, sizeof(end), "%u", w->layer_end); + used += (size_t)snprintf(summary + used, summary_len - used, + " -> %s:%u Q%u %u:%s", + w->peer_host, + w->listen_port, + w->quant_bits, + w->layer_start, + end); + } + bool local_output = false; if (complete && path_len != 0 && - !path[path_len - 1u]->has_output && state->local_can_output_head && - used < sizeof(plan)) { - used += (size_t)snprintf(plan + used, sizeof(plan) - used, - " -> local output"); + !path[path_len - 1u]->has_output && state->local_can_output_head) { + local_output = true; + if (summary && used < summary_len) { + used += (size_t)snprintf(summary + used, summary_len - used, + " -> local output"); + } } if (complete && path_len == 0 && - state->local_end == last && !state->local_has_output && - state->local_can_output_head && used < sizeof(plan)) { - used += (size_t)snprintf(plan + used, sizeof(plan) - used, - " -> local output"); + state->local_end == last && !local_has_output && + state->local_can_output_head) { + local_output = true; + if (summary && used < summary_len) { + used += (size_t)snprintf(summary + used, summary_len - used, + " -> local output"); + } } complete = complete && has_output && next == state->n_layers; pthread_mutex_unlock(&state->mu); + if (summary && summary_len != 0) { + summary[summary_len - 1u] = '\0'; + } + if (missing_layer) *missing_layer = missing; + if (ready) *ready = complete; + if (output_on_coordinator) *output_on_coordinator = local_output || local_has_output; + free(path); + free(workers); + if (errlen) err[0] = '\0'; + return true; +} + +static void dist_coordinator_report_plan(ds4_dist_coordinator_state *state) { + if (!dist_coordinator_debug_enabled(state)) return; + char plan[1024]; + uint32_t missing = 0; + bool complete = false; + char err[128]; + if (!dist_coordinator_format_route_summary(state, + plan, + sizeof(plan), + NULL, + NULL, + &missing, + &complete, + err, + sizeof(err))) { + fprintf(stderr, "ds4: distributed coordinator: %s\n", err[0] ? err : "failed to build route summary"); + return; + } if (complete) { fprintf(stderr, "ds4: distributed coordinator: complete route ready: %s\n", plan); } else { fprintf(stderr, "ds4: distributed coordinator: route incomplete; next needed layer %u\n", missing); } - free(path); - free(workers); } static void dist_route_plan_free(ds4_dist_route_plan *plan) { @@ -4652,6 +4707,75 @@ static bool dist_kv_layout_matches( a->raw_live == b->raw_live; } +static int dist_kv_layout_mismatch_message( + const ds4_dist_kv_layout *want, + const ds4_dist_kv_layout *got, + uint32_t layer_start, + uint32_t layer_end, + char *err, + size_t errlen) { + if (!errlen) return 1; + if (!want || !got) { + snprintf(err, errlen, "distributed KV shards use different layouts"); + return 1; + } + + const char *field = "unknown"; + uint32_t lhs = 0; + uint32_t rhs = 0; + if (want->ctx != got->ctx) { + field = "ctx"; + lhs = want->ctx; + rhs = got->ctx; + } else if (want->prefill_cap != got->prefill_cap) { + field = "prefill_cap"; + lhs = want->prefill_cap; + rhs = got->prefill_cap; + } else if (want->raw_cap != got->raw_cap) { + field = "raw_cap"; + lhs = want->raw_cap; + rhs = got->raw_cap; + } else if (want->raw_window != got->raw_window) { + field = "raw_window"; + lhs = want->raw_window; + rhs = got->raw_window; + } else if (want->comp_cap != got->comp_cap) { + field = "comp_cap"; + lhs = want->comp_cap; + rhs = got->comp_cap; + } else if (want->token_count != got->token_count) { + field = "token_count"; + lhs = want->token_count; + rhs = got->token_count; + } else if (want->n_layers != got->n_layers) { + field = "n_layers"; + lhs = want->n_layers; + rhs = got->n_layers; + } else if (want->head_dim != got->head_dim) { + field = "head_dim"; + lhs = want->head_dim; + rhs = got->head_dim; + } else if (want->indexer_head_dim != got->indexer_head_dim) { + field = "indexer_head_dim"; + lhs = want->indexer_head_dim; + rhs = got->indexer_head_dim; + } else if (want->raw_live != got->raw_live) { + field = "raw_live"; + lhs = want->raw_live; + rhs = got->raw_live; + } + + snprintf(err, + errlen, + "distributed KV shards use different layouts: field=%s local=%u remote=%u remote_layers=%u:%u", + field, + lhs, + rhs, + layer_start, + layer_end); + return 1; +} + static bool dist_kv_raw_live_valid(const ds4_dist_kv_layout *layout) { if (!layout || layout->raw_window == 0 || layout->raw_cap == 0) return false; const uint32_t expected = @@ -4715,8 +4839,12 @@ static int dist_kv_parse_layer_payload( } if (layout_set && *layout_set) { if (!dist_kv_layout_matches(layout, &got)) { - if (errlen) snprintf(err, errlen, "distributed KV shards use different layouts"); - return 1; + return dist_kv_layout_mismatch_message(layout, + &got, + layer_start, + layer_end, + err, + errlen); } } else if (layout && layout_set) { const uint32_t vocab = layout->vocab; @@ -5481,6 +5609,39 @@ int ds4_dist_session_route_ready(ds4_dist_session *d, char *err, size_t errlen) return 1; } +int ds4_dist_session_describe_route( + ds4_dist_session *d, + char *summary, + size_t summary_len, + uint32_t *route_hops, + bool *output_on_coordinator, + char *err, + size_t errlen) { + if (!d) { + if (errlen) snprintf(err, errlen, "missing distributed session"); + return -1; + } + uint32_t missing = 0; + bool ready = false; + if (!dist_coordinator_format_route_summary(&d->state, + summary, + summary_len, + route_hops, + output_on_coordinator, + &missing, + &ready, + err, + errlen)) { + return -1; + } + if (!ready) { + if (errlen) snprintf(err, errlen, "distributed route incomplete: missing layer %u", missing); + return 0; + } + if (errlen) err[0] = '\0'; + return 1; +} + int ds4_dist_session_sync( ds4_dist_session *d, ds4_session *owner, diff --git a/ds4_distributed.h b/ds4_distributed.h index 35c5343bd..a207a9232 100644 --- a/ds4_distributed.h +++ b/ds4_distributed.h @@ -79,6 +79,14 @@ void ds4_dist_session_free(ds4_dist_session *d); * still missing, and -1 for configuration or internal errors. */ int ds4_dist_session_route_ready(ds4_dist_session *d, char *err, size_t errlen); +int ds4_dist_session_describe_route( + ds4_dist_session *d, + char *summary, + size_t summary_len, + uint32_t *route_hops, + bool *output_on_coordinator, + char *err, + size_t errlen); /* Synchronize the distributed KV state to the requested prompt timeline. */ int ds4_dist_session_sync( diff --git a/serve.sh b/serve.sh new file mode 100755 index 000000000..98f507b2c --- /dev/null +++ b/serve.sh @@ -0,0 +1,4 @@ +#!/bin/bash +echo Serving with context 250k +echo Preventing this Mac from going to sleep +caffeinate -i ./ds4-server --host 0.0.0.0 --warm-weights --ctx 250000 --kv-disk-dir /tmp/ds4-kv --kv-disk-space-mb 81920 diff --git a/tests/ds4_test.c b/tests/ds4_test.c index 07292824f..13da4f0b5 100644 --- a/tests/ds4_test.c +++ b/tests/ds4_test.c @@ -893,6 +893,598 @@ static void test_official_logprob_vectors(void) { fclose(fp); } +typedef struct { + uint32_t ctx_size; + uint32_t prefill_cap; + uint32_t raw_cap; + uint32_t raw_window; + uint32_t comp_cap; + uint32_t saved_tokens; + uint32_t n_layer; + uint32_t head_dim; + uint32_t indexer_head_dim; + uint32_t vocab; + uint32_t raw_live; + uint32_t *n_comp; + uint32_t *n_index_comp; +} test_dsv4_metadata; + +typedef struct { + uint32_t ctx_size; + uint32_t prefill_cap; + uint32_t raw_cap; + uint32_t raw_window; + uint32_t comp_cap; + uint32_t saved_tokens; + uint32_t n_layer; + uint32_t head_dim; + uint32_t indexer_head_dim; + uint32_t layer_start; + uint32_t layer_end; + uint32_t raw_live; +} test_dsvl_metadata; + +typedef struct { + int top1_saved; + int top1_restored; + int overlap; + int top5_overlap; + int nonfinite; + float rms; + float max_abs; +} test_resume_logits_result; + +static void test_logits_topk(const float *logits, int n, int *out, int k); +static bool test_topk_contains(const int *top, int k, int id); + +static void test_dsv4_metadata_free(test_dsv4_metadata *meta) { + if (!meta) return; + free(meta->n_comp); + free(meta->n_index_comp); + memset(meta, 0, sizeof(*meta)); +} + +static bool test_read_u32_le(FILE *fp, uint32_t *out) { + uint8_t buf[4]; + if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) return false; + *out = (uint32_t)buf[0] | + ((uint32_t)buf[1] << 8) | + ((uint32_t)buf[2] << 16) | + ((uint32_t)buf[3] << 24); + return true; +} + +static bool test_parse_dsv4_metadata_file(const char *path, + const ds4_session_payload_file *payload, + test_dsv4_metadata *meta) { + memset(meta, 0, sizeof(*meta)); + FILE *fp = fopen(path, "rb"); + TEST_ASSERT(fp != NULL); + if (!fp) return false; + + uint32_t header[DS4_SESSION_PAYLOAD_U32_FIELDS]; + bool ok = true; + for (uint32_t i = 0; ok && i < DS4_SESSION_PAYLOAD_U32_FIELDS; i++) { + ok = test_read_u32_le(fp, &header[i]); + } + TEST_ASSERT(ok); + TEST_ASSERT(header[0] == DS4_SESSION_PAYLOAD_MAGIC); + TEST_ASSERT(header[1] == DS4_SESSION_PAYLOAD_VERSION); + if (!ok || + header[0] != DS4_SESSION_PAYLOAD_MAGIC || + header[1] != DS4_SESSION_PAYLOAD_VERSION) { + fclose(fp); + return false; + } + + meta->ctx_size = header[2]; + meta->prefill_cap = header[3]; + meta->raw_cap = header[4]; + meta->raw_window = header[5]; + meta->comp_cap = header[6]; + meta->saved_tokens = header[7]; + meta->n_layer = header[8]; + meta->head_dim = header[9]; + meta->indexer_head_dim = header[10]; + meta->vocab = header[11]; + meta->raw_live = header[12]; + + const uint64_t fixed_prefix = + (uint64_t)DS4_SESSION_PAYLOAD_U32_FIELDS * sizeof(uint32_t) + + (uint64_t)meta->saved_tokens * sizeof(uint32_t) + + (uint64_t)meta->vocab * sizeof(float); + TEST_ASSERT(payload->bytes >= fixed_prefix); + if (payload->bytes < fixed_prefix) { + fclose(fp); + return false; + } + const off_t skip_bytes = + (off_t)(fixed_prefix - + (uint64_t)DS4_SESSION_PAYLOAD_U32_FIELDS * sizeof(uint32_t)); + const int seek_rc = fseeko(fp, skip_bytes, SEEK_CUR); + TEST_ASSERT(seek_rc == 0); + if (seek_rc != 0) { + fclose(fp); + return false; + } + + meta->n_comp = calloc(meta->n_layer, sizeof(meta->n_comp[0])); + meta->n_index_comp = calloc(meta->n_layer, sizeof(meta->n_index_comp[0])); + TEST_ASSERT(meta->n_comp != NULL); + TEST_ASSERT(meta->n_index_comp != NULL); + if (!meta->n_comp || !meta->n_index_comp) { + test_dsv4_metadata_free(meta); + fclose(fp); + return false; + } + for (uint32_t il = 0; il < meta->n_layer; il++) { + ok = test_read_u32_le(fp, &meta->n_comp[il]); + TEST_ASSERT(ok); + if (!ok) break; + } + for (uint32_t il = 0; ok && il < meta->n_layer; il++) { + ok = test_read_u32_le(fp, &meta->n_index_comp[il]); + TEST_ASSERT(ok); + } + + fclose(fp); + if (!ok) { + test_dsv4_metadata_free(meta); + return false; + } + return true; +} + +static bool test_parse_dsvl_metadata_bytes(const uint8_t *buf, + size_t len, + test_dsvl_metadata *meta) { + memset(meta, 0, sizeof(*meta)); + TEST_ASSERT(len >= (size_t)DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS * sizeof(uint32_t)); + if (len < (size_t)DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS * sizeof(uint32_t)) return false; + + uint32_t header[DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS]; + for (uint32_t i = 0; i < DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS; i++) { + const size_t off = (size_t)i * sizeof(uint32_t); + header[i] = (uint32_t)buf[off] | + ((uint32_t)buf[off + 1] << 8) | + ((uint32_t)buf[off + 2] << 16) | + ((uint32_t)buf[off + 3] << 24); + } + TEST_ASSERT(header[0] == DS4_SESSION_LAYER_PAYLOAD_MAGIC); + TEST_ASSERT(header[1] == DS4_SESSION_LAYER_PAYLOAD_VERSION); + if (header[0] != DS4_SESSION_LAYER_PAYLOAD_MAGIC || + header[1] != DS4_SESSION_LAYER_PAYLOAD_VERSION) { + return false; + } + + meta->ctx_size = header[2]; + meta->prefill_cap = header[3]; + meta->raw_cap = header[4]; + meta->raw_window = header[5]; + meta->comp_cap = header[6]; + meta->saved_tokens = header[7]; + meta->n_layer = header[8]; + meta->head_dim = header[9]; + meta->indexer_head_dim = header[10]; + meta->layer_start = header[11]; + meta->layer_end = header[12]; + meta->raw_live = header[13]; + return true; +} + +static bool test_read_binary_file(const char *path, uint8_t **out, size_t *len_out) { + *out = NULL; + *len_out = 0; + + FILE *fp = fopen(path, "rb"); + TEST_ASSERT(fp != NULL); + if (!fp) return false; + TEST_ASSERT(fseeko(fp, 0, SEEK_END) == 0); + if (fseeko(fp, 0, SEEK_END) != 0) { + fclose(fp); + return false; + } + off_t len = ftello(fp); + TEST_ASSERT(len >= 0); + if (len < 0) { + fclose(fp); + return false; + } + rewind(fp); + + uint8_t *buf = malloc((size_t)len); + TEST_ASSERT(buf != NULL || len == 0); + if (!buf && len != 0) { + fclose(fp); + return false; + } + if (len != 0) { + const size_t nread = fread(buf, 1, (size_t)len, fp); + TEST_ASSERT(nread == (size_t)len); + if (nread != (size_t)len || ferror(fp)) { + free(buf); + fclose(fp); + return false; + } + } + fclose(fp); + *out = buf; + *len_out = (size_t)len; + return true; +} + +static bool test_capture_greedy_tokens(ds4_session *session, + int steps, + int *out, + int *out_len) { + char err[160]; + int n = 0; + while (n < steps) { + const int token = ds4_session_argmax(session); + out[n++] = token; + if (n < steps && ds4_session_eval(session, token, err, sizeof(err)) != 0) { + TEST_ASSERT(false); + *out_len = n; + return false; + } + } + *out_len = n; + return true; +} + +static bool test_tokenize_phase1_prompt(ds4_engine *engine, ds4_tokens *prompt) { + memset(prompt, 0, sizeof(*prompt)); + char *prompt_text = test_read_file("tests/long_context_story_prompt.txt"); + TEST_ASSERT(prompt_text != NULL); + if (!prompt_text) return false; + ds4_tokenize_text(engine, prompt_text, prompt); + free(prompt_text); + TEST_ASSERT(prompt->len > 5000); + return prompt->len > 5000; +} + +static test_resume_logits_result test_compare_resume_logits(const char *label, + const float *saved, + const float *restored, + int vocab) { + int saved_top[20]; + int restored_top[20]; + test_logits_topk(saved, vocab, saved_top, 20); + test_logits_topk(restored, vocab, restored_top, 20); + + int overlap = 0; + int top5_overlap = 0; + for (int i = 0; i < 20; i++) { + if (saved_top[i] >= 0 && test_topk_contains(restored_top, 20, saved_top[i])) overlap++; + if (i < 5 && saved_top[i] >= 0 && test_topk_contains(restored_top, 5, saved_top[i])) { + top5_overlap++; + } + } + + int nonfinite = 0; + double sumsq = 0.0; + float max_abs = 0.0f; + for (int i = 0; i < vocab; i++) { + if (!isfinite(saved[i]) || !isfinite(restored[i])) { + nonfinite++; + continue; + } + const float delta = restored[i] - saved[i]; + const float abs_delta = fabsf(delta); + if (abs_delta > max_abs) max_abs = abs_delta; + sumsq += (double)delta * (double)delta; + } + const float rms = (float)sqrt(sumsq / (double)vocab); + + fprintf(stderr, + "ds4-test: payload resume %s top1 saved=%d restored=%d top5_overlap=%d/5 overlap=%d/20 rms=%g max_abs=%g nonfinite=%d\n", + label, + saved_top[0], + restored_top[0], + top5_overlap, + overlap, + rms, + max_abs, + nonfinite); + + test_resume_logits_result result = { + .top1_saved = saved_top[0], + .top1_restored = restored_top[0], + .overlap = overlap, + .top5_overlap = top5_overlap, + .nonfinite = nonfinite, + .rms = rms, + .max_abs = max_abs, + }; + return result; +} + +static void test_local_payload_resume_frontier(ds4_engine *engine, + const ds4_tokens *prompt, + int ctx, + int frontier, + const test_dsv4_metadata *probe_meta) { + ds4_tokens prefix = { + .v = prompt->v, + .len = frontier, + .cap = frontier, + }; + ds4_session *saved = NULL; + ds4_session *restored = NULL; + ds4_session_payload_file payload = {0}; + test_dsv4_metadata meta = {0}; + float *saved_logits = NULL; + float *restored_logits = NULL; + + TEST_ASSERT(ds4_session_create(&saved, engine, ctx) == 0); + TEST_ASSERT(saved != NULL); + if (!saved) return; + + char err[160]; + TEST_ASSERT(ds4_session_sync(saved, &prefix, err, sizeof(err)) == 0); + if (ds4_session_sync(saved, &prefix, err, sizeof(err)) != 0) goto cleanup; + + const int vocab = ds4_engine_vocab_size(engine); + saved_logits = malloc((size_t)vocab * sizeof(saved_logits[0])); + restored_logits = malloc((size_t)vocab * sizeof(restored_logits[0])); + TEST_ASSERT(saved_logits != NULL); + TEST_ASSERT(restored_logits != NULL); + if (!saved_logits || !restored_logits) goto cleanup; + + TEST_ASSERT(ds4_session_copy_logits(saved, saved_logits, vocab) == vocab); + const int stage_rc = ds4_session_stage_payload(saved, &payload, err, sizeof(err)); + TEST_ASSERT(stage_rc == 0); + TEST_ASSERT(ds4_session_payload_bytes(saved) == payload.bytes); + if (stage_rc != 0) goto cleanup; + + TEST_ASSERT(test_parse_dsv4_metadata_file(payload.path, &payload, &meta)); + TEST_ASSERT(meta.saved_tokens == (uint32_t)frontier); + TEST_ASSERT(meta.raw_window == probe_meta->raw_window); + TEST_ASSERT(meta.n_layer == probe_meta->n_layer); + TEST_ASSERT(meta.vocab == probe_meta->vocab); + + TEST_ASSERT(ds4_session_create(&restored, engine, ctx) == 0); + TEST_ASSERT(restored != NULL); + if (!restored) goto cleanup; + + FILE *fp = fopen(payload.path, "rb"); + TEST_ASSERT(fp != NULL); + if (!fp) goto cleanup; + const int load_rc = ds4_session_load_payload(restored, fp, payload.bytes, err, sizeof(err)); + fclose(fp); + TEST_ASSERT(load_rc == 0); + if (load_rc != 0) goto cleanup; + + TEST_ASSERT(ds4_session_copy_logits(restored, restored_logits, vocab) == vocab); + char label[64]; + snprintf(label, sizeof(label), "frontier=%d", frontier); + test_resume_logits_result result = + test_compare_resume_logits(label, saved_logits, restored_logits, vocab); + TEST_ASSERT(result.nonfinite == 0); + TEST_ASSERT(result.top1_saved == result.top1_restored); + TEST_ASSERT(result.top5_overlap >= 5); + TEST_ASSERT(result.overlap >= 16); + + int saved_gen[8]; + int restored_gen[8]; + int saved_gen_len = 0; + int restored_gen_len = 0; + TEST_ASSERT(test_capture_greedy_tokens(saved, 8, saved_gen, &saved_gen_len)); + TEST_ASSERT(test_capture_greedy_tokens(restored, 8, restored_gen, &restored_gen_len)); + TEST_ASSERT(saved_gen_len == restored_gen_len); + for (int i = 0; i < saved_gen_len && i < restored_gen_len; i++) { + if (saved_gen[i] != restored_gen[i]) { + fprintf(stderr, + "ds4-test: payload resume frontier=%d greedy mismatch step=%d saved=%d restored=%d\n", + frontier, i, saved_gen[i], restored_gen[i]); + } + TEST_ASSERT(saved_gen[i] == restored_gen[i]); + } + + fprintf(stderr, + "ds4-test: payload resume frontier=%d bytes=%llu raw_window=%u raw_cap=%u prefill_cap=%u top5_overlap=%d/5 overlap=%d/20 rms=%g max_abs=%g\n", + frontier, + (unsigned long long)payload.bytes, + meta.raw_window, + meta.raw_cap, + meta.prefill_cap, + result.top5_overlap, + result.overlap, + result.rms, + result.max_abs); + +cleanup: + free(saved_logits); + free(restored_logits); + test_dsv4_metadata_free(&meta); + ds4_session_payload_file_free(&payload); + ds4_session_free(restored); + ds4_session_free(saved); +} + +static bool test_save_layer_payload_bytes(ds4_session *session, + uint32_t layer_start, + uint32_t layer_end, + uint8_t **out, + size_t *len_out) { + *out = NULL; + *len_out = 0; + + const uint64_t payload_bytes = ds4_session_layer_payload_bytes(session, layer_start, layer_end); + TEST_ASSERT(payload_bytes > 0); + if (payload_bytes == 0 || payload_bytes > (uint64_t)SIZE_MAX) return false; + + FILE *fp = tmpfile(); + TEST_ASSERT(fp != NULL); + if (!fp) return false; + + char err[160]; + const int rc = ds4_session_save_layer_payload(session, fp, layer_start, layer_end, err, sizeof(err)); + TEST_ASSERT(rc == 0); + TEST_ASSERT(fflush(fp) == 0); + TEST_ASSERT(fseeko(fp, 0, SEEK_SET) == 0); + if (rc != 0 || fflush(fp) != 0 || fseeko(fp, 0, SEEK_SET) != 0) { + fclose(fp); + return false; + } + + uint8_t *buf = malloc((size_t)payload_bytes); + TEST_ASSERT(buf != NULL); + if (!buf) { + fclose(fp); + return false; + } + TEST_ASSERT(fread(buf, 1, (size_t)payload_bytes, fp) == (size_t)payload_bytes); + fclose(fp); + *out = buf; + *len_out = (size_t)payload_bytes; + return true; +} + +static bool test_load_layer_payload_bytes(ds4_session *session, + const uint8_t *buf, + size_t len, + const int *tokens, + uint32_t n_tokens, + uint32_t layer_start, + uint32_t layer_end) { + FILE *fp = tmpfile(); + TEST_ASSERT(fp != NULL); + if (!fp) return false; + const size_t nwritten = fwrite(buf, 1, len, fp); + const int flush_rc = fflush(fp); + const int rewind_rc = fseeko(fp, 0, SEEK_SET); + TEST_ASSERT(nwritten == len); + TEST_ASSERT(flush_rc == 0); + TEST_ASSERT(rewind_rc == 0); + if (nwritten != len || flush_rc != 0 || rewind_rc != 0) { + fclose(fp); + return false; + } + char err[160]; + const int rc = ds4_session_load_layer_payload(session, fp, (uint64_t)len, + tokens, n_tokens, + layer_start, layer_end, + err, sizeof(err)); + fclose(fp); + TEST_ASSERT(rc == 0); + return rc == 0; +} + +static void test_local_layer_payload_smoke(ds4_engine *engine, + const ds4_tokens *prompt, + int ctx, + int frontier) { + ds4_tokens prefix = { + .v = prompt->v, + .len = frontier, + .cap = frontier, + }; + ds4_session *base = NULL; + ds4_session *restored = NULL; + ds4_session_payload_file full_payload = {0}; + test_dsv4_metadata full_meta = {0}; + uint8_t *src_buf = NULL; + uint8_t *roundtrip_buf = NULL; + size_t src_len = 0; + size_t roundtrip_len = 0; + + TEST_ASSERT(ds4_session_create(&base, engine, ctx) == 0); + TEST_ASSERT(base != NULL); + if (!base) return; + + char err[160]; + TEST_ASSERT(ds4_session_sync(base, &prefix, err, sizeof(err)) == 0); + TEST_ASSERT(ds4_session_stage_payload(base, &full_payload, err, sizeof(err)) == 0); + TEST_ASSERT(test_parse_dsv4_metadata_file(full_payload.path, &full_payload, &full_meta)); + if (!test_parse_dsv4_metadata_file(full_payload.path, &full_payload, &full_meta)) goto cleanup; + + uint32_t layer_cases[4]; + int ncase = 0; + layer_cases[ncase++] = 0; + + uint32_t mid_layer = full_meta.n_layer / 2u; + uint32_t compressed_layer = mid_layer; + for (uint32_t delta = 0; delta < full_meta.n_layer; delta++) { + uint32_t left = mid_layer >= delta ? mid_layer - delta : 0; + uint32_t right = mid_layer + delta < full_meta.n_layer ? mid_layer + delta : full_meta.n_layer - 1u; + if (full_meta.n_comp[left] > 0 && full_meta.n_index_comp[left] == 0) { + compressed_layer = left; + break; + } + if (full_meta.n_comp[right] > 0 && full_meta.n_index_comp[right] == 0) { + compressed_layer = right; + break; + } + } + layer_cases[ncase++] = compressed_layer; + + uint32_t ratio4_layer = compressed_layer; + for (uint32_t il = 0; il < full_meta.n_layer; il++) { + if (full_meta.n_index_comp[il] > 0) { + ratio4_layer = il; + break; + } + } + layer_cases[ncase++] = ratio4_layer; + layer_cases[ncase++] = full_meta.n_layer - 1u; + + for (int i = 0; i < ncase; i++) { + const uint32_t layer = layer_cases[i]; + bool duplicate = false; + for (int j = 0; j < i; j++) { + if (layer_cases[j] == layer) duplicate = true; + } + if (duplicate) continue; + + free(src_buf); + free(roundtrip_buf); + src_buf = NULL; + roundtrip_buf = NULL; + src_len = 0; + roundtrip_len = 0; + + TEST_ASSERT(test_save_layer_payload_bytes(base, layer, layer, &src_buf, &src_len)); + test_dsvl_metadata dsvl = {0}; + TEST_ASSERT(test_parse_dsvl_metadata_bytes(src_buf, src_len, &dsvl)); + TEST_ASSERT(dsvl.layer_start == layer); + TEST_ASSERT(dsvl.layer_end == layer); + TEST_ASSERT(dsvl.saved_tokens == (uint32_t)frontier); + + TEST_ASSERT(ds4_session_create(&restored, engine, ctx) == 0); + TEST_ASSERT(restored != NULL); + if (!restored) break; + + TEST_ASSERT(test_load_layer_payload_bytes(restored, src_buf, src_len, + prompt->v, (uint32_t)frontier, + layer, layer)); + TEST_ASSERT(test_save_layer_payload_bytes(restored, layer, layer, + &roundtrip_buf, &roundtrip_len)); + TEST_ASSERT(src_len == roundtrip_len); + TEST_ASSERT(memcmp(src_buf, roundtrip_buf, src_len) == 0); + + fprintf(stderr, + "ds4-test: layer payload smoke layer=%u bytes=%zu raw_window=%u comp_cap=%u n_comp=%u n_index_comp=%u\n", + layer, + src_len, + dsvl.raw_window, + dsvl.comp_cap, + full_meta.n_comp[layer], + full_meta.n_index_comp[layer]); + + ds4_session_free(restored); + restored = NULL; + } + +cleanup: + free(src_buf); + free(roundtrip_buf); + test_dsv4_metadata_free(&full_meta); + ds4_session_payload_file_free(&full_payload); + ds4_session_free(restored); + ds4_session_free(base); +} + static void test_logits_topk(const float *logits, int n, int *out, int k); static bool test_topk_contains(const int *top, int k, int id); @@ -1103,6 +1695,88 @@ static void test_local_golden_vectors(void) { fclose(fp); } +static void test_local_payload_resume(void) { + char *saved_prefill_chunk = test_save_env("DS4_METAL_PREFILL_CHUNK"); + char *saved_disable_metal4 = test_save_env("DS4_METAL_DISABLE_METAL4"); + char *saved_moe_tile_max = test_save_env("DS4_METAL_MOE_TILE_MAX"); + setenv("DS4_METAL_PREFILL_CHUNK", "4096", 1); + setenv("DS4_METAL_DISABLE_METAL4", "1", 1); + unsetenv("DS4_METAL_MOE_TILE_MAX"); + + ds4_engine *engine = test_open_engine(false); + if (!engine) { + test_restore_env("DS4_METAL_MOE_TILE_MAX", saved_moe_tile_max); + test_restore_env("DS4_METAL_DISABLE_METAL4", saved_disable_metal4); + test_restore_env("DS4_METAL_PREFILL_CHUNK", saved_prefill_chunk); + return; + } + + ds4_tokens prompt = {0}; + if (!test_tokenize_phase1_prompt(engine, &prompt)) { + ds4_engine_close(engine); + test_restore_env("DS4_METAL_MOE_TILE_MAX", saved_moe_tile_max); + test_restore_env("DS4_METAL_DISABLE_METAL4", saved_disable_metal4); + test_restore_env("DS4_METAL_PREFILL_CHUNK", saved_prefill_chunk); + return; + } + + const int probe_ctx = 16384; + ds4_session *probe = NULL; + TEST_ASSERT(ds4_session_create(&probe, engine, probe_ctx) == 0); + TEST_ASSERT(probe != NULL); + test_dsv4_metadata probe_meta = {0}; + ds4_session_payload_file probe_payload = {0}; + if (probe) { + ds4_tokens prefix = { .v = prompt.v, .len = 1, .cap = 1 }; + char err[160]; + TEST_ASSERT(ds4_session_sync(probe, &prefix, err, sizeof(err)) == 0); + TEST_ASSERT(ds4_session_stage_payload(probe, &probe_payload, err, sizeof(err)) == 0); + TEST_ASSERT(test_parse_dsv4_metadata_file(probe_payload.path, &probe_payload, &probe_meta)); + fprintf(stderr, + "ds4-test: payload probe ctx=%u prefill_cap=%u raw_cap=%u raw_window=%u comp_cap=%u saved_tokens=%u n_layer=%u head_dim=%u indexer_head_dim=%u vocab=%u raw_live=%u\n", + probe_meta.ctx_size, + probe_meta.prefill_cap, + probe_meta.raw_cap, + probe_meta.raw_window, + probe_meta.comp_cap, + probe_meta.saved_tokens, + probe_meta.n_layer, + probe_meta.head_dim, + probe_meta.indexer_head_dim, + probe_meta.vocab, + probe_meta.raw_live); + } + const int ctx = probe_meta.raw_window > 0 ? (int)probe_meta.raw_window + 64 : 5000; + int frontiers[] = { + 1, 3, 4, 5, 4095, 4096, 4097, + (int)probe_meta.raw_window - 1, + (int)probe_meta.raw_window, + (int)probe_meta.raw_window + 1, + }; + const int nfrontiers = (int)(sizeof(frontiers) / sizeof(frontiers[0])); + for (int i = 0; i < nfrontiers; i++) { + const int frontier = frontiers[i]; + if (frontier <= 0 || frontier >= ctx || frontier > prompt.len) continue; + bool duplicate = false; + for (int j = 0; j < i; j++) { + if (frontiers[j] == frontier) duplicate = true; + } + if (duplicate) continue; + test_local_payload_resume_frontier(engine, &prompt, ctx, frontier, &probe_meta); + } + + test_local_layer_payload_smoke(engine, &prompt, ctx, probe_meta.raw_window); + + test_dsv4_metadata_free(&probe_meta); + ds4_session_payload_file_free(&probe_payload); + ds4_session_free(probe); + ds4_tokens_free(&prompt); + ds4_engine_close(engine); + test_restore_env("DS4_METAL_MOE_TILE_MAX", saved_moe_tile_max); + test_restore_env("DS4_METAL_DISABLE_METAL4", saved_disable_metal4); + test_restore_env("DS4_METAL_PREFILL_CHUNK", saved_prefill_chunk); +} + #define TEST_MPP_EQ_MAX_CASES 8 #define TEST_MPP_EQ_TOPK 20 #define TEST_MPP_EQ_TOP5 5 @@ -1613,6 +2287,7 @@ static const ds4_test_entry test_entries[] = { {"--long-context", "long-context", "long-context story fact-recall regression", test_long_story_fact_recall}, {"--tool-call-quality", "tool-call-quality", "model emits valid DSML tool calls", test_tool_call_quality}, {"--logprob-vectors", "logprob-vectors", "official API top-logprob vector comparison on the standard Metal path", test_official_logprob_vectors}, + {"--local-payload-resume", "local-payload-resume", "local DSV4 save/load resume and DSVL shard smoke", test_local_payload_resume}, {"--local-golden-vectors", "local-golden-vectors", "local top-k/logit drift regression for long Metal prefill", test_local_golden_vectors}, {"--metal-short-prefill", "metal-short-prefill", "Metal ratio-4 short prefill regression", test_metal_short_prefill_ratio4}, {"--metal-kernels", "metal-kernels", "isolated Metal kernel numeric regressions", test_metal_kernel_group}, diff --git a/tests/issue304_phase0_dgx.c b/tests/issue304_phase0_dgx.c new file mode 100644 index 000000000..8418b4a42 --- /dev/null +++ b/tests/issue304_phase0_dgx.c @@ -0,0 +1,433 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + const char *model_path; + const char *prompt_file; + const char *system_prompt; + const char *listen_host; + const char *coordinator_layers; + const char *worker_layers; + int listen_port; + int ctx_size; + int gen_tokens; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + bool debug; +} dgx_cfg; + +typedef struct { + uint32_t ctx_size; + uint32_t prefill_cap; + uint32_t raw_cap; + uint32_t raw_window; + uint32_t comp_cap; + uint32_t saved_tokens; + uint32_t n_layer; + uint32_t head_dim; + uint32_t indexer_head_dim; + uint32_t vocab; + uint32_t raw_live; +} dsv4_header; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die_usage(const char *argv0) { + fprintf(stderr, + "usage: %s --model FILE --listen-host IPV4 --listen-port N " + "[--prompt-file FILE] [--system TEXT] [--ctx N] [--gen-tokens N] " + "[--prefill-chunk N] [--prefill-window N] [--activation-bits N] " + "[--coordinator-layers A:B|A:output] [--worker-layers A:B|A:output] [--no-debug]\n", + argv0); + exit(2); +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase0-dgx: %s\n", msg); + exit(1); +} + +static void die_errno(const char *msg) { + fprintf(stderr, "issue304-phase0-dgx: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static void u64_to_halves(uint64_t v, uint32_t *hi, uint32_t *lo) { + *hi = (uint32_t)(v >> 32); + *lo = (uint32_t)v; +} + +static uint64_t token_hash_update(uint64_t h, int token) { + uint32_t t = (uint32_t)token; + for (int i = 0; i < 4; i++) { + h ^= (uint64_t)((t >> (i * 8)) & 0xffu); + h *= 1099511628211ull; + } + return h; +} + +static uint64_t token_hash_prefix(const ds4_tokens *tokens) { + uint64_t h = 1469598103934665603ull; + for (int i = 0; i < tokens->len; i++) h = token_hash_update(h, tokens->v[i]); + return h; +} + +static bool read_u32_le(FILE *fp, uint32_t *out) { + uint8_t buf[4]; + if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) return false; + *out = (uint32_t)buf[0] | + ((uint32_t)buf[1] << 8) | + ((uint32_t)buf[2] << 16) | + ((uint32_t)buf[3] << 24); + return true; +} + +static bool parse_dsv4_header(const char *path, dsv4_header *out) { + memset(out, 0, sizeof(*out)); + FILE *fp = fopen(path, "rb"); + if (!fp) return false; + + uint32_t h[DS4_SESSION_PAYLOAD_U32_FIELDS]; + for (uint32_t i = 0; i < DS4_SESSION_PAYLOAD_U32_FIELDS; i++) { + if (!read_u32_le(fp, &h[i])) { + fclose(fp); + return false; + } + } + fclose(fp); + + if (h[0] != DS4_SESSION_PAYLOAD_MAGIC || h[1] != DS4_SESSION_PAYLOAD_VERSION) { + return false; + } + + out->ctx_size = h[2]; + out->prefill_cap = h[3]; + out->raw_cap = h[4]; + out->raw_window = h[5]; + out->comp_cap = h[6]; + out->saved_tokens = h[7]; + out->n_layer = h[8]; + out->head_dim = h[9]; + out->indexer_head_dim = h[10]; + out->vocab = h[11]; + out->raw_live = h[12]; + return true; +} + +static int wait_route(ds4_session *session, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase0-dgx: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase0-dgx: timed out waiting for route\n"); + return 0; +} + +static bool parse_layer_spec(const char *spec, ds4_distributed_layers *out) { + if (!spec || !out) return false; + const char *colon = strchr(spec, ':'); + if (!colon || colon == spec || colon[1] == '\0') return false; + + errno = 0; + char *end = NULL; + unsigned long start = strtoul(spec, &end, 10); + if (errno != 0 || end != colon || start > UINT32_MAX) return false; + + ds4_distributed_layers layers = {0}; + layers.start = (uint32_t)start; + layers.set = true; + if (strcmp(colon + 1, "output") == 0) { + layers.has_output = true; + layers.end = 0; + } else { + errno = 0; + unsigned long layer_end = strtoul(colon + 1, &end, 10); + if (errno != 0 || *end != '\0' || layer_end > UINT32_MAX) return false; + layers.end = (uint32_t)layer_end; + } + *out = layers; + return true; +} + +static void parse_args(dgx_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--prompt-file") && i + 1 < argc) { + cfg->prompt_file = argv[++i]; + } else if (!strcmp(argv[i], "--system") && i + 1 < argc) { + cfg->system_prompt = argv[++i]; + } else if (!strcmp(argv[i], "--listen-host") && i + 1 < argc) { + cfg->listen_host = argv[++i]; + } else if (!strcmp(argv[i], "--listen-port") && i + 1 < argc) { + cfg->listen_port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx") && i + 1 < argc) { + cfg->ctx_size = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--gen-tokens") && i + 1 < argc) { + cfg->gen_tokens = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { + cfg->coordinator_layers = argv[++i]; + } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { + cfg->worker_layers = argv[++i]; + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + die_usage(argv[0]); + } + } +} + +int main(int argc, char **argv) { + dgx_cfg cfg = { + .model_path = NULL, + .prompt_file = "README.md", + .system_prompt = "You are a helpful assistant", + .listen_host = NULL, + .coordinator_layers = "0:21", + .worker_layers = "22:output", + .listen_port = 1234, + .ctx_size = 8192, + .gen_tokens = 16, + .prefill_chunk = 256, + .prefill_window = 0, + .activation_bits = 32, + .debug = true, + }; + parse_args(&cfg, argc, argv); + if (!cfg.model_path || !cfg.listen_host || cfg.listen_port <= 0 || cfg.ctx_size <= 0 || cfg.gen_tokens <= 0) { + die_usage(argv[0]); + } + + struct in_addr addr; + if (inet_pton(AF_INET, cfg.listen_host, &addr) != 1) { + die("listen host must be an IPv4 address reachable from the worker"); + } + + ds4_distributed_layers coordinator_layers = {0}; + if (!parse_layer_spec(cfg.coordinator_layers, &coordinator_layers)) { + die("invalid coordinator layer spec"); + } + + char *prompt_text = read_file(cfg.prompt_file); + if (!prompt_text) die_errno("read prompt file"); + + ds4_engine *engine = NULL; + ds4_session *session = NULL; + ds4_tokens prompt = {0}; + ds4_session_payload_file payload = {0}; + dsv4_header header; + bool stage_ok = false; + char stage_err[256] = {0}; + + ds4_engine_options opt = { + .model_path = cfg.model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = coordinator_layers, + .listen_host = cfg.listen_host, + .listen_port = cfg.listen_port, + .prefill_chunk = cfg.prefill_chunk, + .prefill_window = cfg.prefill_window, + .activation_bits = cfg.activation_bits, + .debug = cfg.debug, + }, + }; + + char err[256] = {0}; + if (ds4_dist_prepare_engine_options(&opt.distributed, &opt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase0-dgx: distributed options failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + if (ds4_engine_open(&engine, &opt) != 0 || !engine) { + die("failed to open coordinator engine"); + } + if (ds4_session_create(&session, engine, cfg.ctx_size) != 0 || !session) { + die("failed to create coordinator session"); + } + if (wait_route(session, 60.0) != 1) goto fail; + + char route_summary[1024] = {0}; + uint32_t route_hops = 0; + bool output_on_coordinator = false; + if (ds4_session_distributed_route_summary(session, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator, + err, + sizeof(err)) != 1) { + fprintf(stderr, "issue304-phase0-dgx: route summary failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + + ds4_encode_chat_prompt(engine, cfg.system_prompt, prompt_text, DS4_THINK_NONE, &prompt); + if (prompt.len <= 0) die("prompt tokenization failed"); + if (prompt.len >= cfg.ctx_size) die("prompt exceeds ctx"); + + double t0 = now_sec(); + if (ds4_session_sync(session, &prompt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase0-dgx: distributed prefill failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + double t1 = now_sec(); + double prefill_sec = t1 - t0; + + memset(&header, 0, sizeof(header)); + double t2 = now_sec(); + if (ds4_session_stage_payload(session, &payload, err, sizeof(err)) == 0) { + stage_ok = true; + if (!parse_dsv4_header(payload.path, &header)) { + die("failed to parse staged DSV4 header"); + } + } else { + snprintf(stage_err, sizeof(stage_err), "%s", err[0] ? err : "unknown error"); + fprintf(stderr, "issue304-phase0-dgx: distributed payload stage failed: %s\n", stage_err); + } + double t3 = now_sec(); + + const ds4_tokens *timeline = ds4_session_tokens(session); + const uint64_t hash = token_hash_prefix(timeline); + uint32_t hash_hi = 0; + uint32_t hash_lo = 0; + u64_to_halves(hash, &hash_hi, &hash_lo); + + double t4 = now_sec(); + for (int i = 0; i < cfg.gen_tokens; i++) { + int token = ds4_session_argmax(session); + if (i + 1 < cfg.gen_tokens && + ds4_session_eval(session, token, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase0-dgx: distributed decode failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + } + double t5 = now_sec(); + + printf("{\n"); + printf(" \"tool\":\"issue304_phase0_dgx\",\n"); + printf(" \"listen_host\":\"%s\",\n", cfg.listen_host); + printf(" \"listen_port\":%d,\n", cfg.listen_port); + printf(" \"model_path\":\"%s\",\n", cfg.model_path); + printf(" \"prompt_file\":\"%s\",\n", cfg.prompt_file); + printf(" \"ctx\":%d,\n", cfg.ctx_size); + printf(" \"prompt_tokens\":%d,\n", prompt.len); + printf(" \"gen_tokens\":%d,\n", cfg.gen_tokens); + printf(" \"prefill_chunk\":%u,\n", cfg.prefill_chunk); + printf(" \"prefill_window\":%u,\n", cfg.prefill_window); + printf(" \"activation_bits\":%u,\n", cfg.activation_bits); + printf(" \"debug\":%s,\n", cfg.debug ? "true" : "false"); + printf(" \"coordinator_layers\":\"%s\",\n", cfg.coordinator_layers); + printf(" \"expected_worker_layers\":\"%s\",\n", cfg.worker_layers); + printf(" \"route_hops\":%u,\n", route_hops); + printf(" \"route_summary\":\"%s\",\n", route_summary); + printf(" \"output_owner\":\"%s\",\n", output_on_coordinator ? "coordinator" : "worker"); + printf(" \"prefill_sec\":%.6f,\n", prefill_sec); + printf(" \"prefill_tok_per_sec\":%.2f,\n", prefill_sec > 0.0 ? (double)prompt.len / prefill_sec : 0.0); + printf(" \"stage_ok\":%s,\n", stage_ok ? "true" : "false"); + printf(" \"stage_sec\":%.6f,\n", t3 - t2); + printf(" \"payload_bytes\":%llu,\n", (unsigned long long)payload.bytes); + printf(" \"stage_error\":\"%s\",\n", stage_ok ? "" : stage_err); + printf(" \"decode_sec\":%.6f,\n", t5 - t4); + printf(" \"decode_tok_per_sec\":%.2f,\n", (t5 - t4) > 0.0 ? (double)cfg.gen_tokens / (t5 - t4) : 0.0); + printf(" \"token_count\":%d,\n", timeline ? timeline->len : 0); + printf(" \"token_hash\":\"0x%08x%08x\",\n", hash_hi, hash_lo); + if (stage_ok) { + printf(" \"dsv4\":{\n"); + printf(" \"ctx_size\":%u,\n", header.ctx_size); + printf(" \"prefill_cap\":%u,\n", header.prefill_cap); + printf(" \"raw_cap\":%u,\n", header.raw_cap); + printf(" \"raw_window\":%u,\n", header.raw_window); + printf(" \"comp_cap\":%u,\n", header.comp_cap); + printf(" \"saved_tokens\":%u,\n", header.saved_tokens); + printf(" \"n_layer\":%u,\n", header.n_layer); + printf(" \"head_dim\":%u,\n", header.head_dim); + printf(" \"indexer_head_dim\":%u,\n", header.indexer_head_dim); + printf(" \"vocab\":%u,\n", header.vocab); + printf(" \"raw_live\":%u\n", header.raw_live); + printf(" }\n"); + } else { + printf(" \"dsv4\":null\n"); + } + printf("}\n"); + + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); + free(prompt_text); + return 0; + +fail: + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); + free(prompt_text); + return 1; +} diff --git a/tests/issue304_phase0_local.c b/tests/issue304_phase0_local.c new file mode 100644 index 000000000..9d8a397e4 --- /dev/null +++ b/tests/issue304_phase0_local.c @@ -0,0 +1,436 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern char **environ; + +typedef struct { + const char *model_path; + const char *prompt_file; + const char *worker_bin; + const char *host; + int port; + int ctx_size; + int gen_tokens; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + bool debug; +} local_cfg; + +typedef struct { + uint32_t ctx_size; + uint32_t prefill_cap; + uint32_t raw_cap; + uint32_t raw_window; + uint32_t comp_cap; + uint32_t saved_tokens; + uint32_t n_layer; + uint32_t head_dim; + uint32_t indexer_head_dim; + uint32_t vocab; + uint32_t raw_live; +} dsv4_header; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase0-local: %s\n", msg); + exit(1); +} + +static void die_errno(const char *msg) { + fprintf(stderr, "issue304-phase0-local: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static int pick_port(const char *host) { + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) die_errno("socket"); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(0); + if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) { + close(fd); + die("invalid host for port probe"); + } + if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) != 0) { + close(fd); + die_errno("bind port probe"); + } + + socklen_t len = (socklen_t)sizeof(addr); + if (getsockname(fd, (struct sockaddr *)&addr, &len) != 0) { + close(fd); + die_errno("getsockname"); + } + int port = (int)ntohs(addr.sin_port); + close(fd); + return port; +} + +static void u64_to_halves(uint64_t v, uint32_t *hi, uint32_t *lo) { + *hi = (uint32_t)(v >> 32); + *lo = (uint32_t)v; +} + +static uint64_t dist_token_hash_update(uint64_t h, int token) { + uint32_t t = (uint32_t)token; + for (int i = 0; i < 4; i++) { + h ^= (uint64_t)((t >> (i * 8)) & 0xffu); + h *= 1099511628211ull; + } + return h; +} + +static uint64_t dist_token_hash_prefix(const ds4_tokens *tokens) { + uint64_t h = 1469598103934665603ull; + for (int i = 0; i < tokens->len; i++) h = dist_token_hash_update(h, tokens->v[i]); + return h; +} + +static bool read_u32_le(FILE *fp, uint32_t *out) { + uint8_t buf[4]; + if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) return false; + *out = (uint32_t)buf[0] | + ((uint32_t)buf[1] << 8) | + ((uint32_t)buf[2] << 16) | + ((uint32_t)buf[3] << 24); + return true; +} + +static bool parse_dsv4_header(const char *path, dsv4_header *out) { + memset(out, 0, sizeof(*out)); + FILE *fp = fopen(path, "rb"); + if (!fp) return false; + + uint32_t h[DS4_SESSION_PAYLOAD_U32_FIELDS]; + for (uint32_t i = 0; i < DS4_SESSION_PAYLOAD_U32_FIELDS; i++) { + if (!read_u32_le(fp, &h[i])) { + fclose(fp); + return false; + } + } + fclose(fp); + + if (h[0] != DS4_SESSION_PAYLOAD_MAGIC || h[1] != DS4_SESSION_PAYLOAD_VERSION) { + return false; + } + + out->ctx_size = h[2]; + out->prefill_cap = h[3]; + out->raw_cap = h[4]; + out->raw_window = h[5]; + out->comp_cap = h[6]; + out->saved_tokens = h[7]; + out->n_layer = h[8]; + out->head_dim = h[9]; + out->indexer_head_dim = h[10]; + out->vocab = h[11]; + out->raw_live = h[12]; + return true; +} + +static void kill_worker(pid_t pid) { + if (pid <= 0) return; + kill(pid, SIGTERM); + for (int i = 0; i < 50; i++) { + int status = 0; + pid_t got = waitpid(pid, &status, WNOHANG); + if (got == pid) return; + usleep(100000); + } + kill(pid, SIGKILL); + (void)waitpid(pid, NULL, 0); +} + +static pid_t spawn_worker(const local_cfg *cfg) { + char port[16]; + snprintf(port, sizeof(port), "%d", cfg->port); + + char *const argv[] = { + (char *)cfg->worker_bin, + "-m", (char *)cfg->model_path, + "--role", "worker", + "--layers", "22:output", + "--coordinator", (char *)cfg->host, port, + NULL, + }; + + pid_t pid = 0; + int rc = posix_spawn(&pid, cfg->worker_bin, NULL, NULL, argv, environ); + if (rc != 0) { + errno = rc; + die_errno("posix_spawn worker"); + } + return pid; +} + +static int wait_route(ds4_session *session, pid_t worker_pid, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + int status = 0; + pid_t got = waitpid(worker_pid, &status, WNOHANG); + if (got == worker_pid) { + if (WIFEXITED(status)) { + fprintf(stderr, + "issue304-phase0-local: worker exited before route formation with status %d\n", + WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + fprintf(stderr, + "issue304-phase0-local: worker exited before route formation from signal %d\n", + WTERMSIG(status)); + } else { + fprintf(stderr, "issue304-phase0-local: worker exited before route formation\n"); + } + return -1; + } + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase0-local: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase0-local: timed out waiting for route\n"); + return 0; +} + +static void parse_args(local_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--prompt-file") && i + 1 < argc) { + cfg->prompt_file = argv[++i]; + } else if (!strcmp(argv[i], "--worker-bin") && i + 1 < argc) { + cfg->worker_bin = argv[++i]; + } else if (!strcmp(argv[i], "--host") && i + 1 < argc) { + cfg->host = argv[++i]; + } else if (!strcmp(argv[i], "--port") && i + 1 < argc) { + cfg->port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx") && i + 1 < argc) { + cfg->ctx_size = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--gen-tokens") && i + 1 < argc) { + cfg->gen_tokens = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + fprintf(stderr, + "usage: %s [--model FILE] [--prompt-file FILE] [--worker-bin FILE] [--host IPV4] [--port N] [--ctx N] [--gen-tokens N] [--prefill-chunk N] [--prefill-window N] [--activation-bits N] [--no-debug]\n", + argv[0]); + exit(2); + } + } +} + +int main(int argc, char **argv) { + local_cfg cfg = { + .model_path = "ds4flash.gguf", + .prompt_file = "README.md", + .worker_bin = "./ds4", + .host = "127.0.0.1", + .port = 0, + .ctx_size = 8192, + .gen_tokens = 16, + .prefill_chunk = 256, + .prefill_window = 0, + .activation_bits = 32, + .debug = true, + }; + parse_args(&cfg, argc, argv); + if (cfg.port == 0) cfg.port = pick_port(cfg.host); + + pid_t worker_pid = 0; + ds4_engine *engine = NULL; + ds4_session *session = NULL; + ds4_tokens prompt = {0}; + ds4_session_payload_file payload = {0}; + char *prompt_text = NULL; + + prompt_text = read_file(cfg.prompt_file); + if (!prompt_text) die_errno("read prompt file"); + + worker_pid = spawn_worker(&cfg); + + ds4_engine_options opt = { + .model_path = cfg.model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = { + .start = 0, + .end = 21, + .has_output = false, + .set = true, + }, + .listen_host = cfg.host, + .listen_port = cfg.port, + .prefill_chunk = cfg.prefill_chunk, + .prefill_window = cfg.prefill_window, + .activation_bits = cfg.activation_bits, + .debug = cfg.debug, + }, + }; + + char err[256] = {0}; + if (ds4_dist_prepare_engine_options(&opt.distributed, &opt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase0-local: distributed options failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + if (ds4_engine_open(&engine, &opt) != 0 || !engine) { + die("failed to open coordinator engine"); + } + if (ds4_session_create(&session, engine, cfg.ctx_size) != 0 || !session) { + die("failed to create coordinator session"); + } + if (wait_route(session, worker_pid, 30.0) != 1) goto fail; + + ds4_encode_chat_prompt(engine, "You are a helpful assistant", prompt_text, DS4_THINK_NONE, &prompt); + if (prompt.len <= 0) die("prompt tokenization failed"); + if (prompt.len >= cfg.ctx_size) die("prompt exceeds ctx"); + const uint32_t chunks = (uint32_t)((prompt.len + (int)cfg.prefill_chunk - 1) / (int)cfg.prefill_chunk); + if (chunks < 2u) die("prompt does not exercise multi-chunk distributed prefill; use a longer prompt or smaller --prefill-chunk"); + + printf("PHASE0_LOCAL_CONFIG host=%s port=%d model=%s prompt_file=%s ctx=%d prefill_chunk=%u prefill_window=%u activation_bits=%u gen_tokens=%d worker_layers=22:output coordinator_layers=0:21\n", + cfg.host, cfg.port, cfg.model_path, cfg.prompt_file, cfg.ctx_size, + cfg.prefill_chunk, cfg.prefill_window, cfg.activation_bits, cfg.gen_tokens); + printf("PHASE0_LOCAL_PROMPT tokens=%d chunks=%u\n", prompt.len, chunks); + + double t0 = now_sec(); + if (ds4_session_sync(session, &prompt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase0-local: distributed prefill failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + double t1 = now_sec(); + double prefill_sec = t1 - t0; + + double t2 = now_sec(); + if (ds4_session_stage_payload(session, &payload, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase0-local: distributed payload stage failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + double t3 = now_sec(); + + dsv4_header header; + if (!parse_dsv4_header(payload.path, &header)) { + die("failed to parse staged DSV4 header"); + } + + const ds4_tokens *timeline = ds4_session_tokens(session); + const uint64_t token_hash = dist_token_hash_prefix(timeline); + uint32_t hash_hi = 0, hash_lo = 0; + u64_to_halves(token_hash, &hash_hi, &hash_lo); + + double t4 = now_sec(); + for (int i = 0; i < cfg.gen_tokens; i++) { + int token = ds4_session_argmax(session); + if (i + 1 < cfg.gen_tokens && + ds4_session_eval(session, token, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase0-local: distributed decode failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + } + double t5 = now_sec(); + + printf("PHASE0_LOCAL_PREFILL tokens=%d sec=%.6f tok_per_sec=%.2f\n", + prompt.len, prefill_sec, (double)prompt.len / prefill_sec); + printf("PHASE0_LOCAL_STAGE bytes=%llu sec=%.6f mib=%.2f\n", + (unsigned long long)payload.bytes, + t3 - t2, + (double)payload.bytes / (1024.0 * 1024.0)); + printf("PHASE0_LOCAL_DECODE tokens=%d sec=%.6f tok_per_sec=%.2f\n", + cfg.gen_tokens, t5 - t4, (double)cfg.gen_tokens / (t5 - t4)); + printf("PHASE0_LOCAL_ROUTE coordinator=0:21 worker=22:output output_owner=worker debug=%d\n", + cfg.debug ? 1 : 0); + printf("PHASE0_LOCAL_HASH token_count=%d token_hash=0x%08x%08x\n", + timeline ? timeline->len : 0, hash_hi, hash_lo); + printf("PHASE0_LOCAL_DSV4 ctx_size=%u prefill_cap=%u raw_cap=%u raw_window=%u comp_cap=%u saved_tokens=%u n_layer=%u head_dim=%u indexer_head_dim=%u vocab=%u raw_live=%u\n", + header.ctx_size, header.prefill_cap, header.raw_cap, header.raw_window, + header.comp_cap, header.saved_tokens, header.n_layer, header.head_dim, + header.indexer_head_dim, header.vocab, header.raw_live); + + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); + free(prompt_text); + kill_worker(worker_pid); + return 0; + +fail: + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); + free(prompt_text); + kill_worker(worker_pid); + return 1; +} diff --git a/tests/issue304_phase1_matrix.c b/tests/issue304_phase1_matrix.c new file mode 100644 index 000000000..81cea6dd2 --- /dev/null +++ b/tests/issue304_phase1_matrix.c @@ -0,0 +1,585 @@ +#include "../ds4.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + const char *mode; + const char *model_path; + const char *prompt_file; + const char *payload_path; + const char *logits_path; + const char *tokens_path; + const char *trace_path; + const char *ref_trace_path; + int ctx; + int frontier; + int greedy_steps; +} matrix_cfg; + +typedef struct { + int top1_saved; + int top1_restored; + int overlap; + int top5_overlap; + int nonfinite; + float rms; + float max_abs; +} logits_cmp; + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase1-matrix: %s\n", msg); + exit(1); +} + +static void die_errno(const char *msg) { + fprintf(stderr, "issue304-phase1-matrix: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static void usage(const char *argv0) { + fprintf(stderr, + "usage: %s --mode save|load-check --model FILE --payload FILE --logits FILE --tokens FILE " + "[--prompt-file FILE] [--ctx N] [--frontier N] [--greedy-steps N]\n", + argv0); + exit(2); +} + +static char *read_file(const char *path, size_t *len_out) { + if (len_out) *len_out = 0; + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (len != 0 && fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + if (len_out) *len_out = (size_t)len; + return buf; +} + +static bool write_binary_file(const char *path, const void *ptr, size_t bytes) { + FILE *fp = fopen(path, "wb"); + if (!fp) return false; + bool ok = fwrite(ptr, 1, bytes, fp) == bytes; + ok = ok && fclose(fp) == 0; + return ok; +} + +static bool read_binary_file(const char *path, void *ptr, size_t bytes) { + FILE *fp = fopen(path, "rb"); + if (!fp) return false; + bool ok = fread(ptr, 1, bytes, fp) == bytes; + ok = ok && fclose(fp) == 0; + return ok; +} + +static bool write_tokens_file(const char *path, const int *tokens, int count) { + FILE *fp = fopen(path, "wb"); + if (!fp) return false; + if (fprintf(fp, "%d\n", count) < 0) { + fclose(fp); + return false; + } + for (int i = 0; i < count; i++) { + if (fprintf(fp, "%d\n", tokens[i]) < 0) { + fclose(fp); + return false; + } + } + return fclose(fp) == 0; +} + +static bool read_tokens_file(const char *path, int *tokens, int cap, int *count_out) { + *count_out = 0; + FILE *fp = fopen(path, "rb"); + if (!fp) return false; + int count = 0; + if (fscanf(fp, "%d", &count) != 1 || count < 0 || count > cap) { + fclose(fp); + return false; + } + for (int i = 0; i < count; i++) { + if (fscanf(fp, "%d", &tokens[i]) != 1) { + fclose(fp); + return false; + } + } + fclose(fp); + *count_out = count; + return true; +} + +static bool read_trace_file(const char *path, float *ptr, size_t bytes) { + return read_binary_file(path, ptr, bytes); +} + +static void logits_topk(const float *logits, int n, int *out, int k) { + for (int i = 0; i < k; i++) out[i] = -1; + for (int i = 0; i < n; i++) { + const float v = logits[i]; + for (int j = 0; j < k; j++) { + if (out[j] < 0 || v > logits[out[j]]) { + for (int t = k - 1; t > j; t--) out[t] = out[t - 1]; + out[j] = i; + break; + } + } + } +} + +static bool topk_contains(const int *top, int k, int id) { + for (int i = 0; i < k; i++) { + if (top[i] == id) return true; + } + return false; +} + +static logits_cmp compare_logits(const float *saved, const float *restored, int vocab) { + int saved_top[20]; + int restored_top[20]; + logits_topk(saved, vocab, saved_top, 20); + logits_topk(restored, vocab, restored_top, 20); + + int overlap = 0; + int top5_overlap = 0; + for (int i = 0; i < 20; i++) { + if (saved_top[i] >= 0 && topk_contains(restored_top, 20, saved_top[i])) overlap++; + if (i < 5 && saved_top[i] >= 0 && topk_contains(restored_top, 5, saved_top[i])) top5_overlap++; + } + + int nonfinite = 0; + double sumsq = 0.0; + float max_abs = 0.0f; + for (int i = 0; i < vocab; i++) { + if (!isfinite(saved[i]) || !isfinite(restored[i])) { + nonfinite++; + continue; + } + float delta = restored[i] - saved[i]; + float abs_delta = fabsf(delta); + if (abs_delta > max_abs) max_abs = abs_delta; + sumsq += (double)delta * (double)delta; + } + + logits_cmp out = { + .top1_saved = saved_top[0], + .top1_restored = restored_top[0], + .overlap = overlap, + .top5_overlap = top5_overlap, + .nonfinite = nonfinite, + .rms = (float)sqrt(sumsq / (double)vocab), + .max_abs = max_abs, + }; + return out; +} + +static bool capture_greedy_tokens(ds4_session *session, int steps, int *out, int *out_len) { + char err[160]; + int n = 0; + while (n < steps) { + int token = ds4_session_argmax(session); + out[n++] = token; + if (n < steps && ds4_session_eval(session, token, err, sizeof(err)) != 0) { + *out_len = n; + return false; + } + } + *out_len = n; + return true; +} + +static void parse_args(matrix_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--mode") && i + 1 < argc) { + cfg->mode = argv[++i]; + } else if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--prompt-file") && i + 1 < argc) { + cfg->prompt_file = argv[++i]; + } else if (!strcmp(argv[i], "--payload") && i + 1 < argc) { + cfg->payload_path = argv[++i]; + } else if (!strcmp(argv[i], "--logits") && i + 1 < argc) { + cfg->logits_path = argv[++i]; + } else if (!strcmp(argv[i], "--tokens") && i + 1 < argc) { + cfg->tokens_path = argv[++i]; + } else if (!strcmp(argv[i], "--trace") && i + 1 < argc) { + cfg->trace_path = argv[++i]; + } else if (!strcmp(argv[i], "--ref-trace") && i + 1 < argc) { + cfg->ref_trace_path = argv[++i]; + } else if (!strcmp(argv[i], "--ctx") && i + 1 < argc) { + cfg->ctx = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--frontier") && i + 1 < argc) { + cfg->frontier = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--greedy-steps") && i + 1 < argc) { + cfg->greedy_steps = atoi(argv[++i]); + } else { + usage(argv[0]); + } + } +} + +static ds4_engine *open_engine(const matrix_cfg *cfg) { + ds4_engine *engine = NULL; + ds4_engine_options opt = { + .model_path = cfg->model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + }; + if (ds4_engine_open(&engine, &opt) != 0 || !engine) { + die("failed to open engine"); + } + return engine; +} + +static bool tokenize_prompt(ds4_engine *engine, const char *prompt_file, ds4_tokens *prompt) { + memset(prompt, 0, sizeof(*prompt)); + char *text = read_file(prompt_file, NULL); + if (!text) return false; + ds4_tokenize_text(engine, text, prompt); + free(text); + return prompt->len > 0; +} + +static int run_save(const matrix_cfg *cfg) { + ds4_engine *engine = open_engine(cfg); + ds4_tokens prompt = {0}; + if (!tokenize_prompt(engine, cfg->prompt_file, &prompt)) die_errno("read prompt"); + if (cfg->frontier <= 0 || cfg->frontier > prompt.len) die("invalid frontier"); + + ds4_tokens prefix = {.v = prompt.v, .len = cfg->frontier, .cap = cfg->frontier}; + ds4_session *session = NULL; + if (ds4_session_create(&session, engine, cfg->ctx) != 0 || !session) die("failed to create session"); + + char err[160]; + if (ds4_session_sync(session, &prefix, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase1-matrix: sync failed: %s\n", err); + return 1; + } + + const int vocab = ds4_engine_vocab_size(engine); + float *logits = malloc((size_t)vocab * sizeof(logits[0])); + if (!logits) die("out of memory for logits"); + if (ds4_session_copy_logits(session, logits, vocab) != vocab) die("failed to copy logits"); + + ds4_session_payload_file payload = {0}; + if (ds4_session_stage_payload(session, &payload, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase1-matrix: stage failed: %s\n", err); + return 1; + } + + int *tokens = malloc((size_t)cfg->greedy_steps * sizeof(tokens[0])); + int token_count = 0; + if (!tokens) die("out of memory for greedy tokens"); + if (!capture_greedy_tokens(session, cfg->greedy_steps, tokens, &token_count)) { + die("failed to capture greedy tokens"); + } + + FILE *dst = fopen(cfg->payload_path, "wb"); + if (!dst) die_errno("open payload output"); + if (ds4_session_write_staged_payload(&payload, dst, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase1-matrix: write staged payload failed: %s\n", err); + fclose(dst); + return 1; + } + if (fclose(dst) != 0) die_errno("close payload output"); + if (!write_binary_file(cfg->logits_path, logits, (size_t)vocab * sizeof(logits[0]))) { + die_errno("write logits output"); + } + if (!write_tokens_file(cfg->tokens_path, tokens, token_count)) { + die_errno("write tokens output"); + } + + printf("{\"mode\":\"save\",\"backend\":\"%s\",\"ctx\":%d,\"frontier\":%d,\"payload_bytes\":%llu,\"vocab\":%d,\"greedy_steps\":%d}\n", +#ifdef __APPLE__ + "metal", +#else + "cuda", +#endif + cfg->ctx, + cfg->frontier, + (unsigned long long)payload.bytes, + vocab, + token_count); + + free(tokens); + free(logits); + ds4_session_payload_file_free(&payload); + ds4_session_free(session); + ds4_tokens_free(&prompt); + ds4_engine_close(engine); + return 0; +} + +static int run_load_check(const matrix_cfg *cfg) { + ds4_engine *engine = open_engine(cfg); + ds4_session *session = NULL; + if (ds4_session_create(&session, engine, cfg->ctx) != 0 || !session) die("failed to create session"); + + FILE *fp = fopen(cfg->payload_path, "rb"); + if (!fp) die_errno("open payload input"); + if (fseek(fp, 0, SEEK_END) != 0) die_errno("seek payload input"); + long bytes = ftell(fp); + if (bytes < 0) die_errno("measure payload input"); + rewind(fp); + + char err[160]; + if (ds4_session_load_payload(session, fp, (uint64_t)bytes, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase1-matrix: load failed: %s\n", err); + fclose(fp); + return 1; + } + fclose(fp); + + const int vocab = ds4_engine_vocab_size(engine); + float *saved_logits = malloc((size_t)vocab * sizeof(saved_logits[0])); + float *restored_logits = malloc((size_t)vocab * sizeof(restored_logits[0])); + int *saved_tokens = malloc((size_t)cfg->greedy_steps * sizeof(saved_tokens[0])); + int *restored_tokens = malloc((size_t)cfg->greedy_steps * sizeof(restored_tokens[0])); + int saved_token_count = 0; + int restored_token_count = 0; + int greedy_mismatch_step = -1; + int greedy_saved_token = -1; + int greedy_restored_token = -1; + if (!saved_logits || !restored_logits || !saved_tokens || !restored_tokens) die("out of memory in load-check"); + + if (!read_binary_file(cfg->logits_path, saved_logits, (size_t)vocab * sizeof(saved_logits[0]))) { + die_errno("read logits input"); + } + if (ds4_session_copy_logits(session, restored_logits, vocab) != vocab) die("failed to copy restored logits"); + if (!read_tokens_file(cfg->tokens_path, saved_tokens, cfg->greedy_steps, &saved_token_count)) { + die_errno("read tokens input"); + } + if (!capture_greedy_tokens(session, cfg->greedy_steps, restored_tokens, &restored_token_count)) { + die("failed to capture restored greedy tokens"); + } + + logits_cmp cmp = compare_logits(saved_logits, restored_logits, vocab); + bool tokens_match = saved_token_count == restored_token_count; + for (int i = 0; i < saved_token_count && i < restored_token_count; i++) { + if (saved_tokens[i] != restored_tokens[i]) { + tokens_match = false; + if (greedy_mismatch_step < 0) { + greedy_mismatch_step = i; + greedy_saved_token = saved_tokens[i]; + greedy_restored_token = restored_tokens[i]; + } + } + } + + printf("{\"mode\":\"load-check\",\"backend\":\"%s\",\"ctx\":%d,\"payload_bytes\":%ld,\"top1_saved\":%d,\"top1_restored\":%d,\"top5_overlap\":%d,\"top20_overlap\":%d,\"rms\":%.9g,\"max_abs\":%.9g,\"nonfinite\":%d,\"greedy_steps\":%d,\"greedy_match\":%s,\"greedy_mismatch_step\":%d,\"greedy_saved_token\":%d,\"greedy_restored_token\":%d}\n", +#ifdef __APPLE__ + "metal", +#else + "cuda", +#endif + cfg->ctx, + bytes, + cmp.top1_saved, + cmp.top1_restored, + cmp.top5_overlap, + cmp.overlap, + cmp.rms, + cmp.max_abs, + cmp.nonfinite, + restored_token_count, + tokens_match ? "true" : "false", + greedy_mismatch_step, + greedy_saved_token, + greedy_restored_token); + + free(saved_tokens); + free(restored_tokens); + free(saved_logits); + free(restored_logits); + ds4_session_free(session); + ds4_engine_close(engine); + + if (cmp.nonfinite != 0 || cmp.top1_saved != cmp.top1_restored || + cmp.top5_overlap < 5 || cmp.overlap < 16 || !tokens_match) { + return 1; + } + return 0; +} + +static int run_trace_forced(const matrix_cfg *cfg) { + ds4_engine *engine = open_engine(cfg); + ds4_session *session = NULL; + if (ds4_session_create(&session, engine, cfg->ctx) != 0 || !session) die("failed to create session"); + + FILE *fp = fopen(cfg->payload_path, "rb"); + if (!fp) die_errno("open payload input"); + if (fseek(fp, 0, SEEK_END) != 0) die_errno("seek payload input"); + long payload_bytes = ftell(fp); + if (payload_bytes < 0) die_errno("measure payload input"); + rewind(fp); + + char err[160]; + if (ds4_session_load_payload(session, fp, (uint64_t)payload_bytes, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase1-matrix: load failed: %s\n", err); + fclose(fp); + return 1; + } + fclose(fp); + + int *tokens = malloc((size_t)cfg->greedy_steps * sizeof(tokens[0])); + if (!tokens) die("out of memory for trace tokens"); + int token_count = 0; + if (!read_tokens_file(cfg->tokens_path, tokens, cfg->greedy_steps, &token_count)) { + die_errno("read tokens input"); + } + + const int vocab = ds4_engine_vocab_size(engine); + const size_t trace_floats = (size_t)(token_count + 1) * (size_t)vocab; + float *trace = malloc(trace_floats * sizeof(trace[0])); + if (!trace) die("out of memory for trace output"); + + if (ds4_session_copy_logits(session, trace, vocab) != vocab) die("failed to copy initial trace logits"); + for (int i = 0; i < token_count; i++) { + if (ds4_session_eval(session, tokens[i], err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase1-matrix: forced eval failed at step %d: %s\n", + i, err[0] ? err : "unknown error"); + return 1; + } + if (ds4_session_copy_logits(session, trace + (size_t)(i + 1) * (size_t)vocab, vocab) != vocab) { + die("failed to copy trace logits"); + } + } + + if (!write_binary_file(cfg->trace_path, trace, trace_floats * sizeof(trace[0]))) { + die_errno("write trace output"); + } + + printf("{\"mode\":\"trace-forced\",\"backend\":\"%s\",\"ctx\":%d,\"payload_bytes\":%ld,\"steps\":%d,\"vocab\":%d}\n", +#ifdef __APPLE__ + "metal", +#else + "cuda", +#endif + cfg->ctx, + payload_bytes, + token_count, + vocab); + + free(trace); + free(tokens); + ds4_session_free(session); + ds4_engine_close(engine); + return 0; +} + +static int run_compare_trace(const matrix_cfg *cfg) { + int *tokens = malloc((size_t)cfg->greedy_steps * sizeof(tokens[0])); + if (!tokens) die("out of memory for compare tokens"); + int token_count = 0; + if (!read_tokens_file(cfg->tokens_path, tokens, cfg->greedy_steps, &token_count)) { + die_errno("read tokens input"); + } + + ds4_engine *engine = open_engine(cfg); + const int vocab = ds4_engine_vocab_size(engine); + ds4_engine_close(engine); + + const size_t trace_floats = (size_t)(token_count + 1) * (size_t)vocab; + const size_t trace_bytes = trace_floats * sizeof(float); + float *ref = malloc(trace_bytes); + float *cand = malloc(trace_bytes); + if (!ref || !cand) die("out of memory for trace compare"); + if (!read_trace_file(cfg->ref_trace_path, ref, trace_bytes)) die_errno("read ref trace"); + if (!read_trace_file(cfg->trace_path, cand, trace_bytes)) die_errno("read candidate trace"); + + int first_bad_step = -1; + logits_cmp first_cmp = {0}; + for (int step = 0; step <= token_count; step++) { + logits_cmp cmp = compare_logits(ref + (size_t)step * (size_t)vocab, + cand + (size_t)step * (size_t)vocab, + vocab); + if (cmp.nonfinite != 0 || cmp.top1_saved != cmp.top1_restored || + cmp.top5_overlap < 5 || cmp.overlap < 16 || cmp.rms != 0.0f || cmp.max_abs != 0.0f) { + first_bad_step = step; + first_cmp = cmp; + break; + } + } + + printf("{\"mode\":\"compare-trace\",\"steps\":%d,\"vocab\":%d,\"first_bad_step\":%d", + token_count, vocab, first_bad_step); + if (first_bad_step >= 0) { + printf(",\"top1_ref\":%d,\"top1_cand\":%d,\"top5_overlap\":%d,\"top20_overlap\":%d,\"rms\":%.9g,\"max_abs\":%.9g,\"forced_token_before_step\":%d", + first_cmp.top1_saved, + first_cmp.top1_restored, + first_cmp.top5_overlap, + first_cmp.overlap, + first_cmp.rms, + first_cmp.max_abs, + first_bad_step > 0 ? tokens[first_bad_step - 1] : -1); + } + printf("}\n"); + + free(ref); + free(cand); + free(tokens); + return first_bad_step >= 0 ? 1 : 0; +} + +int main(int argc, char **argv) { + matrix_cfg cfg = { + .mode = NULL, + .model_path = NULL, + .prompt_file = "tests/long_context_story_prompt.txt", + .payload_path = NULL, + .logits_path = NULL, + .tokens_path = NULL, + .trace_path = NULL, + .ref_trace_path = NULL, + .ctx = 192, + .frontier = 129, + .greedy_steps = 8, + }; + parse_args(&cfg, argc, argv); + if (!cfg.mode || !cfg.model_path) usage(argv[0]); + if (!strcmp(cfg.mode, "save")) { + if (!cfg.payload_path || !cfg.logits_path || !cfg.tokens_path) usage(argv[0]); + return run_save(&cfg); + } + if (!strcmp(cfg.mode, "load-check")) { + if (!cfg.payload_path || !cfg.logits_path || !cfg.tokens_path) usage(argv[0]); + return run_load_check(&cfg); + } + if (!strcmp(cfg.mode, "trace-forced")) { + if (!cfg.payload_path || !cfg.tokens_path || !cfg.trace_path) usage(argv[0]); + return run_trace_forced(&cfg); + } + if (!strcmp(cfg.mode, "compare-trace")) { + if (!cfg.tokens_path || !cfg.trace_path || !cfg.ref_trace_path) usage(argv[0]); + return run_compare_trace(&cfg); + } + usage(argv[0]); + return 2; +} From 9c83dac7a087406f246369a94505d69220101ab3 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Wed, 3 Jun 2026 22:18:22 +0100 Subject: [PATCH 03/17] phase 2 complete --- Makefile | 12 +- PLAN.md | 195 ++--- artifacts/issue-304/compatibility-matrix.md | 7 + artifacts/issue-304/decision-log.md | 72 ++ artifacts/issue-304/logit-comparisons.md | 43 + artifacts/issue-304/perf-breakdown.md | 48 ++ artifacts/issue-304/research-notes.md | 50 +- artifacts/issue-304/runbook.md | 62 +- artifacts/issue-304/shard-metadata.md | 44 + tests/issue304_phase1_matrix | Bin 0 -> 944072 bytes tests/issue304_phase2_handoff | Bin 0 -> 959976 bytes tests/issue304_phase2_handoff.c | 899 ++++++++++++++++++++ 12 files changed, 1320 insertions(+), 112 deletions(-) create mode 100755 tests/issue304_phase1_matrix create mode 100755 tests/issue304_phase2_handoff create mode 100644 tests/issue304_phase2_handoff.c diff --git a/Makefile b/Makefile index 310e98f7e..3c3183b04 100644 --- a/Makefile +++ b/Makefile @@ -220,6 +220,16 @@ else $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase1_matrix.o $(CORE_OBJS) $(CUDA_LDLIBS) endif +tests/issue304_phase2_handoff.o: tests/issue304_phase2_handoff.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase2_handoff.c + +tests/issue304_phase2_handoff: tests/issue304_phase2_handoff.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase2_handoff.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase2_handoff.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + issue304-phase0-local: ds4 tests/issue304_phase0_local ./tests/issue304_phase0_local @@ -239,4 +249,4 @@ q4k-dot-test: tests/test_q4k_dot.c ./tests/test_q4k_dot clean: - rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o + rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o tests/issue304_phase2_handoff tests/issue304_phase2_handoff.o diff --git a/PLAN.md b/PLAN.md index 552bd0978..a44bcf5e4 100644 --- a/PLAN.md +++ b/PLAN.md @@ -38,17 +38,17 @@ Source: and its comment thread. ## Remaining unknowns -- Whether CUDA-produced KV/session payloads are backend-neutral and can be loaded by Metal without format or numeric mismatches. -- How to merge local-layer KV and remote-layer KV into one complete session state on the decode node before generation starts. -- Whether KV payload transfer should happen strictly after prefill or be pipelined chunk-by-chunk during prefill to avoid stalls. -- What API or file format changes are needed so a worker can export only its owned-layer KV/session slice and a coordinator can import it deterministically. +- Why `CUDA -> Metal` payloads restore the handoff logits exactly but still diverge after the first identical resumed decode step. +- Whether that resumed-decode drift lives in backend-specific KV interpretation, backend-specific decode-state evolution, or a smaller payload field that only matters after the next token is evaluated. +- How to let the coordinator participate in distributed prefill while still keeping a full local decode-capable engine resident without exhausting Metal memory budget. +- Whether the eventual handoff path should remain a merged `DSV4` checkpoint, move to an in-memory merged payload, or skip the merged payload entirely by streaming worker-owned KV shards back during prefill. ## Implementation direction -- Add a way for remote workers to serialize and stream owned-layer KV/session chunks back to the coordinator. -- Keep the transfer aligned with existing distributed prefill chunk boundaries so activation and KV movement can share the current pipeline structure. -- Validate cross-backend session portability first with a minimal save/load test between CUDA and Metal before committing to the full feature. -- Once portability is confirmed, add a coordinator-side resume path that reconstructs a complete local session and switches decode to the single-node fast path. +- Keep the merged `DSV4` handoff path as the current correctness boundary. Phase 2 validated that it can gather distributed shards, stage a payload, load locally, and recover the exact handoff checkpoint. +- Treat mixed-backend resumed-decode drift as the immediate blocker. Fix that before spending more time on transport redesign or pipelined KV return. +- Treat coordinator engine residency as a separate productization problem. Phase 2 proved the feature concept by releasing the distributed engine before local decode; the next residency work is about making that handoff practical in one user-visible workflow. +- Defer chunk-by-chunk KV return until after the resumed-decode correctness and residency story are both understood. At this point it is an optimization and UX improvement, not the first proof point. ## Relevant Code Module Map @@ -190,10 +190,10 @@ Source: and its comment thread. ## Most Relevant Files To Start In -- `ds4_distributed.c`: add or prototype KV-return/handoff orchestration here first. -- `ds4.c`: adapt snapshot/payload/session construction boundaries for the handoff. -- `ds4.h`: update public/internal API declarations only after the control flow is clear. -- `ds4_metal.m` and `ds4_cuda.cu`: inspect only if payload portability or restore correctness breaks across backends. +- `ds4_metal.m` and `ds4_cuda.cu`: Phase 2 points first at backend-specific resumed decode behavior, so these are now the highest-priority files. +- `ds4.c`: inspect payload restore, decode entry, and session state setup around `ds4_session_load_payload()` and resumed `ds4_session_eval()`. +- `tests/issue304_phase1_matrix.c` and `tests/issue304_phase2_handoff.c`: keep using these focused harnesses to narrow the first post-load divergence. +- `ds4_distributed.c`: return here after backend resume correctness is understood, or when implementing the later residency/transport optimization phases. ## Research And Implementation Plan @@ -206,7 +206,7 @@ This change should be run as an iterative research project, not as a straight fe - Keep implementation changes small until a validation artifact says the next abstraction is justified. - Capture every surprising result in this plan or a linked artifact before moving on. This includes failures, mismatched logits, transport timings, and rejected API options. - Measure correctness before throughput. A fast handoff is not useful until the resumed local session is demonstrably equivalent enough to continue generation. -- Treat model weight residency as a separate correctness and feasibility problem. Local decode needs full-layer weights available, while distributed prefill benefits from loading only a slice; switching engines or running two engines may be too expensive to be viable. +- Treat model weight residency as a separate correctness and feasibility problem. Phase 2 showed that releasing the distributed engine before local decode is enough to prove the feature concept, but not enough for a clean end-user workflow. ### Required research artifacts @@ -412,12 +412,53 @@ Exit gate: - The existing payload path can hand off distributed prefill state into a local-only decode session, or a specific blocker is captured with enough detail to choose the next implementation step. - If the path works only by running two engines or reloading an engine, it must not proceed directly to user-facing implementation; Phase 3 must choose a viable layer-residency design first. -### Phase 3: Engine layer residency and local decode feasibility +### Phase 3: Mixed-backend resumed decode root cause Goal: -- Why: the feature is not practical if it requires reloading the model or keeping two full model-weight copies in memory after prefill. -- What: choose a viable layer-residency design that lets the decode machine have full local generation capability while still participating efficiently in distributed prefill, and document the memory/performance tradeoff with evidence. +- Why: Phase 2 proved the merged handoff checkpoint is exact, but it also reproduced mixed-backend resumed-decode drift immediately after the first identical forced token. The next phase needs to turn that broad symptom into a concrete backend or restore-path bug. +- What: isolate why `CUDA -> Metal` diverges after the first resumed eval step even when the restored logits are identical and the sampled greedy path can stay stable. + +Expected artifacts: + +- Update `artifacts/issue-304/logit-comparisons.md` with finer-grained forced-token traces around the first divergent resumed step. +- Update `artifacts/issue-304/failure-cases.md` with every narrowed reproduction of post-load decode drift that remains rejected. +- Update `artifacts/issue-304/research-notes.md` with the first divergent state that can be localized reliably. +- Update `artifacts/issue-304/decision-log.md` if the evidence shows the bug is payload-ABI, backend-runtime, or decode-graph specific. + +Code touchpoints: + +- `tests/issue304_phase1_matrix.c` + - Extend the focused resume helper so it can compare finer-grained post-load state, not just logits and greedy tokens. +- `tests/issue304_phase2_handoff.c` + - Keep the distributed-prefill harness aligned with the smaller Phase 1 probes so the same divergence can be reproduced in both contexts. +- `ds4.c` + - `ds4_session_load_payload()`: restore path to inspect for any field that is sufficient for step-0 logits but insufficient for step-1 decode evolution. + - `ds4_session_eval()` and local decode entry path: first resumed decode step after load. +- `ds4_gpu.h` + - Shared tensor read/write and synchronization boundary if the first divergent state turns out to be visible only below the session payload layer. +- `ds4_metal.m` and `ds4_cuda.cu` + - Backend-specific decode-state assumptions, dtype conversion, raw/compressed KV interpretation, and graph state setup. + +Work items: + +- Extend `tests/issue304_phase1_matrix.c` so it can dump or compare finer-grained post-load state around the first resumed decode step. +- Compare `CUDA -> Metal` and `Metal -> Metal` immediately after one identical forced eval token, looking for the first tensor or cache-state difference that appears before logits drift becomes visible. +- Inspect `ds4_session_load_payload()` and resumed `ds4_session_eval()` in `ds4.c` for any state that is restored correctly enough for step-0 logits but not for step-1 decode evolution. +- Inspect `ds4_metal.m` and `ds4_cuda.cu` for backend-specific assumptions around raw KV rows, compressed KV rows, cache frontiers, dtype conversion, or decode-only graph state that may not be fully represented by the current payload ABI. + +Exit gate: + +- Either: + - `CUDA -> Metal` forced-token drift is eliminated for the existing Phase 1 and Phase 2 probes, or + - the first divergent restored state is localized well enough that the remaining work is a specific backend/runtime bug rather than a general handoff uncertainty. + +### Phase 4: Coordinator residency and workflow viability + +Goal: + +- Why: Phase 2 currently proves the concept by releasing the distributed engine and then opening a full local engine. That is enough for research, but not enough for a practical one-shot coordinator workflow. +- What: choose a viable residency design that lets the coordinator do distributed prefill and then local decode without requiring a research-only two-engine transition. Expected artifacts: @@ -448,35 +489,32 @@ Code touchpoints: - `ds4_distributed.c` - `dist_coordinator_build_route_plan()`: route ownership should stay independent from local weight residency if the final design decouples them. - `dist_coordinator_prefill_prompt_pipelined()` and `dist_coordinator_eval_span()`: must continue issuing only the coordinator-owned distributed slice during prefill. -- `ds4_cli.c` - - `--layers` parsing and help text if the meaning splits into "distributed route slice" and "model residency/load slice". -- `README.md` - - Distributed docs currently state that `--layers` controls which tensors are mapped; this must be updated if route ownership and residency are decoupled. -- Backend files: - - `ds4_gpu.h`, `ds4_metal.m`, and `ds4_cuda.cu` if the selected design requires dynamic mapping, lazy mapping, or remapping backend tensor views. +- `ds4_cli.c` and `README.md` + - User-visible meaning of `--layers` if route ownership and residency are decoupled. + - Current distributed docs state that `--layers` controls which tensors are mapped; update that assumption only if the chosen design actually decouples route ownership from residency. +- `ds4_gpu.h`, `ds4_metal.m`, and `ds4_cuda.cu` + - Revisit these if the residency design requires dynamic mapping, lazy mapping, or remapping backend tensor views. Candidate designs to analyze: - Decouple route ownership from weight residency: - Keep `--layers` as the distributed route slice, but allow the coordinator to map full local decode weights at startup. - During distributed prefill, call `ds4_session_eval_layer_slice()` only for the coordinator route slice even though more weights are resident. - - After KV handoff, continue local decode in the same engine/session shape if full-layer KV has been loaded. - Full-resident coordinator with sliced distributed execution: - Load the full model once on the coordinator, but still advertise/execute only the coordinator-owned distributed layer range for prefill. - - This avoids reloads and two engines, but may reduce the memory savings that made distributed prefill useful. - Lazy or expandable residency: - Start with route-slice mapping, then expand to full mapping before local decode without closing the engine. - - This is only viable if backend model map spans and cached/preloaded tensors can be expanded safely and fast enough. + - Only keep this path if backend model map spans and cached/preloaded tensors can be expanded safely and fast enough. - Dual session over one engine: - Use one full-resident engine with separate distributed-prefill and local-decode sessions. - This may avoid duplicate weights but still duplicates KV/session graph memory; measure before selecting. - Two engines or reload: - - Keep only as a correctness harness or fallback diagnostic. Assume this is not the final design unless memory measurements prove otherwise. + - Keep only as a correctness harness or fallback diagnostic, not the final workflow unless the measurements force it. Work items: - Trace exactly how distributed `--layers` becomes loaded model spans today. -- Measure memory for route-slice engine, full engine, dual-session-over-one-engine, and two-engine proof harness where feasible. +- Measure memory for route-slice engine, full engine, dual-session-over-one-engine, and the current two-engine proof harness where feasible. - Verify whether a full-resident coordinator can still execute only its distributed slice during prefill by using the existing layer-slice APIs. - Determine whether session graph allocation assumes only a subset of layers is bound, or whether it can safely hold KV for all layers when the engine has full weights. - Determine whether output head residency is required on the coordinator for local decode and how `load_output_optional` interacts with that. @@ -486,56 +524,45 @@ Exit gate: - A final implementation path exists that does not require loading/unloading the whole engine at handoff time and does not require two full model-weight copies in memory. - The chosen strategy is captured in `artifacts/issue-304/engine-residency.md` and `artifacts/issue-304/decision-log.md`. -- If no viable strategy is found, stop before Phase 4 and record the smallest code experiment needed to test dynamic/expanded residency. +- If no viable strategy is found, stop before advancing and record the smallest code experiment needed to test dynamic or expanded residency. -### Phase 4: Choose the public/internal API shape +### Phase 5: Choose API shape and implement the handoff path Goal: -- Why: API shape should follow validated behavior and residency constraints, not a speculative design that may encode the wrong abstraction. -- What: choose the smallest public/internal API that supports the proven handoff path, records rejected alternatives, and keeps room for later in-memory, incremental, or topology-flexible improvements. +- Why: once resumed-decode correctness and residency constraints are understood, the next step is turning the research-only path into a real session/CLI/server workflow. +- What: choose the smallest API shape that matches the validated behavior, implement it, and verify that distributed prefill can transition to local-only decode without manual harness glue. Expected artifacts: -- Update `artifacts/issue-304/decision-log.md` with the selected API shape, alternatives rejected, and evidence from Phase 2. -- Update `artifacts/issue-304/runbook.md` with the expected developer/operator workflow for the selected API. -- Update `artifacts/issue-304/engine-residency.md` if the chosen API requires new residency semantics or new CLI options. -- Update `artifacts/issue-304/research-notes.md` with the API-shape conclusion and the reasoning that selected it over the other candidates. -- Update this `PLAN.md` if the chosen path changes later phases. +- Update `artifacts/issue-304/decision-log.md` with the selected API shape, alternatives rejected, and evidence from Phases 2-4. +- Update `artifacts/issue-304/runbook.md` with the expected developer/operator workflow for the selected path. +- Update `artifacts/issue-304/logit-comparisons.md` and `artifacts/issue-304/perf-breakdown.md` with post-implementation correctness and timing. +- Update `artifacts/issue-304/failure-cases.md` with user-visible negative cases and observed diagnostics. +- Update `artifacts/issue-304/research-notes.md` with implementation-phase findings and deltas from the earlier hypotheses. +- Update `README.md` only once the workflow is stable enough to describe honestly. Code touchpoints: - `ds4.h` - - Public/internal declarations if a new session handoff helper is needed. - - `ds4_distributed_options` if the feature becomes an option rather than an explicit helper call. + - New helper declaration or option fields if the feature is exposed beyond the research harness. - `ds4.c` - - Session-level implementation if handoff is expressed as a normal session operation. - - Snapshot/payload helpers if in-memory handoff is chosen. + - Core handoff flow and local session creation/load boundaries. - `ds4_distributed.h` - - Distributed-specific declarations if the API remains internal to coordinator sessions. + - Distributed-specific declarations if the chosen API remains internal to coordinator sessions. - `ds4_distributed.c` - - Distributed gather/stage implementation and any coordinator state transition. + - Coordinator gather/handoff path and failure diagnostics for stale/missing shards. - `ds4_cli.c` and `ds4_server.c` - - User-visible wiring only after the core API is validated. - -Other entry points: - -- CLI flags and documented workflow. -- Server request/session persistence behavior. -- Existing `ds4_session_save_payload()` / `ds4_session_load_payload()` API if handoff remains a composition of existing primitives. -- Existing `ds4_session_stage_payload()` if the first API is file-backed. - -Work items: - -- Decide whether the first implementation should be whole-payload, in-memory payload, or explicit shard merge. -- Record the decision and evidence before adding user-facing wiring. -- Update the phase sequence if the chosen API invalidates any later assumptions. + - User-visible wiring only after the core session path works. +- `ds4_kvstore.c` + - Only if the selected path routes through persisted/staged KV payloads. +- `tests/ds4_test.c` + - Regression coverage for local handoff behavior where feasible. Likely options: - Whole-payload handoff: - expose a helper that saves/stages a distributed session payload and loads it into a provided local session. - - This aligns with the existing `DSV4` topology-neutral contract. - In-memory payload handoff: - extend distributed sessions so `ds4_session_save_snapshot()` or a new memory-backed payload helper can gather remote shards. - This avoids temp files, but requires solving the current distributed snapshot restriction. @@ -546,63 +573,17 @@ Likely options: Decision criteria: - Correctness equivalence after resume. -- Compatibility with the chosen single-engine residency strategy. +- Compatibility with the chosen residency strategy. - Operator complexity in CLI/server workflows. - Ability to support cross-backend handoff. - Measured handoff overhead relative to prefill speedup. - Amount of new protocol surface in `ds4_distributed.c`. -Exit gate: - -- `artifacts/issue-304/decision-log.md` records the chosen API shape and rejected alternatives with evidence. - -### Phase 5: Implement local-generation handoff - -Goal: - -- Why: convert the proven research path into a real workflow that users or higher-level server/CLI code can execute without manual payload surgery. -- What: implement the selected handoff mechanism, wire it through the appropriate session/CLI/server entry points, and verify that distributed prefill can transition to local-only decode with correctness and performance artifacts. - -Expected artifacts: - -- Update `artifacts/issue-304/runbook.md` with the user-visible invocation. -- Update `artifacts/issue-304/logit-comparisons.md` with post-implementation correctness results. -- Update `artifacts/issue-304/perf-breakdown.md` with prefill, handoff, load, and local decode timing from the implemented path. -- Update `artifacts/issue-304/failure-cases.md` with negative tests and observed diagnostics. -- Update `artifacts/issue-304/research-notes.md` with implementation-phase findings and any deltas from the earlier hypotheses. -- Update `README.md` only once the workflow is stable enough to describe to users. - -Code touchpoints: - -- `ds4.h` - - New helper declaration or option fields, if selected in Phase 4. -- `ds4.c` - - Core handoff flow. - - Local session creation/load boundaries. - - Any changes to distributed snapshot restriction if memory handoff is selected. -- `ds4_distributed.c` - - Coordinator gather/handoff path. - - Route validation and worker shard fetch. - - Failure diagnostics for stale/missing shards. -- `ds4_cli.c` - - CLI mode/flag for "distributed prefill, local decode" if the feature is exposed in CLI. -- `ds4_server.c` - - Server/session workflow if local decode handoff must work for served sessions. -- `ds4_kvstore.c` - - Only if the feature routes through persisted/staged KV payloads. -- `tests/ds4_test.c` - - Regression coverage for local handoff behavior where feasible. - -Other entry points: - -- CLI command line. -- Server session persistence/load path. -- KV store files if the handoff uses persisted payloads. -- Manual distributed coordinator/worker runbook for cross-host validation. - Work items: -- Add the minimal session-level handoff mechanism selected in Phase 4. +- Decide whether the first implementation should be whole-payload, in-memory payload, or explicit shard merge. +- Record that decision and evidence before adding user-facing wiring. +- Add the minimal session-level handoff mechanism selected from that decision. - Keep the distributed prefill session and local decode session distinct unless evidence shows same-session mutation is safer. - Ensure the local session receives full token timeline, logits, raw SWA KV rows in logical order, compressed KV rows, compressor frontier state, and indexer state. - Add CLI/server wiring only after the core session path works. diff --git a/artifacts/issue-304/compatibility-matrix.md b/artifacts/issue-304/compatibility-matrix.md index 772625043..463748293 100644 --- a/artifacts/issue-304/compatibility-matrix.md +++ b/artifacts/issue-304/compatibility-matrix.md @@ -16,6 +16,12 @@ | 2026-06-03 | save on local `9952733bbc75eedfa1308cfed71b8e2694db978b`, load on `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` DGX | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | Metal | CUDA | Pass | `tests/issue304_phase1_matrix` at `ctx=192`, `frontier=129`: top1 matched, top5 overlap `5/5`, top20 overlap `20/20`, `rms=0`, greedy continuation matched for 8 tokens. | | 2026-06-03 | save on `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` DGX, load on local `9952733bbc75eedfa1308cfed71b8e2694db978b` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | CUDA | Metal | Fail | `tests/issue304_phase1_matrix` at `ctx=192`, `frontier=129`: restore-point logits matched exactly (`top1`, top5/top20, `rms=0`, `max_abs=0`), but 8-token greedy continuation diverged at step `2` with saved token `5655` vs restored token `305`. | +## Phase 2: Distributed prefill to local decode handoff + +| Date | Commit | Model | Route | Handoff path | Result | Notes | +| --- | --- | --- | --- | --- | --- | --- | +| 2026-06-03 | local `116e35881679c99cbe33454f95d2b4c96448761b`, DGX worker rebuilt from synced `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` tree with local source updates | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output` | distributed prefill on Metal/CUDA route -> merged `DSV4` stage on Metal -> fresh local Metal load -> local decode comparison | Mixed result | `tests/issue304_phase2_handoff`: handoff logits matched exactly and 16-token greedy continuation matched exactly; forced-token trace still diverged at step `1` after the first identical post-load eval token (`5`), with `rms=0.0802887231`, `max_abs=0.507860184`. | + ## Representative `DSVL` shard smoke | Date | Commit | Backend | Layer | Result | Notes | @@ -30,3 +36,4 @@ - Every planned Phase 1 backend pair has now been exercised at least once. - The only failing cell is `CUDA -> Metal`, and the current failure is narrower than a restore-point logit mismatch: the loaded Metal session starts from identical logits but diverges during subsequent greedy decode. - Forced-token follow-up on the same failing cell shows that logits already diverge after the first identical post-load eval token, so the failure is not explained by token-selection branching alone. +- Phase 2 now confirms the same pattern after real distributed prefill: exact handoff checkpoint, matching greedy continuation over the sampled window, but first-step forced-trace drift on resumed Metal decode. diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index 8895e9eae..abfdf14d0 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -29,3 +29,75 @@ Why this changes the notes: - distributed generation tolerates worker `ctx >= coordinator ctx` - merged shard save requires exact layout equality, so `ctx` must match across participants - The Phase 2 `DSV4`-first path remains viable if the runbook pins matching `--ctx` on all distributed participants. + +## 2026-06-03: Implement a dedicated Phase 2 handoff harness before changing core transport + +Decision: + +- Validate Phase 2 with a dedicated harness built on existing APIs before attempting any distributed transport or payload-format changes. +- Keep the first Phase 2 proof at the `DSV4` handoff boundary: + - distributed prefill, + - merged payload stage, + - fresh local full-session load, + - handoff logits comparison, + - greedy continuation comparison, + - and forced-token trace comparison. + +Evidence: + +- Phase 0 already proved that immediate merged `DSV4` staging works on the mixed Metal/CUDA route when `ctx` matches. +- Phase 1 already proved that whole-payload local resume is a valid correctness boundary and that `CUDA -> Metal` drift appears after restore during subsequent decode evolution. +- The existing test and helper surface already exposed the needed primitives: + - `tests/issue304_phase0_dgx` for distributed route, prefill, and stage + - `tests/issue304_phase1_matrix` for logit comparison and forced-token trace logic +- A new local helper, `tests/issue304_phase2_handoff`, now builds successfully with: + - `make tests/issue304_phase2_handoff` + +Why this changes the work: + +- It lowers Phase 2 ambiguity without committing to chunked KV return or in-memory payload APIs. +- It makes the next failure mode attributable: + - if staging fails, it is still a distributed gather/layout problem + - if load fails, it is a local payload compatibility problem + - if handoff logits match but forced trace drifts, it is post-load decode evolution, not a bad handoff point + +Follow-up: + +- Run the helper on the DGX/Mac topology and record the resulting metrics before deciding whether Phase 3 needs engine-residency work only or whether Phase 2 still hides a Metal/CUDA payload-resume defect. + +## 2026-06-03: Phase 2 confirms exact handoff but not exact resumed decode evolution + +Decision: + +- Treat Phase 2 as complete. +- Do not spend more Phase 2 effort on distributed KV gather or merged payload staging. +- Carry the remaining defect forward as a mixed-backend resumed-decode evolution problem. + +Evidence: + +- `tests/issue304_phase2_handoff` on the authoritative DGX/Mac topology produced: + - successful distributed prefill + - successful merged `DSV4` stage + - successful fresh local Metal load + - exact handoff logits (`top1`, `top5`, `top20`, `rms=0`, `max_abs=0`) + - exact 16-token greedy continuation match + - but forced-token trace divergence at first bad step `1` + - forced token before bad step: `5` + - `rms=0.0802887231` + - `max_abs=0.507860184` +- Throughput also matched the intended motivation: + - distributed decode `16.28 tok/s` + - local decode after handoff `30.32 tok/s` + +Why this changes the next steps: + +- The current implementation direction is validated at the feature level: + - distributed prefill can hand off to materially faster local decode through the existing merged payload path +- The remaining correctness issue is narrower than “handoff is broken”: + - the checkpoint is exact + - the sampled greedy path stayed stable + - the drift only appears in full-logit forced comparison after resumed eval begins + +Follow-up: + +- Phase 3 and follow-on debugging should focus on backend-specific post-load decode-state evolution, not on redesigning the merged `DSV4` handoff boundary. diff --git a/artifacts/issue-304/logit-comparisons.md b/artifacts/issue-304/logit-comparisons.md index de85c410c..b09e7cc6e 100644 --- a/artifacts/issue-304/logit-comparisons.md +++ b/artifacts/issue-304/logit-comparisons.md @@ -74,6 +74,49 @@ To separate token-selection drift from post-load decode evolution, the same `CUD - backend-specific interpretation of restored state used by the next decode step, or - backend-specific decode-state evolution from the same restored state. +## Phase 2 distributed-prefill handoff + +The new `tests/issue304_phase2_handoff` helper compared: + +1. distributed coordinator session after mixed Metal/CUDA prefill +2. fresh local Metal session after merged `DSV4` load +3. distributed vs local greedy continuation +4. distributed-reference forced-token trace vs local resumed forced-token trace + +### Summary + +- Route: `local 0:21 -> 10.77.0.2:43045 Q2 22:output` +- Prompt: `README.md` +- Prompt tokens: `14,318` +- Result: + - handoff logits matched exactly + - 16-token greedy continuation matched exactly + - forced-token trace diverged at the first post-load eval step + +### Handoff result + +| Compared states | Top-1 match | Top-5 overlap | Top-20 overlap | RMS drift | Max abs drift | Non-finite | +| --- | --- | ---: | ---: | ---: | ---: | ---: | +| distributed handoff vs local resumed handoff | Yes | 5/5 | 20/20 | 0 | 0 | 0 | + +### Greedy continuation + +| Compared traces | Steps checked | Result | +| --- | ---: | --- | +| distributed decode vs local resumed decode | 16 | Exact match | + +### Forced-token trace + +| Compared traces | First bad step | Forced token before bad step | Top-1 at bad step | Top-5 overlap | Top-20 overlap | RMS drift | Max abs drift | +| --- | ---: | ---: | --- | ---: | ---: | ---: | ---: | +| distributed reference vs local resumed Metal | 1 | `5` | same (`420`) | 5/5 | 20/20 | 0.0802887231 | 0.507860184 | + +### Interpretation + +- Phase 2 removes staging and initial restore correctness as leading suspects. +- The mixed-backend drift still shows up only after resumed decode evolution begins. +- The fact that greedy continuation matched for 16 tokens while forced-trace drift still appeared means the drift is currently too small to perturb top-token choice in this sampled window, but it is still a real backend-resume mismatch. + ## Baseline surrounding checks These were rerun after the Phase 1 changes to confirm the new harness did not perturb existing local correctness surfaces. diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md index 8071abe67..9f2cabe95 100644 --- a/artifacts/issue-304/perf-breakdown.md +++ b/artifacts/issue-304/perf-breakdown.md @@ -72,3 +72,51 @@ Notes: - merged `DSV4` stage failed because shard headers require exact layout equality - Reproduced earlier failure signature: - `distributed KV shards use different layouts: field=ctx local=16384 remote=32768 remote_layers=22:42` + +## Phase 2 handoff harness + +### Authoritative DGX + Mac result + +Phase 2 timing collection now has a dedicated tool: + +```sh +make tests/issue304_phase2_handoff +``` + +Authoritative command pair: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./ds4 -m /home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --coordinator 10.77.0.1 1234' +./tests/issue304_phase2_handoff --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --listen-host 10.77.0.1 --listen-port 1234 --prompt-file README.md --ctx 16384 --gen-tokens 16 --forced-steps 8 --prefill-chunk 256 --activation-bits 32 --coordinator-layers 0:21 --worker-layers 22:output --payload-out /private/tmp/issue304-phase2-readme.dsv4 +``` + +Observed result: + +| Item | Result | +| --- | --- | +| Tool build | Pass | +| Prompt file | `README.md` | +| Prompt tokens | 14,318 | +| Route summary | `local 0:21 -> 10.77.0.2:43045 Q2 22:output` | +| Distributed prefill | `38.183 s`, `374.99 tok/s` | +| Merged payload stage | `0.380 s` | +| Merged payload bytes | `221,006,660` | +| Local payload load | `0.028 s` | +| Distributed decode | `0.983 s` for 16 tokens, `16.28 tok/s` | +| Local decode after handoff | `0.528 s` for 16 tokens, `30.32 tok/s` | +| Handoff logits | exact match | +| Greedy continuation | exact match for 16 tokens | +| Forced-trace result | first bad step `1`, `rms=0.0802887231`, `max_abs=0.507860184` | + +Planned fields from `tests/issue304_phase2_handoff`: + +- prompt file +- prompt token count +- route summary and output owner +- distributed prefill seconds / t/s +- merged payload stage seconds / bytes +- local payload load seconds +- distributed greedy decode seconds / t/s +- local greedy decode seconds / t/s +- handoff logit comparison metrics +- forced-trace first bad step and drift metrics diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index bd0ecbed0..822963d2c 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -8,7 +8,7 @@ This file tracks phase-wise findings for the staged investigation in `PLAN.md`. | --- | --- | --- | | Phase 0 | Complete | The DGX/Mac baseline ran end-to-end, and the earlier merged-`DSV4` stage failure was narrowed to a worker/coordinator `ctx` mismatch rather than a backend or route-format incompatibility. | | Phase 1 | Complete | The payload resume matrix is now filled: `Metal -> Metal`, `CUDA -> CUDA`, and `Metal -> CUDA` passed, while `CUDA -> Metal` preserved restore-point logits but diverged during subsequent greedy decode. | -| Phase 2 | Not started | The merged `DSV4` save path is still viable once distributed participants use the same session context. | +| Phase 2 | Complete | Distributed prefill -> merged `DSV4` -> fresh local Metal load now validates end-to-end on the DGX/Mac route. Handoff logits and 16-token greedy continuation matched, but forced-token logits still diverged at the first post-load eval step. | | Phase 3 | Not started | Engine residency and same-process local decode feasibility are still open. | | Later optimization phases | Not started | No work yet on pipelined KV return or user-facing workflow. | @@ -169,7 +169,7 @@ That means Phase 2 can use merged `DSV4` handoff as the first end-to-end correct ### Current status -Not run yet. +Complete. The dedicated handoff harness ran successfully on the DGX/Mac route after its local-decode step was changed to release the distributed engine before opening the full local one. ### Current working hypothesis @@ -185,6 +185,52 @@ The intended correctness check was: - Keep worker and coordinator session context sizes identical before treating any merged-save failure as a true shard-format bug. +### What was completed + +- Added `tests/issue304_phase2_handoff`. +- Built the helper locally and on the DGX host after syncing the changed core files needed by the newer route-summary API surface. +- Ran the authoritative Mac coordinator + DGX worker topology with matching `ctx=16384`. +- Captured a staged merged payload, local load, greedy continuation comparison, forced-token trace comparison, and throughput split. + +### Findings + +1. The `DSV4`-first Phase 2 handoff path works end-to-end on the mixed Metal/CUDA route. + - Distributed prefill completed on the `README.md` prompt. + - Immediate merged stage succeeded. + - Fresh local Metal session load succeeded from the merged payload. + +2. The handoff checkpoint itself is exact enough to rule out a bad merged-save boundary. + - Handoff logits matched exactly: + - top1 match + - top5 overlap `5/5` + - top20 overlap `20/20` + - `rms=0` + - `max_abs=0` + - nonfinite `0` + +3. Greedy continuation from the resumed local session matched the distributed reference for the sampled window. + - The helper compared `16` greedy tokens. + - Result: exact match for all `16` steps. + +4. The remaining defect is still post-load decode evolution, not stage/load correctness. + - Forced-token trace still diverged at the first identical post-load eval step: + - first bad step: `1` + - forced token before bad step: `5` + - top1 still matched (`420`) + - top5 overlap `5/5` + - top20 overlap `20/20` + - `rms=0.0802887231` + - `max_abs=0.507860184` + +5. The expected throughput split was observed. + - Distributed prefill: `38.183 s`, `374.99 tok/s` + - Distributed decode: `16.28 tok/s` + - Local decode after handoff: `30.32 tok/s` + +### Implication + +Phase 2 is no longer blocked on distributed gather, payload staging, or initial local resume. The feature concept is viable through the existing merged `DSV4` path. The remaining technical problem is the already-familiar mixed-backend post-load decode drift, now reproduced after a real distributed prefill rather than only the smaller Phase 1 payload matrix case. + ### Open question carried forward - `CUDA -> Metal` restores the immediate logits exactly, but diverges after the first identical forced post-load eval token. diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md index 5800bf26b..445dc6596 100644 --- a/artifacts/issue-304/runbook.md +++ b/artifacts/issue-304/runbook.md @@ -80,8 +80,8 @@ Observed requirements and results: ## Environment - Date: 2026-06-03 15:54:57Z -- Local repo commit: `9952733bbc75eedfa1308cfed71b8e2694db978b` -- DGX worker repo commit: `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` +- Local repo commit: `116e35881679c99cbe33454f95d2b4c96448761b` +- DGX worker repo commit: `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` plus synced local changes to `ds4.c`, `ds4.h`, `ds4_distributed.c`, `ds4_distributed.h`, `Makefile`, and `tests/issue304_phase2_handoff.c` - Coordinator host: Apple M5 Max / Metal - Worker host: NVIDIA GB10 / CUDA - Model: `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` @@ -97,6 +97,12 @@ Observed requirements and results: make ds4_test ``` +### Phase 2 build + +```sh +make tests/issue304_phase2_handoff +``` + ### Phase 1 focused path ```sh @@ -136,6 +142,58 @@ ssh dgx-direct 'cd ~/ds4 && ./tests/issue304_phase1_matrix --mode load-check --m make test ``` +### Phase 2 DGX/Mac handoff validation + +Start the DGX worker with the same `ctx` as the coordinator: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./ds4 -m /home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --coordinator 10.77.0.1 1234' +``` + +Run the local coordinator handoff helper on the Mac: + +```sh +./tests/issue304_phase2_handoff --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --listen-host 10.77.0.1 --listen-port 1234 --prompt-file README.md --ctx 16384 --gen-tokens 16 --forced-steps 8 --prefill-chunk 256 --activation-bits 32 --coordinator-layers 0:21 --worker-layers 22:output +``` + +Optional: retain the merged payload for post-run inspection: + +```sh +./tests/issue304_phase2_handoff --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --listen-host 10.77.0.1 --listen-port 1234 --prompt-file README.md --ctx 16384 --gen-tokens 16 --forced-steps 8 --prefill-chunk 256 --activation-bits 32 --coordinator-layers 0:21 --worker-layers 22:output --payload-out /private/tmp/issue304-phase2-readme.dsv4 +``` + +What the helper records: + +- route summary and output owner +- prompt token count and token hash +- merged payload bytes and parsed `DSV4` header +- distributed prefill timing +- merged payload stage timing +- local payload load timing +- distributed vs local greedy decode timing +- handoff-point logit comparison +- greedy continuation mismatch step, if any +- forced-token trace first bad step, if any + +Observed authoritative Phase 2 result: + +- Route summary: `local 0:21 -> 10.77.0.2:43045 Q2 22:output` +- Prompt tokens: `14,318` +- Prefill: `38.182716 s`, `374.99 tok/s` +- Stage: `0.380082 s` +- Payload bytes: `221,006,660` +- Local load: `0.028093 s` +- Distributed decode: `16.28 tok/s` +- Local decode: `30.32 tok/s` +- Handoff logits: exact match +- Greedy continuation: exact match for `16` tokens +- Forced trace: + - first bad step: `1` + - forced token before bad step: `5` + - top1 remained `420` + - `rms=0.0802887231` + - `max_abs=0.507860184` + ## Runtime knobs used by `--local-payload-resume` - `DS4_METAL_PREFILL_CHUNK=4096` diff --git a/artifacts/issue-304/shard-metadata.md b/artifacts/issue-304/shard-metadata.md index bdcaf4ad3..0c9875958 100644 --- a/artifacts/issue-304/shard-metadata.md +++ b/artifacts/issue-304/shard-metadata.md @@ -93,3 +93,47 @@ Single-layer shard round trips captured from `./ds4_test --local-payload-resume` - These shard values come from the stable same-backend Metal run only. - The single-layer smoke validates `save -> load -> save` byte identity for the sampled layers. - The DGX/Mac mixed Metal/CUDA Phase 0 run did produce a merged `DSV4` header once the worker `ctx` matched the coordinator `ctx`. + +## Phase 2 harness metadata contract + +The new `tests/issue304_phase2_handoff` helper is intended to emit the following route and handoff metadata once the DGX/Mac run is executed: + +| Field | Intended source | +| --- | --- | +| route hops | `ds4_session_distributed_route_summary()` | +| route summary | `ds4_session_distributed_route_summary()` | +| output owner | `ds4_session_distributed_route_summary()` | +| prompt tokens | encoded chat prompt length on the coordinator | +| payload bytes | merged staged `DSV4` file size | +| token count at handoff checkpoint | `ds4_session_tokens()` on the distributed session | +| token hash at handoff checkpoint | helper-side token hash over the distributed timeline | +| `ctx_size`, `prefill_cap`, `raw_cap`, `raw_window`, `comp_cap`, `saved_tokens`, `n_layer`, `head_dim`, `indexer_head_dim`, `vocab`, `raw_live` | parsed staged `DSV4` header | + +Current status: + +- helper implementation exists locally +- helper build passed locally and on the DGX host after syncing the required core files + +### Phase 2 authoritative DGX/Mac row + +| Field | Value | +| --- | --- | +| route hops | 1 | +| route summary | `local 0:21 -> 10.77.0.2:43045 Q2 22:output` | +| output owner | worker | +| prompt tokens | 14,318 | +| payload bytes | 221,006,660 | +| token count at handoff checkpoint | 14,334 | +| token hash at handoff checkpoint | `0xe9f870851b231ebb` | +| `ctx_size` | 16,384 | +| `prefill_cap` | 4,096 | +| `raw_cap` | 4,352 | +| `raw_window` | 128 | +| `comp_cap` | 4,098 | +| `saved_tokens` | 14,318 | +| `n_layer` | 43 | +| `head_dim` | 512 | +| `indexer_head_dim` | 128 | +| `vocab` | 129,280 | +| `raw_live` | 128 | +| note | `token_count` and `token_hash` were captured after the 16-token distributed reference continuation; the serialized payload itself still reflects the immediate post-prefill checkpoint with `saved_tokens=14,318`. | diff --git a/tests/issue304_phase1_matrix b/tests/issue304_phase1_matrix new file mode 100755 index 0000000000000000000000000000000000000000..0aef66c996d84262f77807e61bcd5dd39cb66c9f GIT binary patch literal 944072 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

slkvqV@MaEm{cvw%4tu&^=&ls;zt3)RS356c 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 H?|u0{KiU6P literal 0 HcmV?d00001 diff --git a/tests/issue304_phase2_handoff b/tests/issue304_phase2_handoff new file mode 100755 index 0000000000000000000000000000000000000000..85778f335b1cedbf747d2952b2460af01a0c8840 GIT binary patch literal 959976 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%0AE){*Pp_ABTdt8#{jmh;OP!<#{WSf! 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 z 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

e=^b1zi`Pvs271Bc;;!Cc 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�im-9u>s{!&YIwO;5PGTw;f;VG{IH8V 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

$q6os)I@JJKD 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 b*86YR!O#)O^!U97f!b literal 0 HcmV?d00001 diff --git a/tests/issue304_phase2_handoff.c b/tests/issue304_phase2_handoff.c new file mode 100644 index 000000000..261d017ee --- /dev/null +++ b/tests/issue304_phase2_handoff.c @@ -0,0 +1,899 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + const char *model_path; + const char *prompt_file; + const char *system_prompt; + const char *listen_host; + const char *coordinator_layers; + const char *worker_layers; + const char *payload_out; + int listen_port; + int ctx_size; + int gen_tokens; + int forced_steps; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + bool debug; +} handoff_cfg; + +typedef struct { + uint32_t ctx_size; + uint32_t prefill_cap; + uint32_t raw_cap; + uint32_t raw_window; + uint32_t comp_cap; + uint32_t saved_tokens; + uint32_t n_layer; + uint32_t head_dim; + uint32_t indexer_head_dim; + uint32_t vocab; + uint32_t raw_live; +} dsv4_header; + +typedef struct { + int top1_saved; + int top1_restored; + int overlap; + int top5_overlap; + int nonfinite; + float rms; + float max_abs; +} logits_cmp; + +typedef struct { + int *tokens; + int token_count; + float *trace; + int trace_steps; + double elapsed_sec; +} token_trace_run; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die_usage(const char *argv0) { + fprintf(stderr, + "usage: %s --model FILE --listen-host IPV4 --listen-port N " + "[--prompt-file FILE] [--system TEXT] [--ctx N] [--gen-tokens N] " + "[--forced-steps N] [--prefill-chunk N] [--prefill-window N] " + "[--activation-bits N] [--coordinator-layers A:B|A:output] " + "[--worker-layers A:B|A:output] [--payload-out FILE] [--no-debug]\n", + argv0); + exit(2); +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase2-handoff: %s\n", msg); + exit(1); +} + +static void die_errno(const char *msg) { + fprintf(stderr, "issue304-phase2-handoff: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (len != 0 && fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static void u64_to_halves(uint64_t v, uint32_t *hi, uint32_t *lo) { + *hi = (uint32_t)(v >> 32); + *lo = (uint32_t)v; +} + +static uint64_t token_hash_update(uint64_t h, int token) { + uint32_t t = (uint32_t)token; + for (int i = 0; i < 4; i++) { + h ^= (uint64_t)((t >> (i * 8)) & 0xffu); + h *= 1099511628211ull; + } + return h; +} + +static uint64_t token_hash_prefix(const ds4_tokens *tokens) { + uint64_t h = 1469598103934665603ull; + for (int i = 0; i < tokens->len; i++) h = token_hash_update(h, tokens->v[i]); + return h; +} + +static bool read_u32_le(FILE *fp, uint32_t *out) { + uint8_t buf[4]; + if (fread(buf, 1, sizeof(buf), fp) != sizeof(buf)) return false; + *out = (uint32_t)buf[0] | + ((uint32_t)buf[1] << 8) | + ((uint32_t)buf[2] << 16) | + ((uint32_t)buf[3] << 24); + return true; +} + +static bool parse_dsv4_header(const char *path, dsv4_header *out) { + memset(out, 0, sizeof(*out)); + FILE *fp = fopen(path, "rb"); + if (!fp) return false; + + uint32_t h[DS4_SESSION_PAYLOAD_U32_FIELDS]; + for (uint32_t i = 0; i < DS4_SESSION_PAYLOAD_U32_FIELDS; i++) { + if (!read_u32_le(fp, &h[i])) { + fclose(fp); + return false; + } + } + fclose(fp); + + if (h[0] != DS4_SESSION_PAYLOAD_MAGIC || h[1] != DS4_SESSION_PAYLOAD_VERSION) { + return false; + } + + out->ctx_size = h[2]; + out->prefill_cap = h[3]; + out->raw_cap = h[4]; + out->raw_window = h[5]; + out->comp_cap = h[6]; + out->saved_tokens = h[7]; + out->n_layer = h[8]; + out->head_dim = h[9]; + out->indexer_head_dim = h[10]; + out->vocab = h[11]; + out->raw_live = h[12]; + return true; +} + +static int wait_route(ds4_session *session, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase2-handoff: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase2-handoff: timed out waiting for route\n"); + return 0; +} + +static bool parse_layer_spec(const char *spec, ds4_distributed_layers *out) { + if (!spec || !out) return false; + const char *colon = strchr(spec, ':'); + if (!colon || colon == spec || colon[1] == '\0') return false; + + errno = 0; + char *end = NULL; + unsigned long start = strtoul(spec, &end, 10); + if (errno != 0 || end != colon || start > UINT32_MAX) return false; + + ds4_distributed_layers layers = {0}; + layers.start = (uint32_t)start; + layers.set = true; + if (strcmp(colon + 1, "output") == 0) { + layers.has_output = true; + layers.end = 0; + } else { + errno = 0; + unsigned long layer_end = strtoul(colon + 1, &end, 10); + if (errno != 0 || *end != '\0' || layer_end > UINT32_MAX) return false; + layers.end = (uint32_t)layer_end; + } + *out = layers; + return true; +} + +static void logits_topk(const float *logits, int n, int *out, int k) { + for (int i = 0; i < k; i++) out[i] = -1; + for (int i = 0; i < n; i++) { + const float v = logits[i]; + for (int j = 0; j < k; j++) { + if (out[j] < 0 || v > logits[out[j]]) { + for (int t = k - 1; t > j; t--) out[t] = out[t - 1]; + out[j] = i; + break; + } + } + } +} + +static bool topk_contains(const int *top, int k, int id) { + for (int i = 0; i < k; i++) { + if (top[i] == id) return true; + } + return false; +} + +static logits_cmp compare_logits(const float *saved, const float *restored, int vocab) { + int saved_top[20]; + int restored_top[20]; + logits_topk(saved, vocab, saved_top, 20); + logits_topk(restored, vocab, restored_top, 20); + + int overlap = 0; + int top5_overlap = 0; + for (int i = 0; i < 20; i++) { + if (saved_top[i] >= 0 && topk_contains(restored_top, 20, saved_top[i])) overlap++; + if (i < 5 && saved_top[i] >= 0 && topk_contains(restored_top, 5, saved_top[i])) top5_overlap++; + } + + int nonfinite = 0; + double sumsq = 0.0; + float max_abs = 0.0f; + for (int i = 0; i < vocab; i++) { + if (!isfinite(saved[i]) || !isfinite(restored[i])) { + nonfinite++; + continue; + } + float delta = restored[i] - saved[i]; + float abs_delta = fabsf(delta); + if (abs_delta > max_abs) max_abs = abs_delta; + sumsq += (double)delta * (double)delta; + } + + logits_cmp out = { + .top1_saved = saved_top[0], + .top1_restored = restored_top[0], + .overlap = overlap, + .top5_overlap = top5_overlap, + .nonfinite = nonfinite, + .rms = (float)sqrt(sumsq / (double)vocab), + .max_abs = max_abs, + }; + return out; +} + +static bool load_payload_into_session(ds4_session *session, + const ds4_session_payload_file *payload, + char *err, + size_t errlen) { + FILE *fp = fopen(payload->path, "rb"); + if (!fp) { + snprintf(err, errlen, "failed to open staged payload: %s", strerror(errno)); + return false; + } + const int rc = ds4_session_load_payload(session, fp, payload->bytes, err, errlen); + fclose(fp); + return rc == 0; +} + +static bool write_payload_copy(const ds4_session_payload_file *payload, + const char *dst_path, + char *err, + size_t errlen) { + FILE *fp = fopen(dst_path, "wb"); + if (!fp) { + snprintf(err, errlen, "failed to open payload output: %s", strerror(errno)); + return false; + } + const int rc = ds4_session_write_staged_payload(payload, fp, err, errlen); + if (fclose(fp) != 0 && rc == 0) { + snprintf(err, errlen, "failed to close payload output: %s", strerror(errno)); + return false; + } + return rc == 0; +} + +static bool write_binary_file(const char *path, const void *ptr, size_t bytes) { + FILE *fp = fopen(path, "wb"); + if (!fp) return false; + bool ok = fwrite(ptr, 1, bytes, fp) == bytes; + ok = ok && fclose(fp) == 0; + return ok; +} + +static bool write_tokens_file(const char *path, const int *tokens, int count) { + FILE *fp = fopen(path, "wb"); + if (!fp) return false; + if (fprintf(fp, "%d\n", count) < 0) { + fclose(fp); + return false; + } + for (int i = 0; i < count; i++) { + if (fprintf(fp, "%d\n", tokens[i]) < 0) { + fclose(fp); + return false; + } + } + return fclose(fp) == 0; +} + +static char *sidecar_path(const char *base, const char *suffix) { + if (!base || !suffix) return NULL; + const size_t n = strlen(base) + strlen(suffix) + 1u; + char *out = malloc(n); + if (!out) return NULL; + snprintf(out, n, "%s%s", base, suffix); + return out; +} + +static bool set_process_lock_file(const char *path, char *err, size_t errlen) { + if (!path || !path[0]) { + snprintf(err, errlen, "invalid lock file path"); + return false; + } + if (setenv("DS4_LOCK_FILE", path, 1) != 0) { + snprintf(err, errlen, "failed to set DS4_LOCK_FILE: %s", strerror(errno)); + return false; + } + return true; +} + +static bool capture_greedy_trace(ds4_session *session, + int vocab, + int steps, + token_trace_run *out) { + memset(out, 0, sizeof(*out)); + out->tokens = malloc((size_t)steps * sizeof(out->tokens[0])); + out->trace = malloc((size_t)(steps + 1) * (size_t)vocab * sizeof(out->trace[0])); + if (!out->tokens || !out->trace) return false; + if (ds4_session_copy_logits(session, out->trace, vocab) != vocab) return false; + + char err[160]; + double t0 = now_sec(); + for (int i = 0; i < steps; i++) { + const int token = ds4_session_argmax(session); + out->tokens[i] = token; + out->token_count++; + if (ds4_session_eval(session, token, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase2-handoff: greedy eval failed at step %d: %s\n", + i, err[0] ? err : "unknown error"); + return false; + } + if (ds4_session_copy_logits(session, + out->trace + (size_t)(i + 1) * (size_t)vocab, + vocab) != vocab) { + return false; + } + out->trace_steps = i + 1; + } + out->elapsed_sec = now_sec() - t0; + return true; +} + +static bool capture_forced_trace(ds4_session *session, + int vocab, + const int *tokens, + int steps, + float *trace_out) { + if (ds4_session_copy_logits(session, trace_out, vocab) != vocab) return false; + char err[160]; + for (int i = 0; i < steps; i++) { + if (ds4_session_eval(session, tokens[i], err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase2-handoff: forced eval failed at step %d: %s\n", + i, err[0] ? err : "unknown error"); + return false; + } + if (ds4_session_copy_logits(session, + trace_out + (size_t)(i + 1) * (size_t)vocab, + vocab) != vocab) { + return false; + } + } + return true; +} + +static void free_token_trace_run(token_trace_run *run) { + free(run->tokens); + free(run->trace); + memset(run, 0, sizeof(*run)); +} + +static void parse_args(handoff_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--prompt-file") && i + 1 < argc) { + cfg->prompt_file = argv[++i]; + } else if (!strcmp(argv[i], "--system") && i + 1 < argc) { + cfg->system_prompt = argv[++i]; + } else if (!strcmp(argv[i], "--listen-host") && i + 1 < argc) { + cfg->listen_host = argv[++i]; + } else if (!strcmp(argv[i], "--listen-port") && i + 1 < argc) { + cfg->listen_port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx") && i + 1 < argc) { + cfg->ctx_size = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--gen-tokens") && i + 1 < argc) { + cfg->gen_tokens = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--forced-steps") && i + 1 < argc) { + cfg->forced_steps = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { + cfg->coordinator_layers = argv[++i]; + } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { + cfg->worker_layers = argv[++i]; + } else if (!strcmp(argv[i], "--payload-out") && i + 1 < argc) { + cfg->payload_out = argv[++i]; + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + die_usage(argv[0]); + } + } +} + +int main(int argc, char **argv) { + handoff_cfg cfg = { + .model_path = NULL, + .prompt_file = "README.md", + .system_prompt = "You are a helpful assistant", + .listen_host = NULL, + .coordinator_layers = "0:21", + .worker_layers = "22:output", + .payload_out = NULL, + .listen_port = 1234, + .ctx_size = 16384, + .gen_tokens = 16, + .forced_steps = 8, + .prefill_chunk = 256, + .prefill_window = 0, + .activation_bits = 32, + .debug = true, + }; + parse_args(&cfg, argc, argv); + if (!cfg.model_path || !cfg.listen_host || cfg.listen_port <= 0 || + cfg.ctx_size <= 0 || cfg.gen_tokens <= 0 || cfg.forced_steps < 0) { + die_usage(argv[0]); + } + if (cfg.forced_steps > cfg.gen_tokens) { + die("--forced-steps must be <= --gen-tokens"); + } + + struct in_addr addr; + if (inet_pton(AF_INET, cfg.listen_host, &addr) != 1) { + die("listen host must be an IPv4 address reachable from the worker"); + } + + ds4_distributed_layers coordinator_layers = {0}; + if (!parse_layer_spec(cfg.coordinator_layers, &coordinator_layers)) { + die("invalid coordinator layer spec"); + } + + char *prompt_text = read_file(cfg.prompt_file); + if (!prompt_text) die_errno("read prompt file"); + + ds4_engine *dist_engine = NULL; + ds4_engine *local_engine = NULL; + ds4_session *dist_session = NULL; + ds4_session *local_session = NULL; + ds4_session *trace_session = NULL; + ds4_tokens prompt = {0}; + ds4_session_payload_file payload = {0}; + dsv4_header header; + token_trace_run dist_run = {0}; + int *local_tokens = NULL; + float *dist_logits = NULL; + float *local_logits = NULL; + float *local_trace = NULL; + char err[256] = {0}; + bool stage_ok = false; + bool payload_copy_ok = false; + bool handoff_load_ok = false; + bool trace_load_ok = false; + bool greedy_match = false; + bool forced_trace_match = false; + int greedy_mismatch_step = -1; + int greedy_dist_token = -1; + int greedy_local_token = -1; + int forced_first_bad_step = -1; + int forced_token_before_step = -1; + logits_cmp handoff_cmp = {0}; + logits_cmp forced_bad_cmp = {0}; + double prefill_sec = 0.0; + double stage_sec = 0.0; + double local_load_sec = 0.0; + double local_decode_sec = 0.0; + char payload_copy_err[256] = {0}; + char export_err[256] = {0}; + uint32_t route_hops = 0; + bool output_on_coordinator = false; + char route_summary[1024] = {0}; + int handoff_token_count = 0; + uint64_t handoff_token_hash = 0; + char *dist_logits_path = NULL; + char *dist_tokens_path = NULL; + char *dist_trace_path = NULL; + + ds4_engine_options dist_opt = { + .model_path = cfg.model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = coordinator_layers, + .listen_host = cfg.listen_host, + .listen_port = cfg.listen_port, + .prefill_chunk = cfg.prefill_chunk, + .prefill_window = cfg.prefill_window, + .activation_bits = cfg.activation_bits, + .debug = cfg.debug, + }, + }; + if (ds4_dist_prepare_engine_options(&dist_opt.distributed, &dist_opt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase2-handoff: distributed options failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + if (ds4_engine_open(&dist_engine, &dist_opt) != 0 || !dist_engine) { + die("failed to open distributed coordinator engine"); + } + if (ds4_session_create(&dist_session, dist_engine, cfg.ctx_size) != 0 || !dist_session) { + die("failed to create distributed coordinator session"); + } + if (wait_route(dist_session, 60.0) != 1) goto fail; + + if (ds4_session_distributed_route_summary(dist_session, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator, + err, + sizeof(err)) != 1) { + fprintf(stderr, "issue304-phase2-handoff: route summary failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + + ds4_encode_chat_prompt(dist_engine, cfg.system_prompt, prompt_text, DS4_THINK_NONE, &prompt); + if (prompt.len <= 0) die("prompt tokenization failed"); + if (prompt.len >= cfg.ctx_size) die("prompt exceeds ctx"); + + const int vocab = ds4_engine_vocab_size(dist_engine); + dist_logits = malloc((size_t)vocab * sizeof(dist_logits[0])); + local_logits = malloc((size_t)vocab * sizeof(local_logits[0])); + if (!dist_logits || !local_logits) die("out of memory for logits"); + + double t0 = now_sec(); + if (ds4_session_sync(dist_session, &prompt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase2-handoff: distributed prefill failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + prefill_sec = now_sec() - t0; + + if (ds4_session_copy_logits(dist_session, dist_logits, vocab) != vocab) { + die("failed to copy distributed handoff logits"); + } + + memset(&header, 0, sizeof(header)); + t0 = now_sec(); + if (ds4_session_stage_payload(dist_session, &payload, err, sizeof(err)) == 0) { + stage_ok = true; + if (!parse_dsv4_header(payload.path, &header)) { + die("failed to parse staged DSV4 header"); + } + } else { + fprintf(stderr, "issue304-phase2-handoff: distributed payload stage failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + stage_sec = now_sec() - t0; + + if (cfg.payload_out) { + payload_copy_ok = write_payload_copy(&payload, + cfg.payload_out, + payload_copy_err, + sizeof(payload_copy_err)); + if (!payload_copy_ok) goto fail; + } + + if (!capture_greedy_trace(dist_session, vocab, cfg.gen_tokens, &dist_run)) { + goto fail; + } + + if (cfg.payload_out) { + dist_logits_path = sidecar_path(cfg.payload_out, ".logits.f32"); + dist_tokens_path = sidecar_path(cfg.payload_out, ".tokens.txt"); + dist_trace_path = sidecar_path(cfg.payload_out, ".trace.f32"); + if (!dist_logits_path || !dist_tokens_path || !dist_trace_path) { + snprintf(export_err, sizeof(export_err), "out of memory creating sidecar paths"); + goto fail; + } + if (!write_binary_file(dist_logits_path, + dist_logits, + (size_t)vocab * sizeof(dist_logits[0]))) { + snprintf(export_err, sizeof(export_err), "failed to write distributed logits sidecar"); + goto fail; + } + if (!write_tokens_file(dist_tokens_path, dist_run.tokens, dist_run.token_count)) { + snprintf(export_err, sizeof(export_err), "failed to write distributed tokens sidecar"); + goto fail; + } + if (!write_binary_file(dist_trace_path, + dist_run.trace, + (size_t)(dist_run.token_count + 1) * (size_t)vocab * sizeof(dist_run.trace[0]))) { + snprintf(export_err, sizeof(export_err), "failed to write distributed trace sidecar"); + goto fail; + } + } + + const ds4_tokens *timeline = ds4_session_tokens(dist_session); + handoff_token_count = timeline ? timeline->len : 0; + handoff_token_hash = timeline ? token_hash_prefix(timeline) : 0; + + ds4_session_free(dist_session); + dist_session = NULL; + ds4_engine_close(dist_engine); + dist_engine = NULL; + + if (!set_process_lock_file("/tmp/ds4-phase2-local.lock", err, sizeof(err))) { + fprintf(stderr, "issue304-phase2-handoff: %s\n", err); + goto fail; + } + + ds4_engine_options local_opt = { + .model_path = cfg.model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + }; + if (ds4_engine_open(&local_engine, &local_opt) != 0 || !local_engine) { + die("failed to open local decode engine"); + } + if (ds4_engine_vocab_size(local_engine) != vocab) { + die("distributed and local vocab sizes differ"); + } + + if (ds4_session_create(&local_session, local_engine, cfg.ctx_size) != 0 || !local_session) { + die("failed to create local decode session"); + } + + t0 = now_sec(); + handoff_load_ok = load_payload_into_session(local_session, &payload, err, sizeof(err)); + local_load_sec = now_sec() - t0; + if (!handoff_load_ok) { + fprintf(stderr, "issue304-phase2-handoff: local payload load failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + + if (ds4_session_copy_logits(local_session, local_logits, vocab) != vocab) { + die("failed to copy local handoff logits"); + } + handoff_cmp = compare_logits(dist_logits, local_logits, vocab); + + local_tokens = malloc((size_t)cfg.gen_tokens * sizeof(local_tokens[0])); + if (!local_tokens) die("out of memory for local decode tokens"); + + t0 = now_sec(); + for (int i = 0; i < cfg.gen_tokens; i++) { + local_tokens[i] = ds4_session_argmax(local_session); + if (ds4_session_eval(local_session, local_tokens[i], err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase2-handoff: local greedy eval failed at step %d: %s\n", + i, err[0] ? err : "unknown error"); + goto fail; + } + } + local_decode_sec = now_sec() - t0; + + greedy_match = true; + for (int i = 0; i < cfg.gen_tokens; i++) { + if (dist_run.tokens[i] != local_tokens[i]) { + greedy_match = false; + greedy_mismatch_step = i; + greedy_dist_token = dist_run.tokens[i]; + greedy_local_token = local_tokens[i]; + break; + } + } + + if (cfg.forced_steps > 0) { + local_trace = malloc((size_t)(cfg.forced_steps + 1) * (size_t)vocab * sizeof(local_trace[0])); + if (!local_trace) die("out of memory for local forced trace"); + + if (ds4_session_create(&trace_session, local_engine, cfg.ctx_size) != 0 || !trace_session) { + die("failed to create forced-trace session"); + } + trace_load_ok = load_payload_into_session(trace_session, &payload, err, sizeof(err)); + if (!trace_load_ok) { + fprintf(stderr, "issue304-phase2-handoff: forced-trace payload load failed: %s\n", + err[0] ? err : "unknown error"); + goto fail; + } + + if (!capture_forced_trace(trace_session, + vocab, + dist_run.tokens, + cfg.forced_steps, + local_trace)) { + goto fail; + } + + forced_trace_match = true; + for (int step = 0; step <= cfg.forced_steps; step++) { + logits_cmp cmp = compare_logits(dist_run.trace + (size_t)step * (size_t)vocab, + local_trace + (size_t)step * (size_t)vocab, + vocab); + if (cmp.nonfinite != 0 || cmp.top1_saved != cmp.top1_restored || + cmp.top5_overlap < 5 || cmp.overlap < 20 || + cmp.rms != 0.0f || cmp.max_abs != 0.0f) { + forced_trace_match = false; + forced_first_bad_step = step; + forced_bad_cmp = cmp; + forced_token_before_step = step > 0 ? dist_run.tokens[step - 1] : -1; + break; + } + } + } + + const uint64_t hash = handoff_token_hash; + uint32_t hash_hi = 0; + uint32_t hash_lo = 0; + u64_to_halves(hash, &hash_hi, &hash_lo); + + printf("{\n"); + printf(" \"tool\":\"issue304_phase2_handoff\",\n"); + printf(" \"listen_host\":\"%s\",\n", cfg.listen_host); + printf(" \"listen_port\":%d,\n", cfg.listen_port); + printf(" \"model_path\":\"%s\",\n", cfg.model_path); + printf(" \"prompt_file\":\"%s\",\n", cfg.prompt_file); + printf(" \"ctx\":%d,\n", cfg.ctx_size); + printf(" \"prompt_tokens\":%d,\n", prompt.len); + printf(" \"gen_tokens\":%d,\n", cfg.gen_tokens); + printf(" \"forced_steps\":%d,\n", cfg.forced_steps); + printf(" \"prefill_chunk\":%u,\n", cfg.prefill_chunk); + printf(" \"prefill_window\":%u,\n", cfg.prefill_window); + printf(" \"activation_bits\":%u,\n", cfg.activation_bits); + printf(" \"debug\":%s,\n", cfg.debug ? "true" : "false"); + printf(" \"coordinator_layers\":\"%s\",\n", cfg.coordinator_layers); + printf(" \"expected_worker_layers\":\"%s\",\n", cfg.worker_layers); + printf(" \"route_hops\":%u,\n", route_hops); + printf(" \"route_summary\":\"%s\",\n", route_summary); + printf(" \"output_owner\":\"%s\",\n", output_on_coordinator ? "coordinator" : "worker"); + printf(" \"prefill_sec\":%.6f,\n", prefill_sec); + printf(" \"prefill_tok_per_sec\":%.2f,\n", prefill_sec > 0.0 ? (double)prompt.len / prefill_sec : 0.0); + printf(" \"stage_ok\":%s,\n", stage_ok ? "true" : "false"); + printf(" \"stage_sec\":%.6f,\n", stage_sec); + printf(" \"payload_bytes\":%llu,\n", (unsigned long long)payload.bytes); + printf(" \"payload_copy_ok\":%s,\n", payload_copy_ok ? "true" : "false"); + printf(" \"payload_copy_path\":\"%s\",\n", cfg.payload_out ? cfg.payload_out : ""); + printf(" \"payload_copy_error\":\"%s\",\n", payload_copy_ok || !cfg.payload_out ? "" : payload_copy_err); + printf(" \"local_load_ok\":%s,\n", handoff_load_ok ? "true" : "false"); + printf(" \"local_load_sec\":%.6f,\n", local_load_sec); + printf(" \"distributed_decode_sec\":%.6f,\n", dist_run.elapsed_sec); + printf(" \"distributed_decode_tok_per_sec\":%.2f,\n", + dist_run.elapsed_sec > 0.0 ? (double)cfg.gen_tokens / dist_run.elapsed_sec : 0.0); + printf(" \"local_decode_sec\":%.6f,\n", local_decode_sec); + printf(" \"local_decode_tok_per_sec\":%.2f,\n", + local_decode_sec > 0.0 ? (double)cfg.gen_tokens / local_decode_sec : 0.0); + printf(" \"token_count\":%d,\n", handoff_token_count); + printf(" \"token_hash\":\"0x%08x%08x\",\n", hash_hi, hash_lo); + printf(" \"handoff\":{\n"); + printf(" \"top1_saved\":%d,\n", handoff_cmp.top1_saved); + printf(" \"top1_restored\":%d,\n", handoff_cmp.top1_restored); + printf(" \"top5_overlap\":%d,\n", handoff_cmp.top5_overlap); + printf(" \"top20_overlap\":%d,\n", handoff_cmp.overlap); + printf(" \"rms\":%.9g,\n", handoff_cmp.rms); + printf(" \"max_abs\":%.9g,\n", handoff_cmp.max_abs); + printf(" \"nonfinite\":%d,\n", handoff_cmp.nonfinite); + printf(" \"match\":%s\n", + (handoff_cmp.nonfinite == 0 && + handoff_cmp.top1_saved == handoff_cmp.top1_restored && + handoff_cmp.top5_overlap == 5 && + handoff_cmp.overlap == 20) ? "true" : "false"); + printf(" },\n"); + printf(" \"greedy\":{\n"); + printf(" \"match\":%s,\n", greedy_match ? "true" : "false"); + printf(" \"mismatch_step\":%d,\n", greedy_mismatch_step); + printf(" \"distributed_token\":%d,\n", greedy_dist_token); + printf(" \"local_token\":%d\n", greedy_local_token); + printf(" },\n"); + printf(" \"forced_trace\":{\n"); + printf(" \"checked\":%s,\n", cfg.forced_steps > 0 ? "true" : "false"); + printf(" \"match\":%s,\n", forced_trace_match ? "true" : "false"); + printf(" \"first_bad_step\":%d,\n", forced_first_bad_step); + printf(" \"forced_token_before_step\":%d,\n", forced_token_before_step); + printf(" \"top1_ref\":%d,\n", forced_bad_cmp.top1_saved); + printf(" \"top1_local\":%d,\n", forced_bad_cmp.top1_restored); + printf(" \"top5_overlap\":%d,\n", forced_bad_cmp.top5_overlap); + printf(" \"top20_overlap\":%d,\n", forced_bad_cmp.overlap); + printf(" \"rms\":%.9g,\n", forced_bad_cmp.rms); + printf(" \"max_abs\":%.9g,\n", forced_bad_cmp.max_abs); + printf(" \"nonfinite\":%d\n", forced_bad_cmp.nonfinite); + printf(" },\n"); + printf(" \"dsv4\":{\n"); + printf(" \"ctx_size\":%u,\n", header.ctx_size); + printf(" \"prefill_cap\":%u,\n", header.prefill_cap); + printf(" \"raw_cap\":%u,\n", header.raw_cap); + printf(" \"raw_window\":%u,\n", header.raw_window); + printf(" \"comp_cap\":%u,\n", header.comp_cap); + printf(" \"saved_tokens\":%u,\n", header.saved_tokens); + printf(" \"n_layer\":%u,\n", header.n_layer); + printf(" \"head_dim\":%u,\n", header.head_dim); + printf(" \"indexer_head_dim\":%u,\n", header.indexer_head_dim); + printf(" \"vocab\":%u,\n", header.vocab); + printf(" \"raw_live\":%u\n", header.raw_live); + printf(" }\n"); + printf("}\n"); + + free(dist_trace_path); + free(dist_tokens_path); + free(dist_logits_path); + free(local_trace); + free(local_logits); + free(dist_logits); + free(local_tokens); + free_token_trace_run(&dist_run); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(trace_session); + ds4_session_free(local_session); + ds4_session_free(dist_session); + ds4_engine_close(local_engine); + ds4_engine_close(dist_engine); + free(prompt_text); + return 0; + +fail: + if (export_err[0]) { + fprintf(stderr, "issue304-phase2-handoff: %s\n", export_err); + } + free(dist_trace_path); + free(dist_tokens_path); + free(dist_logits_path); + free(local_trace); + free(local_logits); + free(dist_logits); + free(local_tokens); + free_token_trace_run(&dist_run); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(trace_session); + ds4_session_free(local_session); + ds4_session_free(dist_session); + ds4_engine_close(local_engine); + ds4_engine_close(dist_engine); + free(prompt_text); + return 1; +} From f7a0baa424ebe8b40c26a6f65254dfcf0c586e34 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Thu, 4 Jun 2026 10:38:58 +0100 Subject: [PATCH 04/17] refine phase 3 plan --- NAVIGATION.md | 16 ++++- PLAN.md | 69 ++++++++++++--------- artifacts/issue-304/compatibility-matrix.md | 10 ++- artifacts/issue-304/decision-log.md | 29 ++++++++- artifacts/issue-304/engine-residency.md | 28 +++++++++ artifacts/issue-304/failure-cases.md | 31 +++++++++ artifacts/issue-304/logit-comparisons.md | 18 +++++- artifacts/issue-304/research-notes.md | 26 ++++---- artifacts/issue-304/runbook.md | 29 +++++++++ artifacts/issue-304/topology-decoupling.md | 28 +++++++++ 10 files changed, 237 insertions(+), 47 deletions(-) create mode 100644 artifacts/issue-304/engine-residency.md create mode 100644 artifacts/issue-304/failure-cases.md create mode 100644 artifacts/issue-304/topology-decoupling.md diff --git a/NAVIGATION.md b/NAVIGATION.md index a713e2dce..d16f4cbc2 100644 --- a/NAVIGATION.md +++ b/NAVIGATION.md @@ -580,6 +580,7 @@ Validation commands: - `./ds4_test --metal-short-prefill` - `./ds4_test --metal-kernels` - `./ds4_test --metal-tensor-equivalence` +- `./ds4_test --logprob-vectors` - `./ds4_test --local-golden-vectors` - `./ds4_test --long-context` @@ -596,6 +597,12 @@ Issue #304 validation additions: - save merged `DSV4`, - load into non-distributed full local session, - compare logits and greedy tokens. +- Add Phase 3 official/local parity checks: + - run official-vector prompts through fully local inference on the decode backend, + - run the same prompts through distributed prefill -> merged `DSV4` -> local decode on that backend, + - compare distributed handoff against fully local before treating cross-engine drift as a defect, + - compare selected tokens/top-logprobs against `tests/test-vectors/official.vec`, + - compare local full-logit behavior against `tests/test-vectors/local-golden.vec` where available. - Add cross-backend manual smoke where hardware allows: - CUDA worker/shard -> Metal local load/decode, - Metal shard -> CUDA local load/decode. @@ -605,6 +612,7 @@ Issue #304 validation additions: - max absolute logit drift, - RMS logit drift, - first 16 greedy tokens. +- Treat bit-exact cross-engine logits as diagnostic evidence, not a Phase 3 requirement, unless they expose a same-backend handoff or official/local-vector failure. ## User-Facing Workflow And Documentation @@ -676,6 +684,7 @@ Useful test binary modes: - `./ds4_test --metal-short-prefill` - `./ds4_test --metal-kernels` - `./ds4_test --metal-tensor-equivalence` +- `./ds4_test --logprob-vectors` - `./ds4_test --local-golden-vectors` - `./ds4_test --long-context` @@ -684,6 +693,10 @@ Relevant test files: - `tests/ds4_test.c` - Local/Metal/session regression surface. - Best place for focused payload save/load and layer-shard tests. +- `tests/test-vectors/official.vec` + - Official API top-logprob vector fixture used as the Phase 3 selected-token/top-logprob acceptance surface. +- `tests/test-vectors/local-golden.vec` + - Local top-k/logit fixture used to catch substantial local backend drift. - `tests/cuda_long_context_smoke.c` - CUDA-specific kernel smoke surface. - `tests/long_context_story_prompt.txt` @@ -736,6 +749,7 @@ Minimal correctness proof: - `ds4_session_load_payload()`. - Decode locally for 1-3 tokens. - Compare against current distributed decode and single-node local decode where feasible. +- For Phase 3, run the official-vector prompt set through the same sequence and require same-backend distributed handoff parity with fully local inference before classifying cross-engine forced-logit drift as acceptable backend variance. Known blockers to analyze before user-facing implementation: @@ -763,7 +777,7 @@ Failure cases to preserve: - Missing output head when logits are requested. - Worker reconnect before shard fetch. - Stale worker session after route rebuild. -- Cross-backend payload load drift outside accepted tolerance. +- Cross-backend payload load drift that changes same-backend handoff behavior or fails official/local-vector tolerance. ## Search Tips diff --git a/PLAN.md b/PLAN.md index a44bcf5e4..daf4dc53a 100644 --- a/PLAN.md +++ b/PLAN.md @@ -38,15 +38,16 @@ Source: and its comment thread. ## Remaining unknowns -- Why `CUDA -> Metal` payloads restore the handoff logits exactly but still diverge after the first identical resumed decode step. -- Whether that resumed-decode drift lives in backend-specific KV interpretation, backend-specific decode-state evolution, or a smaller payload field that only matters after the next token is evaluated. +- Whether `CUDA -> Metal` resumed-decode drift is only normal engine/backend implementation variance, or whether it indicates payload/handoff state that would make distributed-prefill-to-local differ from fully local inference on the same decode engine. +- Whether distributed prefill -> merged `DSV4` -> local decode matches the official-vector and local-golden correctness surfaces already used for fully local inference. - How to let the coordinator participate in distributed prefill while still keeping a full local decode-capable engine resident without exhausting Metal memory budget. - Whether the eventual handoff path should remain a merged `DSV4` checkpoint, move to an in-memory merged payload, or skip the merged payload entirely by streaming worker-owned KV shards back during prefill. ## Implementation direction - Keep the merged `DSV4` handoff path as the current correctness boundary. Phase 2 validated that it can gather distributed shards, stage a payload, load locally, and recover the exact handoff checkpoint. -- Treat mixed-backend resumed-decode drift as the immediate blocker. Fix that before spending more time on transport redesign or pipelined KV return. +- Treat mixed-backend resumed-decode drift as a classification problem, not automatically a bug. Isolate it enough to decide whether it is expected engine variance or a handoff-specific defect. +- Require the distributed-prefill-to-local path to match fully local inference on the same decode engine against `tests/test-vectors/official` / `official.vec` and the local golden-vector surface before productizing the workflow. - Treat coordinator engine residency as a separate productization problem. Phase 2 proved the feature concept by releasing the distributed engine before local decode; the next residency work is about making that handoff practical in one user-visible workflow. - Defer chunk-by-chunk KV return until after the resumed-decode correctness and residency story are both understood. At this point it is an optimization and UX improvement, not the first proof point. @@ -190,9 +191,10 @@ Source: and its comment thread. ## Most Relevant Files To Start In -- `ds4_metal.m` and `ds4_cuda.cu`: Phase 2 points first at backend-specific resumed decode behavior, so these are now the highest-priority files. +- `tests/ds4_test.c` and `tests/test-vectors/official.vec`: Phase 3 should reuse the official-vector and local-golden correctness gates as the primary acceptance surface. +- `tests/issue304_phase1_matrix.c` and `tests/issue304_phase2_handoff.c`: keep using these focused harnesses to isolate and classify cross-engine drift. - `ds4.c`: inspect payload restore, decode entry, and session state setup around `ds4_session_load_payload()` and resumed `ds4_session_eval()`. -- `tests/issue304_phase1_matrix.c` and `tests/issue304_phase2_handoff.c`: keep using these focused harnesses to narrow the first post-load divergence. +- `ds4_metal.m` and `ds4_cuda.cu`: inspect only if evidence points to backend-specific decode behavior that needs classification or documentation. - `ds4_distributed.c`: return here after backend resume correctness is understood, or when implementing the later residency/transport optimization phases. ## Research And Implementation Plan @@ -398,7 +400,7 @@ Work items: - Load the merged `DSV4` payload into that local session. - Decode locally for at least 1-3 tokens. - Compare against continuing distributed decode from the original distributed session and single-node local prefill/decode when feasible. -- Treat this two-session shape as a correctness experiment unless `artifacts/issue-304/engine-residency.md` proves memory is acceptable. +- Treat this two-session shape as a correctness experiment. Phase 4 owns the decision about whether engine residency can make it practical for user-facing use. Key questions: @@ -410,48 +412,57 @@ Key questions: Exit gate: - The existing payload path can hand off distributed prefill state into a local-only decode session, or a specific blocker is captured with enough detail to choose the next implementation step. -- If the path works only by running two engines or reloading an engine, it must not proceed directly to user-facing implementation; Phase 3 must choose a viable layer-residency design first. +- If the path works only by running two engines or reloading an engine, it must not proceed directly to user-facing implementation; Phase 4 must choose a viable layer-residency design first. -### Phase 3: Mixed-backend resumed decode root cause +### Phase 3: Handoff equivalence and drift isolation Goal: -- Why: Phase 2 proved the merged handoff checkpoint is exact, but it also reproduced mixed-backend resumed-decode drift immediately after the first identical forced token. The next phase needs to turn that broad symptom into a concrete backend or restore-path bug. -- What: isolate why `CUDA -> Metal` diverges after the first resumed eval step even when the restored logits are identical and the sampled greedy path can stay stable. +- Why: Phase 2 proved the merged handoff checkpoint is exact and local greedy decode can match distributed reference, but forced-token logits can drift after resumed eval. That drift is acceptable if it is just normal backend implementation variance; it is not acceptable if distributed prefill -> local decode differs from fully local inference on the same decode engine or fails the existing official-vector/local-golden correctness gates. +- What: isolate the drift class and prove that distributed-prefill-to-local decode matches fully local decode on the same backend for `tests/test-vectors/official` / `official.vec` and local golden-vector style checks. Expected artifacts: -- Update `artifacts/issue-304/logit-comparisons.md` with finer-grained forced-token traces around the first divergent resumed step. -- Update `artifacts/issue-304/failure-cases.md` with every narrowed reproduction of post-load decode drift that remains rejected. -- Update `artifacts/issue-304/research-notes.md` with the first divergent state that can be localized reliably. -- Update `artifacts/issue-304/decision-log.md` if the evidence shows the bug is payload-ABI, backend-runtime, or decode-graph specific. +- Update `artifacts/issue-304/logit-comparisons.md` with official-vector comparisons for fully local inference and distributed-prefill-to-local decode on the same decode backend. +- Update `artifacts/issue-304/compatibility-matrix.md` with a Phase 3 row classifying drift as accepted engine variance or rejected handoff-specific mismatch. +- Update `artifacts/issue-304/failure-cases.md` with every drift case that remains rejected because it changes local-backend behavior or fails official/local-golden gates. +- Update `artifacts/issue-304/research-notes.md` with the classification result and any remaining caveat about cross-engine numeric differences. +- Update `artifacts/issue-304/decision-log.md` if the evidence shows the drift is acceptable engine variance, payload-ABI related, backend-runtime related, or decode-graph specific. Code touchpoints: +- `tests/ds4_test.c` + - Existing `--logprob-vectors` and `--local-golden-vectors` checks define the local correctness surface to reuse or mirror. +- `tests/test-vectors/official.vec` and `tests/test-vectors/official/*.official.json` + - Official API top-logprob vectors are the reference surface; the hosted API exposes top-logprobs rather than full logits. - `tests/issue304_phase1_matrix.c` - - Extend the focused resume helper so it can compare finer-grained post-load state, not just logits and greedy tokens. + - Extend the focused resume helper only as needed to classify whether cross-engine drift changes accepted top-token/top-logprob behavior. - `tests/issue304_phase2_handoff.c` - - Keep the distributed-prefill harness aligned with the smaller Phase 1 probes so the same divergence can be reproduced in both contexts. + - Add or reuse a mode that can run the official-vector prompts through distributed prefill -> merged payload -> local decode and compare against fully local decode on the same backend. - `ds4.c` - - `ds4_session_load_payload()`: restore path to inspect for any field that is sufficient for step-0 logits but insufficient for step-1 decode evolution. - - `ds4_session_eval()` and local decode entry path: first resumed decode step after load. + - Inspect `ds4_session_load_payload()` and resumed `ds4_session_eval()` only if distributed handoff differs from fully local inference on the same backend. - `ds4_gpu.h` - - Shared tensor read/write and synchronization boundary if the first divergent state turns out to be visible only below the session payload layer. + - Shared tensor read/write and synchronization boundary if same-backend handoff mismatch appears below the session payload layer. - `ds4_metal.m` and `ds4_cuda.cu` - - Backend-specific decode-state assumptions, dtype conversion, raw/compressed KV interpretation, and graph state setup. + - Backend-specific decode-state assumptions, dtype conversion, raw/compressed KV interpretation, and graph state setup; cross-engine differences here are acceptable if they do not invalidate the same-backend handoff checks. Work items: -- Extend `tests/issue304_phase1_matrix.c` so it can dump or compare finer-grained post-load state around the first resumed decode step. -- Compare `CUDA -> Metal` and `Metal -> Metal` immediately after one identical forced eval token, looking for the first tensor or cache-state difference that appears before logits drift becomes visible. -- Inspect `ds4_session_load_payload()` and resumed `ds4_session_eval()` in `ds4.c` for any state that is restored correctly enough for step-0 logits but not for step-1 decode evolution. -- Inspect `ds4_metal.m` and `ds4_cuda.cu` for backend-specific assumptions around raw KV rows, compressed KV rows, cache frontiers, dtype conversion, or decode-only graph state that may not be fully represented by the current payload ABI. +- Define the Phase 3 acceptance envelope from existing local checks: + - `./ds4_test --logprob-vectors` + - `./ds4_test --local-golden-vectors` + - the existing skipped `long_memory_archive` official-vector caveat +- Add a focused distributed-handoff vector check that runs the official-vector prompts through distributed prefill, stages merged `DSV4`, loads into local decode, and compares against fully local inference on the same decode backend. +- Compare distributed-prefill-to-local output to the official top-logprob vectors using the same selected-token and top-logprob tolerance rules as `--logprob-vectors`. +- Compare distributed-prefill-to-local output to fully local output for the same prompt/frontier before interpreting any cross-engine drift as a defect. +- Keep the forced-token trace probe, but use it to classify and bound backend variance rather than requiring bit-exact agreement across engines. +- Inspect `ds4_session_load_payload()`, `ds4_session_eval()`, and backend decode paths only if the same-backend fully-local vs distributed-handoff comparison fails or official/local-golden gates regress. Exit gate: -- Either: - - `CUDA -> Metal` forced-token drift is eliminated for the existing Phase 1 and Phase 2 probes, or - - the first divergent restored state is localized well enough that the remaining work is a specific backend/runtime bug rather than a general handoff uncertainty. +- Distributed prefill -> local decode matches fully local inference on the same decode backend for the official-vector prompt set, within the existing official/local-golden acceptance envelope. +- Any remaining `CUDA -> Metal` forced-token drift is classified as accepted engine/backend variance, or is localized as a specific handoff defect with a reproduction. +- If official-vector or local-golden checks fail only for distributed handoff, stop before Phase 4 and fix that handoff-specific mismatch. ### Phase 4: Coordinator residency and workflow viability @@ -646,7 +657,7 @@ Work items: Exit gate: -- Incremental KV return reduces measured handoff latency without changing resumed logits/tokens beyond the accepted drift envelope. +- Incremental KV return reduces measured handoff latency without changing resumed logits/tokens beyond the Phase 3 official/local acceptance envelope. ### Phase 7: Failure handling and recovery @@ -702,7 +713,7 @@ Goal: - Why: practical deployments may want GPU-rich machines to do prefill and memory-rich machines to do generation, so control-plane role, prefill layer ownership, output-head/logit ownership, KV return destination, and decode owner should not remain permanently coupled. - What: document the current coordinator-first topology constraints, determine whether topology decoupling is required for the first production implementation or can be deferred, and outline a route/protocol direction if it must be solved. -This is intentionally after Phase 7 because the immediate feature can be proven with the current route model. Do not let this phase block the first correct local-generation handoff unless the chosen Phase 3 residency design makes topology decoupling unavoidable. +This is intentionally after Phase 7 because the immediate feature can be proven with the current route model. Do not let this phase block the first correct local-generation handoff unless the chosen Phase 4 residency design makes topology decoupling unavoidable. Expected artifacts: diff --git a/artifacts/issue-304/compatibility-matrix.md b/artifacts/issue-304/compatibility-matrix.md index 463748293..baed71007 100644 --- a/artifacts/issue-304/compatibility-matrix.md +++ b/artifacts/issue-304/compatibility-matrix.md @@ -20,7 +20,13 @@ | Date | Commit | Model | Route | Handoff path | Result | Notes | | --- | --- | --- | --- | --- | --- | --- | -| 2026-06-03 | local `116e35881679c99cbe33454f95d2b4c96448761b`, DGX worker rebuilt from synced `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` tree with local source updates | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output` | distributed prefill on Metal/CUDA route -> merged `DSV4` stage on Metal -> fresh local Metal load -> local decode comparison | Mixed result | `tests/issue304_phase2_handoff`: handoff logits matched exactly and 16-token greedy continuation matched exactly; forced-token trace still diverged at step `1` after the first identical post-load eval token (`5`), with `rms=0.0802887231`, `max_abs=0.507860184`. | +| 2026-06-03 | local `116e35881679c99cbe33454f95d2b4c96448761b`, DGX worker rebuilt from synced `477c0e82e2699b35a65fd0a1ed6fe66b41087dfe` tree with local source updates | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output` | distributed prefill on Metal/CUDA route -> merged `DSV4` stage on Metal -> fresh local Metal load -> local decode comparison | Pass with drift caveat | `tests/issue304_phase2_handoff`: handoff logits matched exactly and 16-token greedy continuation matched exactly; forced-token trace diverged at step `1` after the first identical post-load eval token (`5`), with `rms=0.0802887231`, `max_abs=0.507860184`. Phase 3 must classify this against fully local and official-vector baselines before treating it as a defect. | + +## Phase 3: Official/local baseline parity + +| Date | Commit | Model | Route | Validation path | Result | Notes | +| --- | --- | --- | --- | --- | --- | --- | +| Pending | Pending | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output` | official-vector prompts -> distributed prefill -> merged `DSV4` -> local decode, compared against fully local inference and `tests/test-vectors/official.vec` | Not run | Phase 3 should classify whether the Phase 2 forced-logit drift is acceptable engine variance by proving same-backend distributed handoff parity with fully local inference and existing official/local-golden gates. | ## Representative `DSVL` shard smoke @@ -36,4 +42,4 @@ - Every planned Phase 1 backend pair has now been exercised at least once. - The only failing cell is `CUDA -> Metal`, and the current failure is narrower than a restore-point logit mismatch: the loaded Metal session starts from identical logits but diverges during subsequent greedy decode. - Forced-token follow-up on the same failing cell shows that logits already diverge after the first identical post-load eval token, so the failure is not explained by token-selection branching alone. -- Phase 2 now confirms the same pattern after real distributed prefill: exact handoff checkpoint, matching greedy continuation over the sampled window, but first-step forced-trace drift on resumed Metal decode. +- Phase 2 now confirms exact handoff checkpoint and matching greedy continuation over the sampled window. The first-step forced-trace drift on resumed Metal decode is a Phase 3 classification item, not automatically a failing compatibility result. diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index abfdf14d0..9bd6a32c5 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -63,7 +63,7 @@ Why this changes the work: Follow-up: -- Run the helper on the DGX/Mac topology and record the resulting metrics before deciding whether Phase 3 needs engine-residency work only or whether Phase 2 still hides a Metal/CUDA payload-resume defect. +- Run the helper on the DGX/Mac topology and record the resulting metrics before deciding whether the remaining work is same-backend handoff validation, acceptable backend-variance classification, or a specific payload-resume defect. ## 2026-06-03: Phase 2 confirms exact handoff but not exact resumed decode evolution @@ -71,7 +71,7 @@ Decision: - Treat Phase 2 as complete. - Do not spend more Phase 2 effort on distributed KV gather or merged payload staging. -- Carry the remaining defect forward as a mixed-backend resumed-decode evolution problem. +- Carry the remaining observed drift forward as a mixed-backend resumed-decode evolution classification problem. Evidence: @@ -100,4 +100,27 @@ Why this changes the next steps: Follow-up: -- Phase 3 and follow-on debugging should focus on backend-specific post-load decode-state evolution, not on redesigning the merged `DSV4` handoff boundary. +- Phase 3 should focus on classifying backend-specific post-load decode drift, not necessarily eliminating it. Cross-engine drift is acceptable if distributed prefill -> local decode matches fully local inference on the same decode backend and passes the official-vector/local-golden correctness gates. + +## 2026-06-04: Re-scope Phase 3 around handoff parity, not bit-exact cross-engine logits + +Decision: + +- Phase 3 success does not require eliminating `CUDA -> Metal` forced-logit drift. +- Treat cross-engine drift as acceptable engine variance if it is isolated from the handoff path. +- Require distributed prefill -> merged `DSV4` -> local decode to match fully local inference on the same decode engine against: + - `tests/test-vectors/official.vec` + - `./ds4_test --logprob-vectors` + - `./ds4_test --local-golden-vectors` + +Evidence: + +- Phase 2 handoff logits matched exactly and 16-token greedy continuation matched exactly. +- The observed drift appeared only in full-logit forced comparison after resumed eval began. +- Existing test-vector infrastructure already treats the official API as a top-logprob reference rather than a bit-exact full-logit oracle. +- Local golden vectors already exist to catch substantial local backend drift while tolerating implementation-level numeric differences. + +Why this changes the next steps: + +- The next test should compare distributed-prefill-to-local decode against fully local decode on the same backend before assigning blame to CUDA/Metal engine differences. +- If the same-backend comparison and official/local gates pass, Phase 3 can classify the forced-logit drift as acceptable backend variance and move on to residency/workflow planning. diff --git a/artifacts/issue-304/engine-residency.md b/artifacts/issue-304/engine-residency.md new file mode 100644 index 000000000..fdb7eba97 --- /dev/null +++ b/artifacts/issue-304/engine-residency.md @@ -0,0 +1,28 @@ +# Issue #304 Engine Residency + +This artifact records the model residency decision for turning the Phase 2 proof path into a practical local-generation handoff workflow. + +## Current Status + +- Phase 2 proved distributed prefill can hand off through a merged `DSV4` payload and continue local decode after the distributed engine is released. +- That proof path opens a fresh full local engine/session for decode. It is acceptable as a research harness, but not yet a user-facing workflow. +- Phase 3 is now scoped to correctness classification: same-backend distributed handoff parity against fully local inference and the official/local vector gates. +- Phase 4 owns the residency decision. + +## Known Constraints + +- Distributed `--layers` currently influences both route ownership and local model layer residency. +- Local decode needs full model weights, output/logit capability, and full KV state. +- A coordinator that maps only its route slice cannot directly perform full local decode without changing residency or opening another full engine. +- The existing validated handoff boundary is the merged `DSV4` payload. + +## Candidate Directions For Phase 4 + +- Keep the current two-engine transition for research and measure whether the memory/runtime cost is acceptable only for validation. +- Decouple distributed route ownership from local weight residency so one coordinator engine can own a route slice during prefill but still retain enough state for full local decode. +- Add lazy or staged residency expansion if full upfront residency is too expensive. +- Keep merged `DSV4` as the correctness boundary while improving the user-facing transition mechanics. + +## Acceptance Direction + +The Phase 4 residency design should not weaken the Phase 3 acceptance envelope: distributed prefill -> local decode must continue to match fully local inference on the same decode backend and pass the official/local vector checks. diff --git a/artifacts/issue-304/failure-cases.md b/artifacts/issue-304/failure-cases.md new file mode 100644 index 000000000..589607d73 --- /dev/null +++ b/artifacts/issue-304/failure-cases.md @@ -0,0 +1,31 @@ +# Issue #304 Failure Cases + +This artifact records mismatches that should remain rejected during distributed-prefill-to-local-decode work. + +## Current Status + +- No Phase 3 official/local parity failure has been recorded yet. +- Phase 2 observed `CUDA -> Metal` forced-token logit drift after resumed eval, but handoff logits and the sampled greedy continuation matched exactly. This is a Phase 3 classification case, not currently a proven rejection case. + +## Phase 3 Rejection Criteria + +A drift case should be recorded here as rejected if it: + +- makes distributed prefill -> merged `DSV4` -> local decode differ from fully local inference on the same decode backend, +- fails the selected-token/top-logprob envelope used by `./ds4_test --logprob-vectors`, +- fails the local-golden drift envelope used by `./ds4_test --local-golden-vectors`, +- changes greedy continuation where the same-backend fully-local baseline stays stable, +- or localizes to payload ABI, shard metadata, token hash, context, layer range, output-head, or cache-state corruption. + +Cross-engine forced-logit differences alone are not a rejection case if same-backend handoff parity and official/local gates pass. + +## Future Failure Classes To Preserve + +- Token hash mismatch. +- Layer range mismatch. +- Context/raw-window/compression-cap mismatch. +- Model id or quant profile mismatch. +- Missing output head when logits are requested. +- Worker reconnect before shard fetch. +- Stale worker session after route rebuild. +- Incomplete or stale incremental KV return chunks. diff --git a/artifacts/issue-304/logit-comparisons.md b/artifacts/issue-304/logit-comparisons.md index b09e7cc6e..4595e146d 100644 --- a/artifacts/issue-304/logit-comparisons.md +++ b/artifacts/issue-304/logit-comparisons.md @@ -115,7 +115,23 @@ The new `tests/issue304_phase2_handoff` helper compared: - Phase 2 removes staging and initial restore correctness as leading suspects. - The mixed-backend drift still shows up only after resumed decode evolution begins. -- The fact that greedy continuation matched for 16 tokens while forced-trace drift still appeared means the drift is currently too small to perturb top-token choice in this sampled window, but it is still a real backend-resume mismatch. +- The fact that greedy continuation matched for 16 tokens while forced-trace drift still appeared means the drift is currently too small to perturb top-token choice in this sampled window. +- Phase 3 should not require bit-exact cross-engine logits. It should decide whether the distributed-prefill-to-local path matches fully local inference on the same decode backend and satisfies the existing official-vector/local-golden correctness envelope. + +## Phase 3 planned official/local parity + +The Phase 3 logit comparison target is: + +1. fully local inference on the decode backend +2. distributed prefill + merged `DSV4` + local decode on that same backend +3. official API top-logprob vectors in `tests/test-vectors/official.vec` +4. local golden-vector drift thresholds where full local logits are available + +Acceptance should use the existing local correctness semantics: + +- `./ds4_test --logprob-vectors` for official selected-token and top-logprob agreement, allowing the existing skipped `long_memory_archive` caveat. +- `./ds4_test --local-golden-vectors` for local top-k/logit drift regression. +- A new or extended issue-304 harness should compare distributed-handoff outputs against fully local outputs before classifying any cross-engine forced-logit drift as a defect. ## Baseline surrounding checks diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index 822963d2c..2fc0aa51e 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -9,8 +9,8 @@ This file tracks phase-wise findings for the staged investigation in `PLAN.md`. | Phase 0 | Complete | The DGX/Mac baseline ran end-to-end, and the earlier merged-`DSV4` stage failure was narrowed to a worker/coordinator `ctx` mismatch rather than a backend or route-format incompatibility. | | Phase 1 | Complete | The payload resume matrix is now filled: `Metal -> Metal`, `CUDA -> CUDA`, and `Metal -> CUDA` passed, while `CUDA -> Metal` preserved restore-point logits but diverged during subsequent greedy decode. | | Phase 2 | Complete | Distributed prefill -> merged `DSV4` -> fresh local Metal load now validates end-to-end on the DGX/Mac route. Handoff logits and 16-token greedy continuation matched, but forced-token logits still diverged at the first post-load eval step. | -| Phase 3 | Not started | Engine residency and same-process local decode feasibility are still open. | -| Later optimization phases | Not started | No work yet on pipelined KV return or user-facing workflow. | +| Phase 3 | Not started | Re-scoped to prove distributed-prefill-to-local decode matches fully local inference on the same decode engine against the official-vector/local-golden correctness surfaces, while classifying any remaining cross-engine forced-logit drift. | +| Later phases | Not started | Engine residency, user-facing workflow, and pipelined KV return remain open after Phase 3 classification. | ## Phase 0: Establish distributed baseline @@ -160,7 +160,7 @@ The original broad conclusion was too strong. The mixed Metal/CUDA route does su The goal is distributed prefill with local generation after handoff. Phase 1 reduces the problem to the real remaining unknowns: - distributed gather/load correctness, -- the root cause of `CUDA -> Metal` post-restore decode divergence, +- classification of `CUDA -> Metal` post-restore decode divergence against same-backend and official/local baselines, - and engine residency / local decode feasibility. That means Phase 2 can use merged `DSV4` handoff as the first end-to-end correctness experiment with much lower ambiguity. @@ -212,7 +212,7 @@ The intended correctness check was: - The helper compared `16` greedy tokens. - Result: exact match for all `16` steps. -4. The remaining defect is still post-load decode evolution, not stage/load correctness. +4. The remaining observed drift is still post-load decode evolution, not stage/load correctness. - Forced-token trace still diverged at the first identical post-load eval step: - first bad step: `1` - forced token before bad step: `5` @@ -229,26 +229,30 @@ The intended correctness check was: ### Implication -Phase 2 is no longer blocked on distributed gather, payload staging, or initial local resume. The feature concept is viable through the existing merged `DSV4` path. The remaining technical problem is the already-familiar mixed-backend post-load decode drift, now reproduced after a real distributed prefill rather than only the smaller Phase 1 payload matrix case. +Phase 2 is no longer blocked on distributed gather, payload staging, or initial local resume. The feature concept is viable through the existing merged `DSV4` path. The remaining question is not whether every backend can produce bit-identical logits after resume; engine implementations can legitimately differ. The next question is whether distributed prefill followed by local decode matches fully local inference on the same decode backend and stays inside the existing official-vector/local-golden acceptance envelope. ### Open question carried forward - `CUDA -> Metal` restores the immediate logits exactly, but diverges after the first identical forced post-load eval token. - This remains unresolved and should be treated as a later investigation into post-load decode evolution, not as a blocker for considering Phases 0 and 1 complete. -## Phase 3: Engine layer residency and local decode feasibility +## Phase 3: Handoff equivalence and drift isolation ### Current status -Not run yet. +Not started. -### What Phase 1 suggests +### Revised goal -If Phase 2 succeeds only by creating a second full local engine, the remaining work is probably not payload correctness. It is likely a residency and execution-shape problem. +- Use `tests/test-vectors/official.vec` and the existing local golden-vector checks as the correctness reference. +- Compare distributed-prefill-to-local decode against fully local inference on the same decode backend before treating cross-engine drift as a defect. +- Keep forced-token traces as diagnostic evidence, but do not require bit-exact cross-engine logits if selected tokens and official/local-golden gates remain stable. -### Main decision to resolve later +### Acceptance direction -Whether the coordinator can keep full local decode weights resident while still participating in distributed prefill using only its owned layer slice. +- Distributed prefill -> merged `DSV4` -> local decode should match fully local inference on the same decode backend for the official-vector prompt set. +- The same path should satisfy the existing official top-logprob tolerance and local-golden drift thresholds, allowing the already documented `long_memory_archive` API/official graph caveat. +- Remaining `CUDA -> Metal` forced-logit drift should be classified as accepted backend variance only after the same-backend distributed handoff checks pass. ## Pointers diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md index 445dc6596..fb9bcd312 100644 --- a/artifacts/issue-304/runbook.md +++ b/artifacts/issue-304/runbook.md @@ -142,6 +142,22 @@ ssh dgx-direct 'cd ~/ds4 && ./tests/issue304_phase1_matrix --mode load-check --m make test ``` +### Official/local vector checks + +Strict local official top-logprob check: + +```sh +./ds4_test --logprob-vectors +``` + +Local golden-vector drift check: + +```sh +./ds4_test --local-golden-vectors +``` + +Phase 3 should use these as the reference envelope for distributed-prefill-to-local decode. The hosted official API exposes top-logprobs, not full logits, so official-vector comparison is about selected-token and top-logprob agreement rather than bit-exact logit equality. + ### Phase 2 DGX/Mac handoff validation Start the DGX worker with the same `ctx` as the coordinator: @@ -194,6 +210,19 @@ Observed authoritative Phase 2 result: - `rms=0.0802887231` - `max_abs=0.507860184` +### Phase 3 planned validation + +Phase 3 should run the official-vector prompt set through both: + +- fully local inference on the decode backend +- distributed prefill -> merged `DSV4` -> local decode on the same backend + +Acceptance: + +- distributed-handoff output matches fully local output on the same decode backend within the same top-token/top-logprob behavior used by `--logprob-vectors` +- distributed-handoff output remains inside the local-golden drift envelope where full local logits are available +- any remaining `CUDA -> Metal` forced-logit drift is classified separately as backend variance unless it causes same-backend handoff parity or official/local-vector checks to fail + ## Runtime knobs used by `--local-payload-resume` - `DS4_METAL_PREFILL_CHUNK=4096` diff --git a/artifacts/issue-304/topology-decoupling.md b/artifacts/issue-304/topology-decoupling.md new file mode 100644 index 000000000..bb5db9487 --- /dev/null +++ b/artifacts/issue-304/topology-decoupling.md @@ -0,0 +1,28 @@ +# Issue #304 Topology Decoupling + +This artifact records follow-on topology work after the first correct local-generation handoff is proven. + +## Current Status + +- Topology decoupling is deferred until after the Phase 3 correctness classification and Phase 4 residency decision. +- The current coordinator-first route model remains acceptable for proving the first local-generation handoff unless Phase 4 shows it blocks a viable residency design. + +## Current Constraints + +- The coordinator currently owns control-plane state, prompt/session state, and the first route slice. +- The route is expressed as ordered layer ownership, commonly `0:M -> N:output`. +- `N:output` makes the final worker own output/logit production. +- Local decode placement is not yet an explicit route property. +- KV return destination is coupled to the coordinator/session flow. + +## Desired Future Properties + +- Control-plane coordination can be separated from execution role. +- Prefill layer ownership can be assigned to the fastest available devices. +- Local decode can be assigned to the machine with full model/KV residency and appropriate memory bandwidth. +- Output-head/logit ownership can be expressed explicitly instead of only through `N:output`. +- KV return destination can differ from the final prefill worker and from the control coordinator. + +## Phase 8 Direction + +Phase 8 should document whether topology flexibility remains deferred or requires protocol/API changes. It should preserve compatibility with the current coordinator-first workflow as shorthand if new topology controls are added. From 85c13af2fe420823cdb9842e219f62bbabae33d5 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Thu, 4 Jun 2026 20:11:53 +0100 Subject: [PATCH 05/17] phase 3.5, route-specificity --- Makefile | 22 +- PLAN.md | 152 ++ artifacts/issue-304/compatibility-matrix.md | 13 +- artifacts/issue-304/decision-log.md | 72 + artifacts/issue-304/failure-cases.md | 47 +- artifacts/issue-304/logit-comparisons.md | 121 +- artifacts/issue-304/perf-breakdown.md | 98 + artifacts/issue-304/phase35/raw/.gitignore | 1 + ...ocal-golden-long_story_4096-r1-rep1.ndjson | 20 + ...ocal-golden-long_story_4096-r1-rep2.ndjson | 20 + ...ocal-golden-long_story_4096-r1-rep3.ndjson | 20 + ...ocal-golden-long_story_4096-r1-rep4.ndjson | 20 + ...ocal-golden-long_story_4096-r1-rep5.ndjson | 20 + ...ocal-golden-long_story_4096-r2-rep1.ndjson | 10 + ...ocal-golden-long_story_4096-r2-rep2.ndjson | 10 + ...ocal-golden-long_story_4096-r2-rep3.ndjson | 10 + ...ocal-golden-long_story_4096-r2-rep4.ndjson | 10 + ...ocal-golden-long_story_4096-r2-rep5.ndjson | 10 + ...ocal-golden-long_story_4096-r3-rep1.ndjson | 45 + ...-golden-long_story_4096-r3-rep1.worker.log | 12 + ...ocal-golden-long_story_4096-r3-rep2.ndjson | 45 + ...-golden-long_story_4096-r3-rep2.worker.log | 12 + ...ocal-golden-long_story_4096-r3-rep3.ndjson | 45 + ...-golden-long_story_4096-r3-rep3.worker.log | 12 + ...ocal-golden-long_story_4096-r3-rep4.ndjson | 45 + ...-golden-long_story_4096-r3-rep4.worker.log | 12 + ...ocal-golden-long_story_4096-r3-rep5.ndjson | 45 + ...-golden-long_story_4096-r3-rep5.worker.log | 12 + ...ocal-golden-long_story_4096-r4-rep1.ndjson | 41 + ...ocal-golden-long_story_4096-r4-rep2.ndjson | 41 + ...ocal-golden-long_story_4096-r4-rep3.ndjson | 41 + ...ocal-golden-long_story_4096-r4-rep4.ndjson | 41 + ...ocal-golden-long_story_4096-r4-rep5.ndjson | 41 + ...ocal-golden-long_story_4096-r5-rep1.ndjson | 10 + ...olden-long_story_4096-r5-rep1.stage.ndjson | 45 + ...-golden-long_story_4096-r5-rep1.worker.log | 13 + ...ocal-golden-long_story_4096-r5-rep2.ndjson | 10 + ...olden-long_story_4096-r5-rep2.stage.ndjson | 45 + ...-golden-long_story_4096-r5-rep2.worker.log | 13 + ...ocal-golden-long_story_4096-r5-rep3.ndjson | 10 + ...olden-long_story_4096-r5-rep3.stage.ndjson | 45 + ...-golden-long_story_4096-r5-rep3.worker.log | 13 + ...ocal-golden-long_story_4096-r5-rep4.ndjson | 10 + ...olden-long_story_4096-r5-rep4.stage.ndjson | 45 + ...-golden-long_story_4096-r5-rep4.worker.log | 13 + ...ocal-golden-long_story_4096-r5-rep5.ndjson | 10 + ...olden-long_story_4096-r5-rep5.stage.ndjson | 45 + ...-golden-long_story_4096-r5-rep5.worker.log | 13 + ...ocal-golden-long_story_4096-r6-rep1.ndjson | 20 + ...olden-long_story_4096-r6-rep1.stage.ndjson | 41 + ...ocal-golden-long_story_4096-r6-rep2.ndjson | 20 + ...olden-long_story_4096-r6-rep2.stage.ndjson | 41 + ...ocal-golden-long_story_4096-r6-rep3.ndjson | 20 + ...olden-long_story_4096-r6-rep3.stage.ndjson | 41 + ...ocal-golden-long_story_4096-r6-rep4.ndjson | 20 + ...olden-long_story_4096-r6-rep4.stage.ndjson | 41 + ...ocal-golden-long_story_4096-r6-rep5.ndjson | 20 + ...olden-long_story_4096-r6-rep5.stage.ndjson | 41 + .../official-long_code_audit-r1-rep1.ndjson | 20 + .../official-long_code_audit-r1-rep2.ndjson | 20 + .../official-long_code_audit-r1-rep3.ndjson | 20 + .../official-long_code_audit-r1-rep4.ndjson | 20 + .../official-long_code_audit-r1-rep5.ndjson | 20 + .../official-long_code_audit-r2-rep1.ndjson | 10 + .../official-long_code_audit-r2-rep2.ndjson | 10 + .../official-long_code_audit-r2-rep3.ndjson | 10 + .../official-long_code_audit-r2-rep4.ndjson | 10 + .../official-long_code_audit-r2-rep5.ndjson | 10 + .../official-long_code_audit-r3-rep1.ndjson | 40 + ...fficial-long_code_audit-r3-rep1.worker.log | 12 + .../official-long_code_audit-r3-rep2.ndjson | 40 + ...fficial-long_code_audit-r3-rep2.worker.log | 12 + .../official-long_code_audit-r3-rep3.ndjson | 40 + ...fficial-long_code_audit-r3-rep3.worker.log | 12 + .../official-long_code_audit-r3-rep4.ndjson | 40 + ...fficial-long_code_audit-r3-rep4.worker.log | 12 + .../official-long_code_audit-r3-rep5.ndjson | 40 + ...fficial-long_code_audit-r3-rep5.worker.log | 12 + .../official-long_code_audit-r4-rep1.ndjson | 36 + .../official-long_code_audit-r4-rep2.ndjson | 36 + .../official-long_code_audit-r4-rep3.ndjson | 36 + .../official-long_code_audit-r4-rep4.ndjson | 36 + .../official-long_code_audit-r4-rep5.ndjson | 36 + .../official-long_code_audit-r5-rep1.ndjson | 10 + ...icial-long_code_audit-r5-rep1.stage.ndjson | 40 + ...fficial-long_code_audit-r5-rep1.worker.log | 13 + .../official-long_code_audit-r5-rep2.ndjson | 10 + ...icial-long_code_audit-r5-rep2.stage.ndjson | 40 + ...fficial-long_code_audit-r5-rep2.worker.log | 13 + .../official-long_code_audit-r5-rep3.ndjson | 10 + ...icial-long_code_audit-r5-rep3.stage.ndjson | 40 + ...fficial-long_code_audit-r5-rep3.worker.log | 13 + .../official-long_code_audit-r5-rep4.ndjson | 10 + ...icial-long_code_audit-r5-rep4.stage.ndjson | 40 + ...fficial-long_code_audit-r5-rep4.worker.log | 13 + .../official-long_code_audit-r5-rep5.ndjson | 10 + ...icial-long_code_audit-r5-rep5.stage.ndjson | 40 + ...fficial-long_code_audit-r5-rep5.worker.log | 13 + .../official-long_code_audit-r6-rep1.ndjson | 20 + ...icial-long_code_audit-r6-rep1.stage.ndjson | 36 + .../official-long_code_audit-r6-rep2.ndjson | 20 + ...icial-long_code_audit-r6-rep2.stage.ndjson | 36 + .../official-long_code_audit-r6-rep3.ndjson | 20 + ...icial-long_code_audit-r6-rep3.stage.ndjson | 36 + .../official-long_code_audit-r6-rep4.ndjson | 20 + ...icial-long_code_audit-r6-rep4.stage.ndjson | 36 + .../official-long_code_audit-r6-rep5.ndjson | 20 + ...icial-long_code_audit-r6-rep5.stage.ndjson | 36 + ...icial-short_code_completion-r1-rep1.ndjson | 20 + ...icial-short_code_completion-r1-rep2.ndjson | 20 + ...icial-short_code_completion-r1-rep3.ndjson | 20 + ...icial-short_code_completion-r1-rep4.ndjson | 20 + ...icial-short_code_completion-r1-rep5.ndjson | 20 + ...icial-short_code_completion-r2-rep1.ndjson | 10 + ...icial-short_code_completion-r2-rep2.ndjson | 10 + ...icial-short_code_completion-r2-rep3.ndjson | 10 + ...icial-short_code_completion-r2-rep4.ndjson | 10 + ...icial-short_code_completion-r2-rep5.ndjson | 10 + ...icial-short_code_completion-r3-rep1.ndjson | 23 + ...l-short_code_completion-r3-rep1.worker.log | 12 + ...icial-short_code_completion-r3-rep2.ndjson | 23 + ...l-short_code_completion-r3-rep2.worker.log | 12 + ...icial-short_code_completion-r3-rep3.ndjson | 23 + ...l-short_code_completion-r3-rep3.worker.log | 12 + ...icial-short_code_completion-r3-rep4.ndjson | 23 + ...l-short_code_completion-r3-rep4.worker.log | 12 + ...icial-short_code_completion-r3-rep5.ndjson | 23 + ...l-short_code_completion-r3-rep5.worker.log | 12 + ...icial-short_code_completion-r4-rep1.ndjson | 19 + ...icial-short_code_completion-r4-rep2.ndjson | 19 + ...icial-short_code_completion-r4-rep3.ndjson | 19 + ...icial-short_code_completion-r4-rep4.ndjson | 19 + ...icial-short_code_completion-r4-rep5.ndjson | 19 + ...icial-short_code_completion-r5-rep1.ndjson | 10 + ...short_code_completion-r5-rep1.stage.ndjson | 23 + ...l-short_code_completion-r5-rep1.worker.log | 13 + ...icial-short_code_completion-r5-rep2.ndjson | 10 + ...short_code_completion-r5-rep2.stage.ndjson | 23 + ...l-short_code_completion-r5-rep2.worker.log | 13 + ...icial-short_code_completion-r5-rep3.ndjson | 10 + ...short_code_completion-r5-rep3.stage.ndjson | 23 + ...l-short_code_completion-r5-rep3.worker.log | 13 + ...icial-short_code_completion-r5-rep4.ndjson | 10 + ...short_code_completion-r5-rep4.stage.ndjson | 23 + ...l-short_code_completion-r5-rep4.worker.log | 13 + ...icial-short_code_completion-r5-rep5.ndjson | 10 + ...short_code_completion-r5-rep5.stage.ndjson | 23 + ...l-short_code_completion-r5-rep5.worker.log | 13 + ...icial-short_code_completion-r6-rep1.ndjson | 20 + ...short_code_completion-r6-rep1.stage.ndjson | 19 + ...icial-short_code_completion-r6-rep2.ndjson | 20 + ...short_code_completion-r6-rep2.stage.ndjson | 19 + ...icial-short_code_completion-r6-rep3.ndjson | 20 + ...short_code_completion-r6-rep3.stage.ndjson | 19 + ...icial-short_code_completion-r6-rep4.ndjson | 20 + ...short_code_completion-r6-rep4.stage.ndjson | 19 + ...icial-short_code_completion-r6-rep5.ndjson | 20 + ...short_code_completion-r6-rep5.stage.ndjson | 19 + ...official-short_italian_fact-r1-rep1.ndjson | 20 + ...official-short_italian_fact-r1-rep2.ndjson | 20 + ...official-short_italian_fact-r1-rep3.ndjson | 20 + ...official-short_italian_fact-r1-rep4.ndjson | 20 + ...official-short_italian_fact-r1-rep5.ndjson | 20 + ...official-short_italian_fact-r2-rep1.ndjson | 10 + ...official-short_italian_fact-r2-rep2.ndjson | 10 + ...official-short_italian_fact-r2-rep3.ndjson | 10 + ...official-short_italian_fact-r2-rep4.ndjson | 10 + ...official-short_italian_fact-r2-rep5.ndjson | 10 + ...official-short_italian_fact-r3-rep1.ndjson | 23 + ...cial-short_italian_fact-r3-rep1.worker.log | 12 + ...official-short_italian_fact-r3-rep2.ndjson | 23 + ...cial-short_italian_fact-r3-rep2.worker.log | 12 + ...official-short_italian_fact-r3-rep3.ndjson | 23 + ...cial-short_italian_fact-r3-rep3.worker.log | 12 + ...official-short_italian_fact-r3-rep4.ndjson | 23 + ...cial-short_italian_fact-r3-rep4.worker.log | 12 + ...official-short_italian_fact-r3-rep5.ndjson | 23 + ...cial-short_italian_fact-r3-rep5.worker.log | 12 + ...official-short_italian_fact-r4-rep1.ndjson | 19 + ...official-short_italian_fact-r4-rep2.ndjson | 19 + ...official-short_italian_fact-r4-rep3.ndjson | 19 + ...official-short_italian_fact-r4-rep4.ndjson | 19 + ...official-short_italian_fact-r4-rep5.ndjson | 19 + ...official-short_italian_fact-r5-rep1.ndjson | 10 + ...al-short_italian_fact-r5-rep1.stage.ndjson | 23 + ...cial-short_italian_fact-r5-rep1.worker.log | 13 + ...official-short_italian_fact-r5-rep2.ndjson | 10 + ...al-short_italian_fact-r5-rep2.stage.ndjson | 23 + ...cial-short_italian_fact-r5-rep2.worker.log | 13 + ...official-short_italian_fact-r5-rep3.ndjson | 10 + ...al-short_italian_fact-r5-rep3.stage.ndjson | 23 + ...cial-short_italian_fact-r5-rep3.worker.log | 13 + ...official-short_italian_fact-r5-rep4.ndjson | 10 + ...al-short_italian_fact-r5-rep4.stage.ndjson | 23 + ...cial-short_italian_fact-r5-rep4.worker.log | 13 + ...official-short_italian_fact-r5-rep5.ndjson | 10 + ...al-short_italian_fact-r5-rep5.stage.ndjson | 23 + ...cial-short_italian_fact-r5-rep5.worker.log | 13 + ...official-short_italian_fact-r6-rep1.ndjson | 20 + ...al-short_italian_fact-r6-rep1.stage.ndjson | 19 + ...official-short_italian_fact-r6-rep2.ndjson | 20 + ...al-short_italian_fact-r6-rep2.stage.ndjson | 19 + ...official-short_italian_fact-r6-rep3.ndjson | 20 + ...al-short_italian_fact-r6-rep3.stage.ndjson | 19 + ...official-short_italian_fact-r6-rep4.ndjson | 20 + ...al-short_italian_fact-r6-rep4.stage.ndjson | 19 + ...official-short_italian_fact-r6-rep5.ndjson | 20 + ...al-short_italian_fact-r6-rep5.stage.ndjson | 19 + ...icial-short_reasoning_plain-r1-rep1.ndjson | 20 + ...icial-short_reasoning_plain-r1-rep2.ndjson | 20 + ...icial-short_reasoning_plain-r1-rep3.ndjson | 20 + ...icial-short_reasoning_plain-r1-rep4.ndjson | 20 + ...icial-short_reasoning_plain-r1-rep5.ndjson | 20 + ...icial-short_reasoning_plain-r2-rep1.ndjson | 10 + ...icial-short_reasoning_plain-r2-rep2.ndjson | 10 + ...icial-short_reasoning_plain-r2-rep3.ndjson | 10 + ...icial-short_reasoning_plain-r2-rep4.ndjson | 10 + ...icial-short_reasoning_plain-r2-rep5.ndjson | 10 + ...icial-short_reasoning_plain-r3-rep1.ndjson | 20 + ...l-short_reasoning_plain-r3-rep1.worker.log | 12 + ...icial-short_reasoning_plain-r3-rep2.ndjson | 20 + ...l-short_reasoning_plain-r3-rep2.worker.log | 12 + ...icial-short_reasoning_plain-r3-rep3.ndjson | 20 + ...l-short_reasoning_plain-r3-rep3.worker.log | 12 + ...icial-short_reasoning_plain-r3-rep4.ndjson | 20 + ...l-short_reasoning_plain-r3-rep4.worker.log | 12 + ...icial-short_reasoning_plain-r3-rep5.ndjson | 20 + ...l-short_reasoning_plain-r3-rep5.worker.log | 12 + ...icial-short_reasoning_plain-r4-rep1.ndjson | 16 + ...icial-short_reasoning_plain-r4-rep2.ndjson | 16 + ...icial-short_reasoning_plain-r4-rep3.ndjson | 16 + ...icial-short_reasoning_plain-r4-rep4.ndjson | 16 + ...icial-short_reasoning_plain-r4-rep5.ndjson | 16 + ...icial-short_reasoning_plain-r5-rep1.ndjson | 10 + ...short_reasoning_plain-r5-rep1.stage.ndjson | 20 + ...l-short_reasoning_plain-r5-rep1.worker.log | 13 + ...icial-short_reasoning_plain-r5-rep2.ndjson | 10 + ...short_reasoning_plain-r5-rep2.stage.ndjson | 20 + ...l-short_reasoning_plain-r5-rep2.worker.log | 13 + ...icial-short_reasoning_plain-r5-rep3.ndjson | 10 + ...short_reasoning_plain-r5-rep3.stage.ndjson | 20 + ...l-short_reasoning_plain-r5-rep3.worker.log | 13 + ...icial-short_reasoning_plain-r5-rep4.ndjson | 10 + ...short_reasoning_plain-r5-rep4.stage.ndjson | 20 + ...l-short_reasoning_plain-r5-rep4.worker.log | 13 + ...icial-short_reasoning_plain-r5-rep5.ndjson | 10 + ...short_reasoning_plain-r5-rep5.stage.ndjson | 20 + ...l-short_reasoning_plain-r5-rep5.worker.log | 13 + ...icial-short_reasoning_plain-r6-rep1.ndjson | 20 + ...short_reasoning_plain-r6-rep1.stage.ndjson | 16 + ...icial-short_reasoning_plain-r6-rep2.ndjson | 20 + ...short_reasoning_plain-r6-rep2.stage.ndjson | 16 + ...icial-short_reasoning_plain-r6-rep3.ndjson | 20 + ...short_reasoning_plain-r6-rep3.stage.ndjson | 16 + ...icial-short_reasoning_plain-r6-rep4.ndjson | 20 + ...short_reasoning_plain-r6-rep4.stage.ndjson | 16 + ...icial-short_reasoning_plain-r6-rep5.ndjson | 20 + ...short_reasoning_plain-r6-rep5.stage.ndjson | 16 + .../phase35/raw/phase35-summary.ndjson | 6 + artifacts/issue-304/research-notes.md | 133 +- artifacts/issue-304/runbook.md | 184 +- artifacts/issue-304/shard-metadata.md | 78 + tests/issue304_phase35_matrix.py | 535 +++++ tests/issue304_phase35_vectors.c | 1742 +++++++++++++++++ tests/issue304_phase3_vectors.c | 1309 +++++++++++++ 265 files changed, 9431 insertions(+), 27 deletions(-) create mode 100644 artifacts/issue-304/phase35/raw/.gitignore create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.worker.log create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.ndjson create mode 100644 artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.stage.ndjson create mode 100644 artifacts/issue-304/phase35/raw/phase35-summary.ndjson create mode 100644 tests/issue304_phase35_matrix.py create mode 100644 tests/issue304_phase35_vectors.c create mode 100644 tests/issue304_phase3_vectors.c diff --git a/Makefile b/Makefile index 3c3183b04..95ba33b33 100644 --- a/Makefile +++ b/Makefile @@ -230,6 +230,26 @@ else $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase2_handoff.o $(CORE_OBJS) $(CUDA_LDLIBS) endif +tests/issue304_phase3_vectors.o: tests/issue304_phase3_vectors.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase3_vectors.c + +tests/issue304_phase3_vectors: tests/issue304_phase3_vectors.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase3_vectors.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase3_vectors.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + +tests/issue304_phase35_vectors.o: tests/issue304_phase35_vectors.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase35_vectors.c + +tests/issue304_phase35_vectors: tests/issue304_phase35_vectors.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase35_vectors.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase35_vectors.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + issue304-phase0-local: ds4 tests/issue304_phase0_local ./tests/issue304_phase0_local @@ -249,4 +269,4 @@ q4k-dot-test: tests/test_q4k_dot.c ./tests/test_q4k_dot clean: - rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o tests/issue304_phase2_handoff tests/issue304_phase2_handoff.o + rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o tests/issue304_phase2_handoff tests/issue304_phase2_handoff.o tests/issue304_phase3_vectors tests/issue304_phase3_vectors.o tests/issue304_phase35_vectors tests/issue304_phase35_vectors.o diff --git a/PLAN.md b/PLAN.md index daf4dc53a..0a3c7a099 100644 --- a/PLAN.md +++ b/PLAN.md @@ -464,6 +464,158 @@ Exit gate: - Any remaining `CUDA -> Metal` forced-token drift is classified as accepted engine/backend variance, or is localized as a specific handoff defect with a reproduction. - If official-vector or local-golden checks fail only for distributed handoff, stop before Phase 4 and fix that handoff-specific mismatch. +### Phase 3.5: Six-route variance matrix and worst@5 envelope + +Goal: + +- Why: Phase 3 showed that one distributed-prefill-to-local-decode route can drift materially from a fresh same-backend local baseline on longer prompts. That result is not enough to separate three different causes cleanly: + - ordinary `CUDA <-> Metal` implementation variance, + - variance introduced by distributed generation itself, + - variance introduced by distributed prefill followed by resumed generation from a merged `DSV4` payload. +- What: build a like-for-like measurement rig that runs the same prompt sets across six execution routes, records both official top-logprob variance and local logit/greedy variance, and reports `worst@5` for every case and route. + +Required route matrix: + +- `1.` pure local `CUDA` prefill + generation +- `2.` pure local `Metal` prefill + generation +- `3.` distributed prefill + generation `CUDA -> Metal` +- `4.` distributed prefill + generation `Metal -> CUDA` +- `5.` distributed prefill `CUDA -> Metal`, then resumed pure `Metal` generation from merged `DSV4` +- `6.` distributed prefill `Metal -> CUDA`, then resumed pure `CUDA` generation from merged `DSV4` + +Measurement contract: + +- Every route must run with `--repeat 5` semantics and emit: + - one result record per repeat, + - one `worst@5` summary record per case. +- Every official-vector case must emit: + - selected-token pass/fail, + - missing official top-token count, + - max logprob delta, + - route metadata, + - timing metadata. +- Every local variance case must emit: + - top1 match or first mismatch step, + - top5/top20/top64 overlap, + - RMS drift, + - max absolute drift, + - top20 max absolute drift, + - greedy token divergence, + - route metadata, + - timing metadata. +- Each distributed or resumed route must also record: + - coordinator host/backend, + - worker host/backend, + - layer split, + - `ctx`, + - `prefill_chunk`, + - `prefill_window`, + - `activation_bits`, + - `prefill_cap`, + - payload bytes where applicable, + - model hash on both hosts. + +Expected artifacts: + +- Update `artifacts/issue-304/compatibility-matrix.md` with one row per route group and context bucket, using `worst@5` as the authoritative summary. +- Update `artifacts/issue-304/logit-comparisons.md` with: + - official-vector `worst@5` variance tables for all six routes, + - local/golden `worst@5` variance tables for all six routes, + - explicit comparisons between: + - pure local `CUDA` vs pure local `Metal`, + - distributed generation vs pure local on the same generation backend, + - resumed generation vs pure local on the same generation backend. +- Update `artifacts/issue-304/perf-breakdown.md` with route-specific prefill, staging, load, and generation timing envelopes from the same runs. +- Update `artifacts/issue-304/shard-metadata.md` with the authoritative route/layout metadata for every distributed and resumed route. +- Update `artifacts/issue-304/runbook.md` with exact local and remote commands, including source sync, remote build, payload copy, worker startup, and one-shot repeat structure. +- Update `artifacts/issue-304/research-notes.md` with the classification outcome: + - whether resumed generation adds variance beyond pure backend differences, + - whether distributed generation adds variance beyond pure local generation, + - whether any route is acceptable under the official and local envelopes. +- Update `artifacts/issue-304/decision-log.md` with the final interpretation of the six-route matrix. +- Update `artifacts/issue-304/failure-cases.md` with any route/case combination that remains rejected after `worst@5`. + +Code touchpoints: + +- `tests/issue304_phase1_matrix.c` + - Reuse for pure local save/load, forced-token trace capture, and same-prompt local backend comparisons. +- `tests/issue304_phase2_handoff.c` + - Reuse for distributed prefill + generation and staged merged-payload export. +- `tests/issue304_phase3_vectors.c` + - Reuse its official/local-golden parsing, parity metrics, and `worst@5` summary shape as the base reporting contract. +- New helper: `tests/issue304_phase35_vectors.c` + - Add a single-host vector runner with three modes: + - `local` + - `distributed` + - `payload` + - It must support both: + - `--suite official` + - `--suite local-golden` + - It must emit one stable NDJSON record schema across all three modes. +- New orchestrator: `tests/issue304_phase35_matrix.py` + - Own cross-host orchestration rather than embedding SSH/rsync logic into the C helpers. + - Responsibilities: + - compare local and remote GGUF hashes before every run, + - sync source to `dgx-direct:~/ds4` when code differs, + - build local and remote helpers, + - start/stop opposite-host workers, + - run five one-shot repeats per case to avoid coordinator port reuse races, + - copy merged payloads between hosts for resumed routes, + - collect raw NDJSON into an artifact directory. +- `Makefile` + - Add build targets for `tests/issue304_phase35_vectors`. + +Execution strategy: + +- Start by standardizing measurement shape, not by expanding route logic inside the existing helpers. +- Keep cross-host control in the orchestrator and keep the C helper focused on: + - tokenization, + - official/golden checks, + - logit parity metrics, + - route-local session control. +- Use the current trusted helpers to bootstrap the new runner: + - `issue304_phase3_vectors` defines the official/golden comparison rules, + - `issue304_phase2_handoff` defines distributed route setup and payload staging, + - `issue304_phase1_matrix` defines the local forced-trace comparison shape. +- Treat one-shot coordinator runs with short pauses as mandatory for distributed routes; do not regress to a persistent in-process repeat loop for route-level validation. + +Work items: + +- Add `tests/issue304_phase35_vectors.c` with: + - `local` mode for pure local prefill + generation on the host backend, + - `distributed` mode for distributed prefill + generation on the coordinator host, + - `payload` mode for loading a merged `DSV4` payload and continuing generation on the host backend, + - official and local-golden suite support, + - per-repeat and `worst@5` NDJSON output. +- Add `tests/issue304_phase35_matrix.py` to orchestrate: + - route selection, + - local/remote build, + - worker lifecycle, + - payload shipping, + - result collection. +- Define a route manifest inside the orchestrator for the six required paths, including authoritative host role, backend role, layer split, and payload direction. +- Reuse the current context buckets as the first required coverage set: + - `4096` + - `5000` + - `16384` +- Run official vectors for all six routes where the route can produce normal token-by-token top-logprobs. +- Run local-golden and prompt-length variance checks for all six routes. +- Record a separate comparison table that normalizes each route against the pure local run on the same generation backend. +- Only after the rig works reliably should we consider broadening prompt coverage beyond the existing official/local-golden cases. + +Key questions: + +- Can the distributed-generation routes use the same official top-logprob comparison rules directly, or do they need a coordinator-local top-logprob extraction shim when the output owner is remote? +- Does the opposite-host resumed route require any payload normalization beyond the current merged `DSV4` file copy? +- Are there backend-specific environment constraints, such as `DS4_METAL_PREFILL_CHUNK`, that must become part of the route manifest rather than ad hoc runbook notes? +- Do any routes need distinct frontier definitions beyond the current official and local-golden prompt surfaces to make prompt-length variance comparisons fair? + +Exit gate: + +- We have authoritative `worst@5` results for all six routes across the required context buckets. +- Official top-logprob variance and local logit/greedy variance are both available in one consistent result schema. +- The evidence can answer, with numbers, whether resumed generation introduces materially more drift than pure `CUDA <-> Metal` variance and whether distributed generation introduces additional drift beyond pure local generation. + ### Phase 4: Coordinator residency and workflow viability Goal: diff --git a/artifacts/issue-304/compatibility-matrix.md b/artifacts/issue-304/compatibility-matrix.md index baed71007..76afe267e 100644 --- a/artifacts/issue-304/compatibility-matrix.md +++ b/artifacts/issue-304/compatibility-matrix.md @@ -26,7 +26,16 @@ | Date | Commit | Model | Route | Validation path | Result | Notes | | --- | --- | --- | --- | --- | --- | --- | -| Pending | Pending | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output` | official-vector prompts -> distributed prefill -> merged `DSV4` -> local decode, compared against fully local inference and `tests/test-vectors/official.vec` | Not run | Phase 3 should classify whether the Phase 2 forced-logit drift is acceptable engine variance by proving same-backend distributed handoff parity with fully local inference and existing official/local-golden gates. | +| 2026-06-04 | local working tree from `f7a0baa`, synced to `dgx-direct:~/ds4` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output`, worker `ctx=4096`, worker `DS4_METAL_PREFILL_CHUNK=2048` | official vectors `ctx=4096`, 5 one-shot repeats, same-backend Metal baseline vs distributed-prefill handoff | Fail | Official gate passed on every run, but same-backend parity did not: `short_code_completion` worst@5 `top20=17/20`, `top64=62/64`, `rms=0.356403291`; `short_reasoning_plain` worst@5 `top20=20/20`, `top64=62/64`, `rms=0.327032387`. | +| 2026-06-04 | local working tree from `f7a0baa`, synced to `dgx-direct:~/ds4` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output`, worker `ctx=16384`, worker `DS4_METAL_PREFILL_CHUNK=2048` | official vectors `ctx=16384`, 5 one-shot repeats, same-backend Metal baseline vs distributed-prefill handoff | Fail | Official gate passed on every run, but same-backend parity stayed loose. Worst case was `long_code_audit` with worst@5 `top5=4/5`, `top20=15/20`, `top64=55/64`, `rms=0.876981199`, `max_abs=4.63468361`. | +| 2026-06-04 | local working tree from `f7a0baa`, synced to `dgx-direct:~/ds4` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `0:21 -> 22:output`, worker `ctx=5000`, worker `DS4_METAL_PREFILL_CHUNK=4096` | local golden `ctx=5000`, 5 one-shot repeats, same-backend Metal baseline vs distributed-prefill handoff | Fail | The resumed handoff still passed the local-golden fixture on every run, but same-backend continuation parity failed decisively. `long_story_4096` worst@5: `top5=3/5`, `top20=12/20`, `top64=46/64`, `rms=2.1708498`, `max_abs=12.3051796`. | + +## Phase 3.5: Six-route variance matrix + +| Date | Commit | Model | Route set | Validation path | Result | Notes | +| --- | --- | --- | --- | --- | --- | --- | +| 2026-06-04 | local working tree synced to `dgx-direct:~/ds4`, remote host `ilo037@10.77.0.2`, worker/runtime `--power 50` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | routes `1-6`: local CUDA, local Metal, distributed `CUDA -> Metal`, distributed `Metal -> CUDA`, resumed `CUDA -> Metal`, resumed `Metal -> CUDA` | official vectors, worst@5, all four official cases | Mixed | Official top-logprob behavior was route-dependent. `short_code_completion` failed official acceptance on routes `1`, `3`, and `5`, but passed on routes `2`, `4`, and `6`. All six routes passed official acceptance for `short_italian_fact`, `short_reasoning_plain`, and `long_code_audit`. Resumed routes still showed weaker parity than direct generation: e.g. `short_reasoning_plain` route `5` `top64=61/64`, `rms=0.382280707`; route `6` `top20=18/20`, `top64=59/64`, `rms=0.504765928`. | +| 2026-06-04 | local working tree synced to `dgx-direct:~/ds4`, remote host `ilo037@10.77.0.2`, worker/runtime `--power 50` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | routes `1-6` | local-golden frontier `long_story_4096`, worst@5 | Mixed | Route `2` pure local Metal did not satisfy the stored local-golden fixture (`top5=3/5`, `top20=16/20`, `top64=46/64`, `top20_max_abs=5.2168293`), while routes `1`, `3`, `4`, `5`, and `6` all passed the coarse golden gate. Same-route parity remained exact for direct generation routes `2-4`, but resumed routes stayed loose against their direct-route references: route `5` `top5=3/5`, `top20=13/20`, `top64=42/64`, `rms=2.14919782`; route `6` `top5=3/5`, `top20=14/20`, `top64=40/64`, `rms=1.60283542`. | ## Representative `DSVL` shard smoke @@ -43,3 +52,5 @@ - The only failing cell is `CUDA -> Metal`, and the current failure is narrower than a restore-point logit mismatch: the loaded Metal session starts from identical logits but diverges during subsequent greedy decode. - Forced-token follow-up on the same failing cell shows that logits already diverge after the first identical post-load eval token, so the failure is not explained by token-selection branching alone. - Phase 2 now confirms exact handoff checkpoint and matching greedy continuation over the sampled window. The first-step forced-trace drift on resumed Metal decode is a Phase 3 classification item, not automatically a failing compatibility result. +- Phase 3 now shows the resumed-decode drift is not only a cross-engine phenomenon. The distributed-prefill handoff differs from a fresh same-backend Metal baseline even when the official-vector gate and the local-golden fixture still pass. +- Phase 3.5 broadens that classification: short official prompts can look acceptable on some route/backend pairings while failing on others, but longer prompts and resumed payload routes still show materially weaker parity than direct generation paths. diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index 9bd6a32c5..6c1d3a872 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -124,3 +124,75 @@ Why this changes the next steps: - The next test should compare distributed-prefill-to-local decode against fully local decode on the same backend before assigning blame to CUDA/Metal engine differences. - If the same-backend comparison and official/local gates pass, Phase 3 can classify the forced-logit drift as acceptable backend variance and move on to residency/workflow planning. + +## 2026-06-04: Phase 3 rejects backend-variance-only classification + +Decision: + +- Do not classify the remaining resumed-decode drift as acceptable backend variance. +- Treat the current problem as a handoff-specific resumed-decode mismatch until proven otherwise. +- Keep Phase 4+ productization work blocked behind a same-backend parity fix or a tighter localization of the mismatch. + +Evidence: + +- Local and DGX GGUF hashes matched exactly before the runs: + - `efc7ed607ff27076e3e501fc3fefefa33c0ed8cf1eff483a2b7fdc0c2e616668` +- The new `tests/issue304_phase3_vectors` helper compared fresh local Metal decode against distributed-prefill -> merged `DSV4` -> local Metal decode. +- Official vector cases passed the existing selected-token/top-logprob gate on every run, but same-backend parity still drifted: + - `short_code_completion` worst@5: `top20=17/20`, `top64=62/64`, `rms=0.356403291` + - `short_italian_fact` worst@5: `top20=19/20`, `top64=62/64`, `rms=0.21716401` + - `long_code_audit` worst@5: `top5=4/5`, `top20=15/20`, `top64=55/64`, `rms=0.876981199`, `max_abs=4.63468361` +- The local-golden frontier showed the clearest rejection: + - the resumed handoff still passed the coarse local-golden fixture on all five runs + - but same-backend continuation parity for `long_story_4096` failed worst@5 with `top5=3/5`, `top20=12/20`, `top64=46/64`, `rms=2.1708498`, `max_abs=12.3051796` + +Why this changes the next steps: + +- Cross-engine `CUDA -> Metal` drift is no longer the main question. +- The more important defect is that a distributed-prefill checkpoint resumed on the same local decode backend does not evolve like a fresh local checkpoint. +- The next work should inspect post-load decode evolution on Metal after merged distributed prefill, rather than moving on to residency or UX work. + +Operational note: + +- Phase 3 also confirmed that merged `DSV4` staging requires `prefill_cap` alignment in addition to `ctx` alignment. +- The DGX worker had to be launched with: + - `DS4_METAL_PREFILL_CHUNK=2048` for the strict official-vector environment + - `DS4_METAL_PREFILL_CHUNK=4096` for the local-golden environment + +## 2026-06-04: Phase 3.5 broadens the drift classification across six routes + +Decision: + +- Keep treating resumed payload routes as suspect, but stop using the local-golden fixture as a local-Metal oracle. +- Treat official-vector acceptance as necessary but not sufficient. +- Split the remaining investigation into three independent buckets: + - backend-specific long-prompt generation variance, + - local-golden fixture drift, + - payload-resume-specific variance beyond those two baselines. + +Evidence: + +- Phase 3.5 measured all six routes at worst@5 with the DGX worker and DGX-side helper running at `--power 50`. +- `short_code_completion` official acceptance was route-specific: + - fail on route `1` pure local CUDA + - fail on route `3` distributed generation `CUDA -> Metal` + - fail on route `5` resumed `CUDA -> Metal` + - pass on routes `2`, `4`, and `6` +- Longer official cases all passed the official gate, but resumed payload routes still had weaker parity: + - `short_reasoning_plain` route `5`: `top64=61/64`, `rms=0.382280707` + - `short_reasoning_plain` route `6`: `top20=18/20`, `top64=59/64`, `rms=0.504765928` + - `long_code_audit` route `5`: `top5=4/5`, `top20=16/20`, `top64=50/64`, `rms=0.972514927` + - `long_code_audit` route `6`: `top5=4/5`, `top20=15/20`, `top64=53/64`, `rms=0.903749108` +- Pure CUDA already shows longer-prompt drift without any payload resume: + - `long_code_audit` route `1`: `top5=4/5`, `top20=16/20`, `top64=52/64`, `rms=0.893455684`, `max_abs=4.59287167` +- The stored local-golden fixture is not purely local-Metal-canonical: + - `long_story_4096` route `2` pure local Metal missed it with `top5=3/5`, `top20=16/20`, `top64=46/64`, `top20_max_abs=5.2168293` + - routes `1`, `3`, `4`, `5`, and `6` still passed the coarse fixture + +Why this changes the next steps: + +- Phase 3 was correct to block productization on “same-backend parity” alone, but Phase 3.5 shows that the remaining variance story is not one-dimensional. +- A resumed-route miss is only attributable to the handoff path after it is compared against: + - the matching direct-generation backend, + - the opposite direct-generation backend, + - and the behavior of the stored local-golden fixture itself. diff --git a/artifacts/issue-304/failure-cases.md b/artifacts/issue-304/failure-cases.md index 589607d73..ca19aac27 100644 --- a/artifacts/issue-304/failure-cases.md +++ b/artifacts/issue-304/failure-cases.md @@ -4,8 +4,44 @@ This artifact records mismatches that should remain rejected during distributed- ## Current Status -- No Phase 3 official/local parity failure has been recorded yet. -- Phase 2 observed `CUDA -> Metal` forced-token logit drift after resumed eval, but handoff logits and the sampled greedy continuation matched exactly. This is a Phase 3 classification case, not currently a proven rejection case. +- Phase 3 recorded a real same-backend rejection case. +- Phase 2 observed `CUDA -> Metal` forced-token logit drift after resumed eval, but that is no longer the main blocker. +- The stronger rejection is: distributed-prefill -> merged `DSV4` -> local Metal decode does not stay close enough to a fresh local Metal baseline after resumed evaluation begins. + +## Recorded Rejection Cases + +- `official ctx=16384 / long_code_audit` + - Official gate: pass on all five runs. + - Same-backend parity worst@5: `top5=4/5`, `top20=15/20`, `top64=55/64`, `rms=0.876981199`, `max_abs=4.63468361`. + - Why rejected: the handoff path diverges materially from a fresh local Metal baseline even though selected tokens/top-logprobs stay inside the official API envelope. + +- `local-golden ctx=5000 / long_story_4096` + - Local-golden fixture: pass on all five runs. + - Same-backend parity worst@5: `top5=3/5`, `top20=12/20`, `top64=46/64`, `rms=2.1708498`, `max_abs=12.3051796`, `top20_max_abs=7.73109055`. + - Why rejected: the resumed checkpoint stays within the coarse local-golden regression envelope, but the next eight greedy steps do not match a fresh local Metal baseline closely enough. + +- `phase3.5 official / short_code_completion / route1 pure local CUDA` + - Official gate: fail at worst@5. + - First selected mismatch step: `1`. + - Max logprob delta: `1.42368603`. + - Why rejected: this route misses the authoritative official selected-token/logprob surface before any distributed or resumed-handoff behavior is involved. + +- `phase3.5 official / short_code_completion / route3 distributed generation CUDA -> Metal` + - Official gate: fail at worst@5. + - First selected mismatch step: `1`. + - Max logprob delta: `0.85852015`. + - Why rejected: direct distributed generation on this backend pairing already misses the official acceptance gate, so later resumed-route drift on the same pairing cannot be attributed only to payload resume. + +- `phase3.5 official / short_code_completion / route5 resumed CUDA -> Metal` + - Official gate: fail at worst@5. + - First selected mismatch step: `1`. + - Resumed-route parity: `top5=3/5`, `top20=14/20`, `top64=54/64`, `rms=1.25698996`, `max_abs=6.82095432`. + - Why rejected: this cell misses both the official gate and resumed-route parity. + +- `phase3.5 local-golden / long_story_4096 / route2 pure local Metal` + - Local-golden fixture: fail at worst@5. + - Golden overlap: `top5=3/5`, `top20=16/20`, `top64=46/64`, `top20_max_abs=5.2168293`. + - Why rejected: the stored local-golden vector is not a reliable “pure local Metal canonical” surface for Phase 3.5 route attribution. ## Phase 3 Rejection Criteria @@ -19,6 +55,13 @@ A drift case should be recorded here as rejected if it: Cross-engine forced-logit differences alone are not a rejection case if same-backend handoff parity and official/local gates pass. +## Additional Layout Constraint + +- Merged `DSV4` staging also rejects worker/coordinator `prefill_cap` mismatch. +- Phase 3 required worker `DS4_METAL_PREFILL_CHUNK` alignment with the local environment: + - `2048` for the official-vector runs + - `4096` for the local-golden runs + ## Future Failure Classes To Preserve - Token hash mismatch. diff --git a/artifacts/issue-304/logit-comparisons.md b/artifacts/issue-304/logit-comparisons.md index 4595e146d..c1b237900 100644 --- a/artifacts/issue-304/logit-comparisons.md +++ b/artifacts/issue-304/logit-comparisons.md @@ -118,20 +118,43 @@ The new `tests/issue304_phase2_handoff` helper compared: - The fact that greedy continuation matched for 16 tokens while forced-trace drift still appeared means the drift is currently too small to perturb top-token choice in this sampled window. - Phase 3 should not require bit-exact cross-engine logits. It should decide whether the distributed-prefill-to-local path matches fully local inference on the same decode backend and satisfies the existing official-vector/local-golden correctness envelope. -## Phase 3 planned official/local parity +## Phase 3 official/local parity -The Phase 3 logit comparison target is: +The new `tests/issue304_phase3_vectors` helper compared: -1. fully local inference on the decode backend -2. distributed prefill + merged `DSV4` + local decode on that same backend -3. official API top-logprob vectors in `tests/test-vectors/official.vec` -4. local golden-vector drift thresholds where full local logits are available +1. fresh fully local Metal inference +2. distributed prefill -> merged `DSV4` -> local Metal load +3. official API vector acceptance for official cases +4. the existing local golden fixture for the `long_story_4096` frontier -Acceptance should use the existing local correctness semantics: +Local and DGX GGUF hashes matched exactly before these runs: -- `./ds4_test --logprob-vectors` for official selected-token and top-logprob agreement, allowing the existing skipped `long_memory_archive` caveat. -- `./ds4_test --local-golden-vectors` for local top-k/logit drift regression. -- A new or extended issue-304 harness should compare distributed-handoff outputs against fully local outputs before classifying any cross-engine forced-logit drift as a defect. +- `efc7ed607ff27076e3e501fc3fefefa33c0ed8cf1eff483a2b7fdc0c2e616668` + +### Official vectors, worst@5 + +The official top-logprob gate passed on every run below, but same-backend parity against a fresh local Metal baseline did not stay close enough to classify the remaining drift as harmless backend variance. + +| Case | Ctx | Worker `prefill_cap` | Official gate | Top-5 | Top-20 | Top-64 | RMS | Max abs | Top-20 max abs | Envelope | +| --- | ---: | ---: | --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | +| `short_code_completion` | 4096 | 2048 | Pass | 5/5 | 17/20 | 62/64 | 0.356403291 | 1.69900322 | 0.734794617 | Tolerant only | +| `short_reasoning_plain` | 4096 | 2048 | Pass | 5/5 | 20/20 | 62/64 | 0.327032387 | 1.77348614 | 0.5119133 | Tolerant only | +| `short_italian_fact` | 16384 | 2048 | Pass | 5/5 | 19/20 | 62/64 | 0.21716401 | 1.00239372 | 0.559177399 | Tolerant only | +| `long_code_audit` | 16384 | 2048 | Pass | 4/5 | 15/20 | 55/64 | 0.876981199 | 4.63468361 | 2.87808609 | Tolerant floor | + +### Local-golden frontier, worst@5 + +The resumed handoff still satisfied the existing local-golden fixture itself on all five runs, but the same resumed state diverged sharply from a fresh local Metal baseline over the next eight greedy steps. + +| Case | Ctx | Worker `prefill_cap` | Golden fixture | Golden top-20 | Golden top-64 | Golden top-20 max abs | Same-backend top-5 | Same-backend top-20 | Same-backend top-64 | Same-backend RMS | Same-backend max abs | Same-backend top-20 max abs | Result | +| --- | ---: | ---: | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | +| `long_story_4096` | 5000 | 4096 | Pass | 16/20 | 56/64 | 3.20196915 | 3/5 | 12/20 | 46/64 | 2.1708498 | 12.3051796 | 7.73109055 | Same-backend parity fail | + +### Interpretation + +- Official selected-token/top-logprob agreement is not strong enough to prove handoff equivalence. +- The local-golden fixture is also not sufficient by itself: the resumed checkpoint can satisfy that coarse regression while still diverging materially from a fresh local Metal baseline immediately afterward. +- Phase 3 therefore classifies the remaining issue as a handoff-specific resumed-decode mismatch, not merely cross-engine numeric variance. ## Baseline surrounding checks @@ -143,3 +166,81 @@ These were rerun after the Phase 1 changes to confirm the new harness did not pe | `./ds4_test --metal-short-prefill` | Pass | Existing short prefill regression remained green | | `./ds4_test --metal-tensor-equivalence` | Pass | Worst observed `rms=0.024882`, `max_abs=0.105766`, `top20_max_abs=0.0233078` on `long_code_audit` | | `make test` | Pass | Full default test target passed with the new resume test included | + +## Phase 3.5 six-route variance matrix + +Phase 3.5 extends the comparison surface to six execution routes and measures each at worst@5: + +1. pure local CUDA prefill+generation +2. pure local Metal prefill+generation +3. distributed generation `CUDA -> Metal` +4. distributed generation `Metal -> CUDA` +5. distributed prefill `CUDA -> Metal`, then resumed pure Metal generation +6. distributed prefill `Metal -> CUDA`, then resumed pure CUDA generation + +The DGX worker and DGX-side helper were run with `--power 50`. + +### Official vectors, worst@5 by route + +`short_code_completion` + +| Route | Official gate | First selected mismatch | Max logprob delta | Top-5 | Top-20 | Top-64 | RMS | Max abs | +| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | +| `1` local CUDA | Fail | 1 | 1.42368603 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `2` local Metal | Pass | -1 | 0.188549042 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `3` distributed `CUDA -> Metal` | Fail | 1 | 0.85852015 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `4` distributed `Metal -> CUDA` | Pass | -1 | 0.178744242 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `5` resumed `CUDA -> Metal` | Fail | 1 | 0.85852015 | 3/5 | 14/20 | 54/64 | 1.25698996 | 6.82095432 | +| `6` resumed `Metal -> CUDA` | Pass | -1 | 0.178744242 | 3/5 | 14/20 | 49/64 | 1.30479431 | 6.16060066 | + +`short_reasoning_plain` + +| Route | Official gate | Max logprob delta | Top-5 | Top-20 | Top-64 | RMS | Max abs | +| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | +| `1` local CUDA | Pass | 0.0258535184 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `2` local Metal | Pass | 0.0112166749 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `3` distributed `CUDA -> Metal` | Pass | 0.034484677 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `4` distributed `Metal -> CUDA` | Pass | 0.0139614902 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `5` resumed `CUDA -> Metal` | Pass | 0.034484677 | 5/5 | 20/20 | 61/64 | 0.382280707 | 2.11430359 | +| `6` resumed `Metal -> CUDA` | Pass | 0.0139614902 | 5/5 | 18/20 | 59/64 | 0.504765928 | 2.56024551 | + +`short_italian_fact` + +| Route | Official gate | Max logprob delta | Top-5 | Top-20 | Top-64 | RMS | Max abs | +| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | +| `1` local CUDA | Pass | 0.000240828318 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `2` local Metal | Pass | 0.000227290249 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `3` distributed `CUDA -> Metal` | Pass | 0.000264710223 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `4` distributed `Metal -> CUDA` | Pass | 0.000175568683 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `5` resumed `CUDA -> Metal` | Pass | 0.000264710223 | 4/5 | 18/20 | 56/64 | 0.663591683 | 3.45166492 | +| `6` resumed `Metal -> CUDA` | Pass | 0.000175568683 | 4/5 | 18/20 | 58/64 | 0.688694775 | 4.14918375 | + +`long_code_audit` + +| Route | Official gate | Max logprob delta | Top-5 | Top-20 | Top-64 | RMS | Max abs | +| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | +| `1` local CUDA | Pass | 0.107287943 | 4/5 | 16/20 | 52/64 | 0.893455684 | 4.59287167 | +| `2` local Metal | Pass | 0.0687521324 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `3` distributed `CUDA -> Metal` | Pass | 0.0741011128 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `4` distributed `Metal -> CUDA` | Pass | 0.0563559905 | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `5` resumed `CUDA -> Metal` | Pass | 0.0503566675 | 4/5 | 16/20 | 50/64 | 0.972514927 | 4.36004543 | +| `6` resumed `Metal -> CUDA` | Pass | 0.0933624879 | 4/5 | 15/20 | 53/64 | 0.903749108 | 4.15296125 | + +### Local-golden frontier, worst@5 by route + +`long_story_4096` + +| Route | Golden fixture | Golden top-20 | Golden top-64 | Golden top-20 max abs | Same-route parity | Top-5 | Top-20 | Top-64 | RMS | Max abs | +| --- | --- | ---: | ---: | ---: | --- | ---: | ---: | ---: | ---: | ---: | +| `1` local CUDA | Pass | 17/20 | 52/64 | 3.07355976 | Fail | 2/5 | 13/20 | 44/64 | 2.12094522 | 15.0152826 | +| `2` local Metal | Fail | 16/20 | 46/64 | 5.2168293 | Strict | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `3` distributed `CUDA -> Metal` | Pass | 16/20 | 50/64 | 3.56194687 | Strict | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `4` distributed `Metal -> CUDA` | Pass | 16/20 | 53/64 | 3.55953407 | Strict | 5/5 | 20/20 | 64/64 | 0 | 0 | +| `5` resumed `CUDA -> Metal` | Pass | 16/20 | 51/64 | 2.24486637 | Fail | 3/5 | 13/20 | 42/64 | 2.14919782 | 14.7165461 | +| `6` resumed `Metal -> CUDA` | Pass | 16/20 | 52/64 | 3.03334045 | Tolerant | 3/5 | 14/20 | 40/64 | 1.60283542 | 8.42455864 | + +### Interpretation + +- The official API gate is materially weaker than route parity. Three `short_code_completion` routes missed official acceptance, while the longer official cases still passed even when resumed-route parity had already drifted. +- Resumed payload routes remain the weakest cells. They are the only routes that repeatedly combine nonzero official deltas with visibly looser top-k overlap and RMS on otherwise passing cases. +- The local-golden fixture itself is also route-sensitive. Pure local Metal (`route 2`) missed the stored fixture while both distributed direct-generation routes (`3` and `4`) passed it exactly against their own references. diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md index 9f2cabe95..644486cb9 100644 --- a/artifacts/issue-304/perf-breakdown.md +++ b/artifacts/issue-304/perf-breakdown.md @@ -120,3 +120,101 @@ Planned fields from `tests/issue304_phase2_handoff`: - local greedy decode seconds / t/s - handoff logit comparison metrics - forced-trace first bad step and drift metrics + +## Phase 3 vector parity timings + +Phase 3 used `tests/issue304_phase3_vectors` with five one-shot coordinator runs per group. The one-shot structure avoided coordinator port reuse races on `10.77.0.1:1234` and gives the relevant worst@5 timing envelope directly. + +### Official vectors at `ctx=4096` + +Worker environment: + +- `--ctx 4096` +- `DS4_METAL_PREFILL_CHUNK=2048` + +Worst@5 observed timing by case: + +| Case | Payload bytes | Prefill sec | Stage sec | Load sec | +| --- | ---: | ---: | ---: | ---: | +| `short_code_completion` | 15,423,992 | 0.450 | 0.090 | 0.0020 | +| `short_reasoning_plain` | 14,523,860 | 0.394 | 0.076 | 0.0021 | + +Notes: + +- The `ctx=4096` official cases are cheap enough that phase timing was effectively stable across all five runs. +- These timings are not the blocker; the blocker is same-backend resumed-decode parity. + +### Official vectors at `ctx=16384` + +Worker environment: + +- `--ctx 16384` +- `DS4_METAL_PREFILL_CHUNK=2048` + +Worst@5 observed timing by case: + +| Case | Payload bytes | Prefill sec | Stage sec | Load sec | +| --- | ---: | ---: | ---: | ---: | +| `short_italian_fact` | 14,841,824 | 0.656 | 0.077 | 0.0022 | +| `long_code_audit` | 76,903,324 | 9.977 | 0.368 | 0.0189 | + +Notes: + +- `long_code_audit` makes the intended cost split clear: + - distributed prefill still dominates at about 10 s + - merged payload stage stayed below 0.4 s + - local payload load stayed below 0.02 s +- The throughput argument for handoff remains intact; the unresolved problem is decode-state equivalence after load. + +### Local-golden frontier at `ctx=5000` + +Worker environment: + +- `--ctx 5000` +- `DS4_METAL_PREFILL_CHUNK=4096` + +Worst@5 observed timing: + +| Case | Payload bytes | Prefill sec | Stage sec | Load sec | +| --- | ---: | ---: | ---: | ---: | +| `long_story_4096` | 80,373,132 | 12.262 | 0.367 | 0.0102 | + +Notes: + +- The 4096-token frontier remains practical from a staging perspective: + - prefill about 12.1 s + - merged stage at most about 0.37 s + - local load about 0.01 s +- That makes the same-backend parity failure more important: there is no evidence here that handoff cost, rather than resumed state evolution, is the main issue. + +## Phase 3.5 six-route timings + +Phase 3.5 used `tests/issue304_phase35_matrix.py` to run five one-shot repeats per route/case. The DGX worker and DGX-side helper were run with `--power 50`. + +### Official vectors + +| Case | Route `1` prefill sec | Route `2` prefill sec | Route `3` prefill sec | Route `4` prefill sec | Route `5` load sec | Route `6` load sec | Payload bytes | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | +| `short_code_completion` | 0.753 | 0.294 | 1.043 | 0.874 | 0.0018 | 0.0219 | 15,423,992 | +| `short_reasoning_plain` | 0.621 | 0.257 | 0.982 | 0.823 | 0.0018 | 0.0680 | 14,523,860 | +| `short_italian_fact` | 0.634 | 0.263 | 1.065 | 0.832 | 0.0024 | 0.0198 | 14,841,824 | +| `long_code_audit` | 19.446 | 10.416 | 12.196 | 9.271 | 0.0111 | 0.0932 | 76,903,324 | + +Notes: + +- The route `1` vs route `2` gap is the expected CUDA-vs-Metal local prefill cost split. +- Direct distributed generation remained close to the slower of the two local-prefill paths. +- Payload resume cost stayed small relative to prefill cost, even on the longer frontier: + - route `5` loads stayed around `0.0018-0.0111 s` + - route `6` loads stayed around `0.0198-0.0932 s` + +### Local-golden frontier + +| Case | Route `1` prefill sec | Route `2` prefill sec | Route `3` prefill sec | Route `4` prefill sec | Route `5` load sec | Route `6` load sec | Payload bytes | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | +| `long_story_4096` | 19.855 | 8.933 | 15.193 | 11.276 | 0.0112 | 0.0883 | 80,373,132 | + +Notes: + +- The same pattern holds on the 4096-token frontier: payload load remains cheap, and the dominant runtime is still prefill. +- That keeps the Phase 3.5 focus on correctness classification rather than route cost. diff --git a/artifacts/issue-304/phase35/raw/.gitignore b/artifacts/issue-304/phase35/raw/.gitignore new file mode 100644 index 000000000..4d52be8cb --- /dev/null +++ b/artifacts/issue-304/phase35/raw/.gitignore @@ -0,0 +1 @@ +*.dsv4 \ No newline at end of file diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep1.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep1.ndjson new file mode 100644 index 000000000..2e791597f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.667489,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":48,"rms":1.71911132,"max_abs":8.94140053,"top20_max_abs":4.78171921,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":1.90172768},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.667489,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":48,"rms":1.71911132,"max_abs":8.94140053,"top20_max_abs":4.78171921,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":1.90172768}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.295s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep2.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep2.ndjson new file mode 100644 index 000000000..07a7b2b2f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.783894,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":14,"top64_overlap":44,"rms":1.71360886,"max_abs":11.7790642,"top20_max_abs":7.18909836,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"top20_max_abs":1.49534607},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.783894,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":14,"top64_overlap":44,"rms":1.71360886,"max_abs":11.7790642,"top20_max_abs":7.18909836,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"top20_max_abs":1.49534607}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.344s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep3.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep3.ndjson new file mode 100644 index 000000000..795c15c59 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.827625,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":2,"top20_overlap":14,"top64_overlap":46,"rms":2.12094522,"max_abs":9.78272629,"top20_max_abs":8.60928154,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"top20_max_abs":2.57775402},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.827625,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":2,"top20_overlap":14,"top64_overlap":46,"rms":2.12094522,"max_abs":9.78272629,"top20_max_abs":8.60928154,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"top20_max_abs":2.57775402}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.313s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep4.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep4.ndjson new file mode 100644 index 000000000..8673b4eb3 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.808640,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":15,"top64_overlap":45,"rms":1.38345706,"max_abs":6.61496544,"top20_max_abs":4.71162033,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":1.64238358},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.808640,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":15,"top64_overlap":45,"rms":1.38345706,"max_abs":6.61496544,"top20_max_abs":4.71162033,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":1.64238358}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.305s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep5.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep5.ndjson new file mode 100644 index 000000000..8daa426f0 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r1-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.855204,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":13,"top64_overlap":45,"rms":2.02197361,"max_abs":15.0152826,"top20_max_abs":4.83264923,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":57,"top20_max_abs":3.07355976},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.855204,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":13,"top64_overlap":45,"rms":2.02197361,"max_abs":15.0152826,"top20_max_abs":4.83264923,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":57,"top20_max_abs":3.07355976}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.395s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep1.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep1.ndjson new file mode 100644 index 000000000..5e52d375a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":8.701739,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":8.701739,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.013 ms, residency requested in 342.234 ms, warmup 3.904 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep2.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep2.ndjson new file mode 100644 index 000000000..678996ac7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":8.712840,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":8.712840,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.993 ms, residency requested in 351.412 ms, warmup 3.524 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep3.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep3.ndjson new file mode 100644 index 000000000..6664c98fc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":8.933015,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":8.933015,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.415 ms, residency requested in 377.645 ms, warmup 3.779 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep4.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep4.ndjson new file mode 100644 index 000000000..d023ce621 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":8.775471,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":8.775471,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.239 ms, residency requested in 380.975 ms, warmup 3.650 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep5.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep5.ndjson new file mode 100644 index 000000000..970c5b19c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r2-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":8.678460,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293},"error":""} +{"mode":"local","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":8.678460,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":false,"top1":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"top20_max_abs":5.2168293}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 5.671 ms, residency requested in 369.293 ms, warmup 3.589 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.ndjson new file mode 100644 index 000000000..8a626a039 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:64488 Q2 22:output","payload_bytes":0,"prefill_sec":13.077673,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":18,"top64_overlap":55,"top20_max_abs":1.89717007},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:64488 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":13.077673,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":18,"top64_overlap":55,"top20_max_abs":1.89717007}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.462s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:64497 data_port=64488 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:64488 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:64488, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=828.552ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=545.177ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=549.608ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=598.124ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=594.075ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=622.690ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=597.117ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=589.401ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=630.613ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=608.900ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=614.909ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=620.298ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=632.042ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=614.839ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=612.900ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=611.076ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=13.074s 313.29 t/s local=7.292s send=11.564s 22.14 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=15.629ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.414ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.327ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=18.009ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.837ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.881ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.747ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.766ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:64497 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.worker.log new file mode 100644 index 000000000..b00c27f89 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep1.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.212 ms, residency requested in 174.449 ms, warmup 4.461 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:64488 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.ndjson new file mode 100644 index 000000000..a8e63455c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:64499 Q2 22:output","payload_bytes":0,"prefill_sec":15.193016,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":2.37919807},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:64499 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":15.193016,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":2.37919807}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.456s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:64566 data_port=64499 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:64499 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:64499, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=815.544ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=541.332ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=553.919ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=596.264ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=596.441ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=621.125ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=598.246ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=587.185ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=623.532ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=610.889ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=620.530ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=623.794ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=637.489ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=618.131ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=613.790ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=613.061ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=15.190s 269.65 t/s local=7.327s send=13.823s 18.52 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=15.311ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.155ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.300ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=17.863ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.822ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.746ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.642ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.728ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:64566 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.worker.log new file mode 100644 index 000000000..442f888ba --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep2.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.637 ms, residency requested in 205.965 ms, warmup 4.903 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:64499 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.ndjson new file mode 100644 index 000000000..eae8095a7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:64569 Q2 22:output","payload_bytes":0,"prefill_sec":13.145014,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":54,"top20_max_abs":1.93170357},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:64569 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":13.145014,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":54,"top20_max_abs":1.93170357}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.424s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:64674 data_port=64569 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:64569 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:64569, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=817.277ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=543.215ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=549.529ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=600.096ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=594.267ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=622.688ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=597.081ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=588.123ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=625.210ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=609.493ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=615.079ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=622.878ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=636.219ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=615.237ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=615.181ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=615.043ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=13.142s 311.68 t/s local=7.338s send=11.857s 21.59 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=15.638ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.310ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.218ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=17.868ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.481ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.635ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.768ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.685ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:64674 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.worker.log new file mode 100644 index 000000000..46e21ecd2 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep3.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.370 ms, residency requested in 171.762 ms, warmup 4.418 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:64569 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.ndjson new file mode 100644 index 000000000..e859783f1 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:64677 Q2 22:output","payload_bytes":0,"prefill_sec":13.530439,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":2.14455605},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:64677 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":13.530439,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":2.14455605}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.453s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:64784 data_port=64677 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:64677 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:64677, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=819.514ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=547.224ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=548.425ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=601.226ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=596.472ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=623.647ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=599.637ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=587.310ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=623.394ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=603.992ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=614.663ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=621.926ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=634.702ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=616.795ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=611.762ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=609.143ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=13.527s 302.80 t/s local=7.319s send=12.248s 20.90 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=16.751ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.364ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.185ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=17.973ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.820ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.731ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.613ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.698ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:64784 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.worker.log new file mode 100644 index 000000000..735a6f7fc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep4.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.553 ms, residency requested in 170.847 ms, warmup 3.737 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:64677 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.ndjson new file mode 100644 index 000000000..4c3b9448e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:64787 Q2 22:output","payload_bytes":0,"prefill_sec":12.565076,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":50,"top20_max_abs":3.56194687},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:64787 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":12.565076,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":50,"top20_max_abs":3.56194687}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.465s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:64897 data_port=64787 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:64787 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:64787, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=832.954ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=544.657ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=547.330ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=600.728ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=596.459ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=622.742ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=594.744ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=592.454ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=629.106ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=609.974ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=617.779ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=620.143ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=636.909ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=613.285ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=610.985ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=616.733ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=12.563s 326.04 t/s local=7.348s send=11.241s 22.78 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=14.921ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.214ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.174ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=17.789ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.822ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.710ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=17.322ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.889ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:64897 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.worker.log new file mode 100644 index 000000000..064284b35 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r3-rep5.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.355 ms, residency requested in 169.798 ms, warmup 3.503 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:64787 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep1.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep1.ndjson new file mode 100644 index 000000000..a4d6ad9f0 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep1.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:46557 Q2 22:output","payload_bytes":0,"prefill_sec":11.259020,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":3.15752983},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:46557 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":11.259020,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":3.15752983}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.852 ms, residency requested in 183.377 ms, warmup 3.837 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:49464 data_port=46557 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:46557 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:46557, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=496.646ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=369.856ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=388.839ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=395.768ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=401.427ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=420.549ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=408.815ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=412.629ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=415.834ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=410.356ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=424.504ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=416.983ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=425.715ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=422.326ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=413.697ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=417.432ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.259s 363.80 t/s local=10.795s send=0.346s 739.72 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=49.845ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=43.740ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=44.161ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=39.479ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.679ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=39.564ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=40.349ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=40.322ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep2.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep2.ndjson new file mode 100644 index 000000000..526494a93 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep2.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:45093 Q2 22:output","payload_bytes":0,"prefill_sec":11.264830,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":56,"top20_max_abs":3.39771843},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:45093 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":11.264830,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":56,"top20_max_abs":3.39771843}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.403 ms, residency requested in 186.229 ms, warmup 4.333 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:58114 data_port=45093 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:45093 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:45093, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=509.635ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=370.234ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=378.706ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=397.982ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=403.792ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=413.430ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=411.220ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=413.077ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=417.088ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=420.560ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=412.117ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=417.590ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=421.540ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=413.017ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=426.172ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=419.845ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.265s 363.61 t/s local=10.803s send=0.365s 700.86 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=45.850ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=41.967ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=44.181ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=38.887ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.318ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=39.172ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=39.203ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=39.258ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep3.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep3.ndjson new file mode 100644 index 000000000..20a2bf38a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep3.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:35195 Q2 22:output","payload_bytes":0,"prefill_sec":11.268496,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"top20_max_abs":3.54968643},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:35195 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":11.268496,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"top20_max_abs":3.54968643}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.434 ms, residency requested in 186.322 ms, warmup 3.475 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:46190 data_port=35195 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:35195 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:35195, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=495.113ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=372.255ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=377.261ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=400.891ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=400.795ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=415.476ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=408.281ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=412.669ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=425.484ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=410.497ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=414.058ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=414.994ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=423.854ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=420.141ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=414.594ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=414.253ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.268s 363.50 t/s local=10.811s send=0.366s 699.55 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=45.174ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=43.662ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=43.458ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=41.893ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.120ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=45.745ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=39.187ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=40.690ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep4.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep4.ndjson new file mode 100644 index 000000000..4fd517d55 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep4.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:46781 Q2 22:output","payload_bytes":0,"prefill_sec":11.271952,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":54,"top20_max_abs":3.04090118},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:46781 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":11.271952,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":54,"top20_max_abs":3.04090118}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.532 ms, residency requested in 189.545 ms, warmup 3.810 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:58906 data_port=46781 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:46781 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:46781, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=495.589ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=369.777ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=386.407ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=396.051ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=401.161ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=415.479ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=409.283ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=422.372ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=415.760ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=409.344ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=424.334ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=414.086ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=425.271ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=413.436ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=411.937ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=425.553ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.272s 363.38 t/s local=10.806s send=0.348s 736.36 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=45.406ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=45.132ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=44.703ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=39.472ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.195ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=38.366ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=38.118ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=40.127ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep5.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep5.ndjson new file mode 100644 index 000000000..04b0c75ab --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r4-rep5.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:37215 Q2 22:output","payload_bytes":0,"prefill_sec":11.275562,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":3.55953407},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:37215 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":11.275562,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":3.55953407}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.337 ms, residency requested in 188.209 ms, warmup 3.708 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:51918 data_port=37215 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:37215 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:37215, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=508.286ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=372.527ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=376.296ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=394.725ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=403.482ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=414.372ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=416.819ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=412.344ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=417.202ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=417.460ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=412.711ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=416.153ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=422.578ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=412.716ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=418.171ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=417.935ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.275s 363.27 t/s local=10.806s send=0.371s 690.84 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=43.553ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=45.448ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=45.409ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=40.264ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.651ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=39.975ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=38.893ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=40.181ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.ndjson new file mode 100644 index 000000000..e557db2dc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.011085,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":14,"top64_overlap":45,"rms":1.5977602,"max_abs":9.42034149,"top20_max_abs":3.70003796,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":2.24486637},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.011085,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":14,"top64_overlap":45,"rms":1.5977602,"max_abs":9.42034149,"top20_max_abs":3.70003796,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":2.24486637}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.373 ms, residency requested in 392.208 ms, warmup 3.402 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.stage.ndjson new file mode 100644 index 000000000..f3430dfc2 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.stage.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:64923 Q2 22:output","payload_bytes":80373132,"prefill_sec":12.764373,"stage_sec":2.706085,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":2.24486637},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:64923 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":12.764373,"stage_sec_max":2.706085,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":55,"top20_max_abs":2.24486637}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.452s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:65031 data_port=64923 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:64923 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:64923, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=814.860ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=540.590ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=549.939ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=607.225ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=591.479ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=620.759ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=590.856ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=589.544ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=623.308ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=608.660ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=619.179ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=621.597ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=636.183ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=613.016ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=608.271ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=606.260ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=12.761s 320.98 t/s local=7.361s send=11.416s 22.43 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=192.331ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.005ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.143ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=18.061ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=17.246ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=17.370ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.349ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.940ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:65031 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.worker.log new file mode 100644 index 000000000..46e621906 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep1.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.232 ms, residency requested in 180.602 ms, warmup 4.466 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:64923 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.ndjson new file mode 100644 index 000000000..907c4f132 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.011077,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":15,"top64_overlap":42,"rms":2.13493848,"max_abs":14.4514904,"top20_max_abs":4.90267944,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":1.80493069},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.011077,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":15,"top64_overlap":42,"rms":2.13493848,"max_abs":14.4514904,"top20_max_abs":4.90267944,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":1.80493069}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.846 ms, residency requested in 399.191 ms, warmup 4.221 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.stage.ndjson new file mode 100644 index 000000000..ee5fea598 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.stage.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:65174 Q2 22:output","payload_bytes":80373132,"prefill_sec":13.151818,"stage_sec":2.647919,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":1.80493069},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:65174 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":13.151818,"stage_sec_max":2.647919,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":17,"top64_overlap":54,"top20_max_abs":1.80493069}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.507s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:65284 data_port=65174 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:65174 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:65174, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=818.212ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=543.159ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=548.177ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=596.252ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=596.734ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=618.925ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=595.796ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=587.870ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=626.557ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=607.913ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=623.447ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=626.666ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=639.233ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=616.801ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=612.323ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=611.801ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=13.149s 311.52 t/s local=7.368s send=11.849s 21.61 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=187.930ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.397ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.499ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=18.276ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.808ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.947ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.766ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.491ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:65284 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.worker.log new file mode 100644 index 000000000..4a28679e0 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep2.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.334 ms, residency requested in 170.875 ms, warmup 4.222 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:65174 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.ndjson new file mode 100644 index 000000000..4537805d3 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.011227,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":45,"rms":1.60129142,"max_abs":8.93506241,"top20_max_abs":3.8504076,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":16,"top64_overlap":51,"top20_max_abs":2.12569904},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.011227,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":45,"rms":1.60129142,"max_abs":8.93506241,"top20_max_abs":3.8504076,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":16,"top64_overlap":51,"top20_max_abs":2.12569904}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.711 ms, residency requested in 347.166 ms, warmup 3.759 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.stage.ndjson new file mode 100644 index 000000000..8bb44a7ea --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.stage.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:65452 Q2 22:output","payload_bytes":80373132,"prefill_sec":21.141729,"stage_sec":2.438832,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":16,"top64_overlap":51,"top20_max_abs":2.12569904},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:65452 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":21.141729,"stage_sec_max":2.438832,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":5,"top20_overlap":16,"top64_overlap":51,"top20_max_abs":2.12569904}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.486s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:65461 data_port=65452 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:65452 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:65452, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=813.009ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=539.997ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=550.182ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=596.012ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=593.444ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=616.626ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=601.914ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=780.280ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=830.205ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=801.824ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=818.903ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=624.222ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=635.015ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=623.176ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=621.587ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=622.233ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=21.138s 193.77 t/s local=7.329s send=19.760s 12.96 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=190.060ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=15.142ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=13.990ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=18.256ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.605ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.639ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.906ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.841ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:65461 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.worker.log new file mode 100644 index 000000000..ea938cd4c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep3.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.217 ms, residency requested in 164.291 ms, warmup 4.466 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:65452 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.ndjson new file mode 100644 index 000000000..c4469ea99 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.011186,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"rms":1.47629261,"max_abs":7.8612566,"top20_max_abs":5.26890564,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":1.78080177},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.011186,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":16,"top64_overlap":46,"rms":1.47629261,"max_abs":7.8612566,"top20_max_abs":5.26890564,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":1.78080177}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.044 ms, residency requested in 357.670 ms, warmup 3.422 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.stage.ndjson new file mode 100644 index 000000000..30afd0065 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.stage.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:49206 Q2 22:output","payload_bytes":80373132,"prefill_sec":23.207394,"stage_sec":2.536130,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":1.78080177},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:49206 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":23.207394,"stage_sec_max":2.536130,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":1.78080177}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.468s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:49217 data_port=49206 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:49206 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:49206, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=825.418ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=560.099ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=559.427ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=599.327ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=596.259ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=629.295ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=596.960ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=791.671ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=827.052ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=811.299ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=623.162ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=630.417ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=641.487ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=618.351ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=618.095ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=616.119ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=23.204s 176.52 t/s local=7.288s send=21.835s 11.73 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=187.740ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=15.343ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.245ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=17.795ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.650ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=16.651ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.380ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.611ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:49217 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.worker.log new file mode 100644 index 000000000..b2b1ba08f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep4.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.475 ms, residency requested in 165.705 ms, warmup 3.409 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:49206 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.ndjson new file mode 100644 index 000000000..436c94b48 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.010994,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":13,"top64_overlap":45,"rms":2.14919782,"max_abs":14.7165461,"top20_max_abs":5.82323074,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":18,"top64_overlap":52,"top20_max_abs":1.6473732},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.010994,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":13,"top64_overlap":45,"rms":2.14919782,"max_abs":14.7165461,"top20_max_abs":5.82323074,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":18,"top64_overlap":52,"top20_max_abs":1.6473732}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.790 ms, residency requested in 354.075 ms, warmup 3.449 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.stage.ndjson new file mode 100644 index 000000000..1a8b396c6 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.stage.ndjson @@ -0,0 +1,45 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:49377 Q2 22:output","payload_bytes":80373132,"prefill_sec":13.752061,"stage_sec":2.859571,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":18,"top64_overlap":52,"top20_max_abs":1.6473732},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:49377 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":13.752061,"stage_sec_max":2.859571,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":18,"top64_overlap":52,"top20_max_abs":1.6473732}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.581s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:49494 data_port=49377 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:49377 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:49377, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=811.590ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=542.512ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=552.885ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=596.747ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=595.644ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=621.078ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=597.493ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=592.103ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=634.413ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=608.693ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=614.890ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=625.028ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=636.216ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=615.783ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=616.769ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=613.321ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=13.749s 297.92 t/s local=7.278s send=12.460s 20.55 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=186.343ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=14.227ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=14.214ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=17.891ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=16.840ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=17.008ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=16.913ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=17.965ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:49494 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.worker.log b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.worker.log new file mode 100644 index 000000000..feb9c10b5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r5-rep5.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 4.431 ms, residency requested in 169.585 ms, warmup 4.021 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:49377 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.ndjson new file mode 100644 index 000000000..57662b6f1 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.082131,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":47,"rms":1.4922334,"max_abs":7.27260399,"top20_max_abs":3.35482216,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":52,"top20_max_abs":2.94882679},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.082131,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":47,"rms":1.4922334,"max_abs":7.27260399,"top20_max_abs":3.35482216,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":52,"top20_max_abs":2.94882679}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.472s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.stage.ndjson new file mode 100644 index 000000000..be7bed5f8 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep1.stage.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:37487 Q2 22:output","payload_bytes":80373132,"prefill_sec":11.267617,"stage_sec":0.204731,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":52,"top20_max_abs":2.94882679},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:37487 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":11.267617,"stage_sec_max":0.204731,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":52,"top20_max_abs":2.94882679}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.339 ms, residency requested in 183.275 ms, warmup 4.324 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:40646 data_port=37487 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:37487 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:37487, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=495.077ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=368.545ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=376.131ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=392.905ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=400.531ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=410.678ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=407.326ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=417.093ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=412.860ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=409.432ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=409.915ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=411.503ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=425.274ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=409.230ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=410.321ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=419.438ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.268s 363.52 t/s local=10.806s send=0.360s 711.87 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=44.533ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=43.661ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=44.290ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=39.588ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.773ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=39.602ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=38.812ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=41.022ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.ndjson new file mode 100644 index 000000000..36b8eba42 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.088323,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":4,"top20_overlap":14,"top64_overlap":48,"rms":1.56049478,"max_abs":7.28148937,"top20_max_abs":4.52456474,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":2.89902687},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.088323,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":4,"top20_overlap":14,"top64_overlap":48,"rms":1.56049478,"max_abs":7.28148937,"top20_max_abs":4.52456474,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":2.89902687}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.452s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.stage.ndjson new file mode 100644 index 000000000..158b43435 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep2.stage.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:34255 Q2 22:output","payload_bytes":80373132,"prefill_sec":11.258659,"stage_sec":0.341775,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":2.89902687},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:34255 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":11.258659,"stage_sec_max":0.341775,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":2.89902687}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.377 ms, residency requested in 185.592 ms, warmup 4.530 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:59240 data_port=34255 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:34255 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:34255, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=499.063ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=367.707ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=374.534ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=393.900ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=399.241ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=418.689ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=410.705ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=410.628ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=425.795ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=409.503ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=412.124ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=409.826ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=418.978ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=417.237ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=411.916ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=416.437ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.259s 363.81 t/s local=10.796s send=0.355s 721.13 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=44.165ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=44.654ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=44.608ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=39.573ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.055ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=39.135ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=39.332ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=40.371ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.ndjson new file mode 100644 index 000000000..b6192452c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.087373,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":14,"top64_overlap":42,"rms":1.53389478,"max_abs":7.53617382,"top20_max_abs":3.39732742,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":55,"top20_max_abs":3.03334045},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.087373,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":14,"top64_overlap":42,"rms":1.53389478,"max_abs":7.53617382,"top20_max_abs":3.39732742,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":55,"top20_max_abs":3.03334045}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.354s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.stage.ndjson new file mode 100644 index 000000000..57472fee0 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep3.stage.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:35035 Q2 22:output","payload_bytes":80373132,"prefill_sec":11.252440,"stage_sec":0.238496,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":55,"top20_max_abs":3.03334045},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:35035 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":11.252440,"stage_sec_max":0.238496,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":55,"top20_max_abs":3.03334045}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.314 ms, residency requested in 185.786 ms, warmup 4.043 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:45218 data_port=35035 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:35035 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:35035, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=497.631ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=370.442ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=376.786ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=403.623ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=401.158ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=416.395ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=411.179ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=412.119ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=421.538ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=409.722ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=412.084ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=424.855ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=419.552ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=411.238ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=414.540ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=417.549ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.252s 364.01 t/s local=10.795s send=0.351s 730.40 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=43.619ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=43.702ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=45.076ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=38.687ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=39.755ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=40.912ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=39.843ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=39.876ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.ndjson new file mode 100644 index 000000000..0d1b7c0da --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.079343,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":17,"top64_overlap":47,"rms":1.50220609,"max_abs":8.31523132,"top20_max_abs":3.84506989,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":2.98101425},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.079343,"parity":{"envelope":"fail","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":3,"top20_overlap":17,"top64_overlap":47,"rms":1.50220609,"max_abs":8.31523132,"top20_max_abs":3.84506989,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":2.98101425}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.359s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.stage.ndjson new file mode 100644 index 000000000..6d6aba593 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep4.stage.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:45253 Q2 22:output","payload_bytes":80373132,"prefill_sec":11.255492,"stage_sec":0.218686,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":2.98101425},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:45253 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":11.255492,"stage_sec_max":0.218686,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":17,"top64_overlap":53,"top20_max_abs":2.98101425}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.363 ms, residency requested in 184.596 ms, warmup 4.434 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:58092 data_port=45253 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:45253 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:45253, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=502.620ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=368.736ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=378.141ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=394.782ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=398.469ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=413.249ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=412.741ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=409.715ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=415.923ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=414.624ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=412.140ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=415.067ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=417.516ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=413.132ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=418.036ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=417.815ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.255s 363.91 t/s local=10.796s send=0.337s 759.44 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=45.581ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=44.697ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=44.808ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=39.616ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=38.921ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=38.654ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=39.446ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=39.679ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.ndjson new file mode 100644 index 000000000..88f78928e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":80373132,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.083459,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":40,"rms":1.60283542,"max_abs":8.42455864,"top20_max_abs":4.18976974,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":3.00371647},"error":""} +{"mode":"payload","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":80373132,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.083459,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":40,"rms":1.60283542,"max_abs":8.42455864,"top20_max_abs":4.18976974,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":3.00371647}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.493s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.stage.ndjson new file mode 100644 index 000000000..4d54acb99 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/local-golden-long_story_4096-r6-rep5.stage.ndjson @@ -0,0 +1,41 @@ +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:34009 Q2 22:output","payload_bytes":80373132,"prefill_sec":11.274306,"stage_sec":0.239110,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":3.00371647},"error":""} +{"mode":"distributed","suite":"local-golden","case":"long_story_4096","ctx":5000,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:34009 Q2 22:output","payload_bytes_max":80373132,"prefill_sec_max":11.274306,"stage_sec_max":0.239110,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":4371,"top1_cand":4371,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0},"golden":{"pass":true,"top1":4371,"top5_overlap":4,"top20_overlap":16,"top64_overlap":53,"top20_max_abs":3.00371647}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.339 ms, residency requested in 183.255 ms, warmup 3.524 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:48654 data_port=34009 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=5000 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:34009 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:34009, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=499.836ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=373.985ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=378.701ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=392.714ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=407.069ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=415.763ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=410.054ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=420.534ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=412.738ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=410.971ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=411.972ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=413.652ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=426.408ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=418.368ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=414.022ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=256 eval=417.573ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=4096 chunks=16 total=11.274s 363.31 t/s local=10.798s send=0.371s 689.49 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=4096 tokens=1 eval=45.398ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=4097 tokens=1 eval=42.839ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=4098 tokens=1 eval=43.591ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=21 hop=0 layers=22:42 route=0 pos=4099 tokens=1 eval=40.895ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=22 hop=0 layers=22:42 route=0 pos=4100 tokens=1 eval=38.871ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=23 hop=0 layers=22:42 route=0 pos=4101 tokens=1 eval=39.529ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=24 hop=0 layers=22:42 route=0 pos=4102 tokens=1 eval=40.049ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=25 hop=0 layers=22:42 route=0 pos=4103 tokens=1 eval=39.278ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep1.ndjson new file mode 100644 index 000000000..448b3e77c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.445634,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":54,"rms":0.669915676,"max_abs":4.20909119,"top20_max_abs":1.95630836,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0339670144},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.445634,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":54,"rms":0.669915676,"max_abs":4.20909119,"top20_max_abs":1.95630836,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0339670144},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.366s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep2.ndjson new file mode 100644 index 000000000..146091653 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.391889,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":58,"rms":0.624250293,"max_abs":3.51475906,"top20_max_abs":1.29362106,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0499462932},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.391889,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":58,"rms":0.624250293,"max_abs":3.51475906,"top20_max_abs":1.29362106,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0499462932},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.351s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep3.ndjson new file mode 100644 index 000000000..49553c06d --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.440176,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"rms":0.681145728,"max_abs":3.42942619,"top20_max_abs":2.34897614,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0929543898},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.440176,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"rms":0.681145728,"max_abs":3.42942619,"top20_max_abs":2.34897614,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0929543898},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.420s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep4.ndjson new file mode 100644 index 000000000..cfb1ac1a0 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.437909,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"rms":0.893455684,"max_abs":4.43102932,"top20_max_abs":3.75432396,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.063203983},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.437909,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"rms":0.893455684,"max_abs":4.43102932,"top20_max_abs":3.75432396,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.063203983},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.412s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep5.ndjson new file mode 100644 index 000000000..6ae9f264c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r1-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":19.511959,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"rms":0.74813807,"max_abs":4.59287167,"top20_max_abs":1.68626404,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.107287943},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":19.511959,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"rms":0.74813807,"max_abs":4.59287167,"top20_max_abs":1.68626404,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.107287943},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.355s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep1.ndjson new file mode 100644 index 000000000..d1617b83d --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":9.551189,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":9.551189,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.310 ms, residency requested in 346.480 ms, warmup 4.146 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep2.ndjson new file mode 100644 index 000000000..bb6ba0cb5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":9.579823,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":9.579823,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.134 ms, residency requested in 356.522 ms, warmup 3.525 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep3.ndjson new file mode 100644 index 000000000..90e6cb752 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":10.415664,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":10.415664,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.291 ms, residency requested in 380.739 ms, warmup 3.800 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep4.ndjson new file mode 100644 index 000000000..2fc7d7ccb --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":10.021032,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":10.021032,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.951 ms, residency requested in 408.226 ms, warmup 3.903 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep5.ndjson new file mode 100644 index 000000000..c6103978d --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r2-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":9.636912,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":9.636912,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0687521324},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.110 ms, residency requested in 380.763 ms, warmup 3.607 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.ndjson new file mode 100644 index 000000000..5fe39d4da --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:62379 Q2 22:output","payload_bytes":0,"prefill_sec":12.568796,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0526480526},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:62379 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":12.568796,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0526480526},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.492s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:62495 data_port=62379 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:62379 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:62379, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=786.477ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=513.707ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=529.621ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=532.189ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=541.733ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=541.633ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=551.717ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=549.364ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=578.840ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=585.297ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=581.405ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=584.220ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=582.198ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=576.508ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=596.690ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.487ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=12.566s 305.92 t/s local=6.397s send=11.264s 21.33 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=24.108ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=23.315ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.317ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:62495 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.worker.log new file mode 100644 index 000000000..adb73ca21 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep1.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.223 ms, residency requested in 177.110 ms, warmup 4.307 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:62379 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.ndjson new file mode 100644 index 000000000..8753ce267 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:62498 Q2 22:output","payload_bytes":0,"prefill_sec":12.196051,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0741011128},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:62498 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":12.196051,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0741011128},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.608s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:62610 data_port=62498 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:62498 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:62498, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=790.614ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=518.971ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=535.069ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=535.383ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=543.466ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=545.607ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=547.125ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=552.625ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=585.349ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=578.825ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=579.308ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=578.924ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=585.090ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=589.245ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=598.998ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=34.746ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=12.193s 315.27 t/s local=6.446s send=10.963s 21.92 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=15.733ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=14.625ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.403ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:62610 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.worker.log new file mode 100644 index 000000000..7df80ac56 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep2.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.416 ms, residency requested in 171.042 ms, warmup 3.970 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:62498 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.ndjson new file mode 100644 index 000000000..95d1522e8 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:62612 Q2 22:output","payload_bytes":0,"prefill_sec":12.474563,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0213075131},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:62612 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":12.474563,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0213075131},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.480s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:62719 data_port=62612 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:62612 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:62612, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=793.689ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=518.133ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=535.218ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=535.175ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=541.457ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=545.092ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=552.121ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=552.373ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=580.656ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=582.436ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=582.398ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=580.696ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=589.344ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=581.571ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=599.779ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=34.853ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=12.471s 308.23 t/s local=6.453s send=11.219s 21.42 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=15.660ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=14.234ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.311ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:62719 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.worker.log new file mode 100644 index 000000000..a6996f144 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep3.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.306 ms, residency requested in 172.475 ms, warmup 3.527 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:62612 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.ndjson new file mode 100644 index 000000000..10ef0c7aa --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:62721 Q2 22:output","payload_bytes":0,"prefill_sec":13.662227,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0365786143},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:62721 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":13.662227,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0365786143},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.466s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:62828 data_port=62721 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:62721 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:62721, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=787.755ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=516.561ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=536.310ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=541.169ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=541.943ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=542.864ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=551.510ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=552.452ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=579.282ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=577.020ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=579.298ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=594.410ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=580.968ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=586.107ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=591.462ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.577ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=13.659s 281.43 t/s local=6.426s send=12.423s 19.34 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=25.566ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=13.908ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.405ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:62828 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.worker.log new file mode 100644 index 000000000..9f52d1993 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep4.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.252 ms, residency requested in 168.270 ms, warmup 3.777 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:62721 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.ndjson new file mode 100644 index 000000000..b68dcc8c8 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:62831 Q2 22:output","payload_bytes":0,"prefill_sec":13.242607,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0209505875},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:62831 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":13.242607,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0209505875},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.448s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:62943 data_port=62831 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:62831 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:62831, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=774.543ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=515.490ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=535.728ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=539.377ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=538.695ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=543.491ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=553.778ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=552.236ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=578.474ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=578.365ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=578.595ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=587.811ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=583.753ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=589.592ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=601.470ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.686ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=13.239s 290.35 t/s local=6.444s send=11.968s 20.08 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=16.857ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=14.620ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.628ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:62943 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.worker.log new file mode 100644 index 000000000..c9648d88a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r3-rep5.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.268 ms, residency requested in 169.887 ms, warmup 3.524 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:62831 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep1.ndjson new file mode 100644 index 000000000..14e6610e4 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep1.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:44759 Q2 22:output","payload_bytes":0,"prefill_sec":9.311805,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.051819656},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:44759 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":9.311805,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.051819656},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.444 ms, residency requested in 194.707 ms, warmup 4.128 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:52038 data_port=44759 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:44759 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:44759, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=501.605ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=367.814ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=373.474ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=378.138ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=387.696ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=389.729ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=394.234ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=402.400ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=401.221ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=399.618ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=407.888ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=400.875ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=402.903ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=406.670ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=410.242ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=78.377ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.312s 412.82 t/s local=8.820s send=0.316s 761.47 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=46.430ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=44.588ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=42.437ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep2.ndjson new file mode 100644 index 000000000..e3cce0da0 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep2.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:35313 Q2 22:output","payload_bytes":0,"prefill_sec":9.270740,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0563559905},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:35313 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":9.270740,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0563559905},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.352 ms, residency requested in 185.153 ms, warmup 4.102 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:57488 data_port=35313 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:35313 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:35313, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=505.659ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=365.652ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=373.921ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=382.723ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=385.471ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=387.152ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=396.041ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=397.613ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=400.200ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=402.295ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=399.491ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=401.037ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=405.189ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=404.433ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=410.801ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=76.484ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.271s 414.64 t/s local=8.760s send=0.328s 731.50 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=45.694ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=43.620ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=43.739ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep3.ndjson new file mode 100644 index 000000000..42b6c9fb3 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep3.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:46719 Q2 22:output","payload_bytes":0,"prefill_sec":9.264093,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.052271504},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:46719 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":9.264093,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.052271504},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.279 ms, residency requested in 184.329 ms, warmup 4.405 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:60224 data_port=46719 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:46719 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:46719, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=498.754ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=362.185ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=370.174ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=385.905ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=383.549ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=388.809ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=403.906ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=400.629ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=400.068ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=404.907ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=400.143ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=398.568ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=407.485ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=400.749ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=408.354ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=76.498ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.264s 414.94 t/s local=8.772s send=0.323s 744.21 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=45.356ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=43.744ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=43.804ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep4.ndjson new file mode 100644 index 000000000..2603199b2 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep4.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:32955 Q2 22:output","payload_bytes":0,"prefill_sec":9.258283,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0445772707},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:32955 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":9.258283,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0445772707},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.394 ms, residency requested in 187.286 ms, warmup 3.930 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:37252 data_port=32955 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:32955 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:32955, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=504.839ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=365.601ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=373.327ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=378.163ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=384.372ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=391.014ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=395.946ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=401.562ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=400.948ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=404.797ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=398.534ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=401.181ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=409.377ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=401.750ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=409.503ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=76.502ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.258s 415.20 t/s local=8.767s send=0.321s 748.36 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=45.073ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=43.171ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=48.750ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep5.ndjson new file mode 100644 index 000000000..e27ded1b5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r4-rep5.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:38529 Q2 22:output","payload_bytes":0,"prefill_sec":9.287371,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0503385961},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:38529 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":9.287371,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0503385961},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.340 ms, residency requested in 189.846 ms, warmup 4.641 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:40022 data_port=38529 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:38529 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:38529, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=505.416ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=366.700ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=378.773ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=379.254ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=384.016ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=394.906ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=394.222ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=401.859ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=413.326ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=402.034ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=400.163ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=408.445ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=403.173ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=404.010ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=421.314ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=75.425ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.287s 413.90 t/s local=8.772s send=0.348s 690.08 MiB/s +ds4: distributed telemetry: request=17 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=44.279ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=43.914ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=43.607ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.ndjson new file mode 100644 index 000000000..d86219352 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.011115,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":50,"rms":0.762632489,"max_abs":4.18057632,"top20_max_abs":2.23833466,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0287036505},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.011115,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":50,"rms":0.762632489,"max_abs":4.18057632,"top20_max_abs":2.23833466,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0287036505},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.851 ms, residency requested in 408.150 ms, warmup 3.681 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.stage.ndjson new file mode 100644 index 000000000..321bed5cd --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.stage.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:62970 Q2 22:output","payload_bytes":76903324,"prefill_sec":12.809643,"stage_sec":2.470742,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0287036505},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:62970 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":12.809643,"stage_sec_max":2.470742,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0287036505},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.475s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:63085 data_port=62970 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:62970 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:62970, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=790.470ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=515.585ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=533.223ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=539.819ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=539.916ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=545.653ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=550.321ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=554.330ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=580.950ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=582.254ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=579.178ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=581.697ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=588.902ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=585.808ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=603.837ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.475ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=12.806s 300.16 t/s local=6.419s send=11.551s 20.80 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=190.488ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=14.391ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.569ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:63085 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.worker.log new file mode 100644 index 000000000..1e8bd79aa --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep1.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.544 ms, residency requested in 170.864 ms, warmup 3.548 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:62970 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.ndjson new file mode 100644 index 000000000..48e9d212f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.010780,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"rms":0.972514927,"max_abs":4.36004543,"top20_max_abs":3.10638809,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0298511684},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.010780,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":52,"rms":0.972514927,"max_abs":4.36004543,"top20_max_abs":3.10638809,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0298511684},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.935 ms, residency requested in 350.651 ms, warmup 3.731 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.stage.ndjson new file mode 100644 index 000000000..b0aa991d2 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.stage.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:63249 Q2 22:output","payload_bytes":76903324,"prefill_sec":12.919438,"stage_sec":2.346033,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0298511684},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:63249 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":12.919438,"stage_sec_max":2.346033,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0298511684},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.624s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:63362 data_port=63249 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:63249 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:63249, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=794.474ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=520.995ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=535.071ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=534.401ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=545.592ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=542.163ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=553.433ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=549.942ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=582.740ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=578.901ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=580.146ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=594.989ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=584.931ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=581.699ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=598.299ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.770ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=12.916s 297.61 t/s local=6.438s send=11.662s 20.60 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=189.432ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=14.255ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.333ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:63362 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.worker.log new file mode 100644 index 000000000..858a30a26 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep2.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.213 ms, residency requested in 178.140 ms, warmup 4.084 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:63249 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.ndjson new file mode 100644 index 000000000..c1134644a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.010865,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"rms":0.695183873,"max_abs":3.45978928,"top20_max_abs":1.57339668,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0373200923},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.010865,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":56,"rms":0.695183873,"max_abs":3.45978928,"top20_max_abs":1.57339668,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0373200923},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.768 ms, residency requested in 399.625 ms, warmup 3.526 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.stage.ndjson new file mode 100644 index 000000000..ca3108a05 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.stage.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:63526 Q2 22:output","payload_bytes":76903324,"prefill_sec":11.616271,"stage_sec":2.154109,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0373200923},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:63526 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":11.616271,"stage_sec_max":2.154109,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0373200923},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.457s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:63635 data_port=63526 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:63526 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:63526, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=791.951ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=515.947ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=534.480ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=538.126ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=545.300ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=543.592ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=554.858ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=549.860ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=577.388ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=578.414ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=575.458ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=582.908ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=584.450ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=583.449ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=594.011ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.551ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=11.613s 331.01 t/s local=6.420s send=10.327s 23.27 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=192.161ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=14.020ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.168ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:63635 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.worker.log new file mode 100644 index 000000000..ddaab3081 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep3.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.419 ms, residency requested in 174.991 ms, warmup 3.975 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:63526 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.ndjson new file mode 100644 index 000000000..2fcea3ab9 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.011107,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":57,"rms":0.61021632,"max_abs":3.20054412,"top20_max_abs":2.27858353,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0503566675},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.011107,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":57,"rms":0.61021632,"max_abs":3.20054412,"top20_max_abs":2.27858353,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0503566675},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.796 ms, residency requested in 352.572 ms, warmup 3.373 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.stage.ndjson new file mode 100644 index 000000000..a3f56811e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.stage.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:63790 Q2 22:output","payload_bytes":76903324,"prefill_sec":11.649437,"stage_sec":2.233452,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0503566675},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:63790 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":11.649437,"stage_sec_max":2.233452,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0503566675},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.463s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:63858 data_port=63790 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:63790 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:63790, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=800.424ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=518.591ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=534.764ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=530.958ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=536.086ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=540.688ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=550.212ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=550.331ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=577.554ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=575.258ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=577.209ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=580.929ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=586.749ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=585.734ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=599.437ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.643ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=11.646s 330.06 t/s local=6.438s send=10.333s 23.25 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=182.963ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=15.597ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.327ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:63858 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.worker.log new file mode 100644 index 000000000..3a4ebf775 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep4.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.186 ms, residency requested in 170.223 ms, warmup 3.879 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:63790 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.ndjson new file mode 100644 index 000000000..6657e9d0e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.011200,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":57,"rms":0.545941293,"max_abs":2.59675503,"top20_max_abs":1.54932404,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0241757426},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.011200,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":57,"rms":0.545941293,"max_abs":2.59675503,"top20_max_abs":1.54932404,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0241757426},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.114 ms, residency requested in 352.377 ms, warmup 3.413 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.stage.ndjson new file mode 100644 index 000000000..43f0cf27b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.stage.ndjson @@ -0,0 +1,40 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:63976 Q2 22:output","payload_bytes":76903324,"prefill_sec":11.843607,"stage_sec":2.595544,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0241757426},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:63976 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":11.843607,"stage_sec_max":2.595544,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0241757426},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.570s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:64091 data_port=63976 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:63976 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 192.168.1.218:63976, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=788.123ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=516.754ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=529.670ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=538.093ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=544.389ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=544.941ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=548.799ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=550.260ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=576.022ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=580.078ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=580.131ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=580.955ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=585.209ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=577.854ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=600.718ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=35.341ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=11.842s 324.61 t/s local=6.391s send=10.586s 22.70 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=186.407ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=14.173ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=14.161ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:64091 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.worker.log new file mode 100644 index 000000000..e904a86a5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r5-rep5.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.368 ms, residency requested in 168.448 ms, warmup 3.710 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:63976 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.ndjson new file mode 100644 index 000000000..76e2abb3c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.242621,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":57,"rms":0.592848241,"max_abs":2.86506987,"top20_max_abs":1.86075211,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.057265643},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.242621,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":57,"rms":0.592848241,"max_abs":2.86506987,"top20_max_abs":1.86075211,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.057265643},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.320s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.stage.ndjson new file mode 100644 index 000000000..c12e17fcb --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep1.stage.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:33787 Q2 22:output","payload_bytes":76903324,"prefill_sec":9.252428,"stage_sec":0.376546,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.057265643},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:33787 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":9.252428,"stage_sec_max":0.376546,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.057265643},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.377 ms, residency requested in 183.925 ms, warmup 4.077 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:59854 data_port=33787 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:33787 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:33787, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=499.855ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=363.726ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=370.213ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=385.700ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=383.121ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=391.316ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=401.026ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=397.777ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=399.720ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=405.969ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=398.697ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=401.288ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=412.702ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=404.319ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=407.816ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=75.497ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.252s 415.46 t/s local=8.762s send=0.324s 740.45 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=45.304ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=43.808ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=44.526ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.ndjson new file mode 100644 index 000000000..885488b05 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.093165,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":55,"rms":0.549745619,"max_abs":2.69295526,"top20_max_abs":1.8057766,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0651414096},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.093165,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":55,"rms":0.549745619,"max_abs":2.69295526,"top20_max_abs":1.8057766,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0651414096},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.602s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.stage.ndjson new file mode 100644 index 000000000..d57baf66b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep2.stage.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:42527 Q2 22:output","payload_bytes":76903324,"prefill_sec":9.268765,"stage_sec":0.337292,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0651414096},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:42527 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":9.268765,"stage_sec_max":0.337292,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0651414096},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.380 ms, residency requested in 184.567 ms, warmup 3.755 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:51000 data_port=42527 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:42527 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:42527, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=500.191ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=373.773ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=374.608ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=379.438ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=397.087ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=391.392ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=396.070ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=412.656ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=397.358ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=401.193ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=406.378ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=402.486ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=404.771ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=405.214ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=410.783ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=76.661ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.269s 414.73 t/s local=8.757s send=0.354s 679.62 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=45.132ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=42.852ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=43.617ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.ndjson new file mode 100644 index 000000000..76ae23d78 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.088191,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":55,"rms":0.569068551,"max_abs":2.95434713,"top20_max_abs":1.58810043,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0519559048},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.088191,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":17,"top64_overlap":55,"rms":0.569068551,"max_abs":2.95434713,"top20_max_abs":1.58810043,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0519559048},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.511s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.stage.ndjson new file mode 100644 index 000000000..f2a88a7fd --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep3.stage.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:38711 Q2 22:output","payload_bytes":76903324,"prefill_sec":9.244220,"stage_sec":0.213055,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0519559048},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:38711 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":9.244220,"stage_sec_max":0.213055,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0519559048},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.315 ms, residency requested in 184.672 ms, warmup 3.826 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:56234 data_port=38711 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:38711 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:38711, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=498.922ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=363.935ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=373.982ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=389.607ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=384.444ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=389.930ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=400.090ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=401.114ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=398.927ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=412.498ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=403.573ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=396.600ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=407.717ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=402.355ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=408.096ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=74.390ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.244s 415.83 t/s local=8.757s send=0.325s 739.58 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=45.158ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=44.059ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=48.307ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.ndjson new file mode 100644 index 000000000..d70509cae --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.071449,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":15,"top64_overlap":53,"rms":0.903749108,"max_abs":4.15296125,"top20_max_abs":2.60333824,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0593865961},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.071449,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":15,"top64_overlap":53,"rms":0.903749108,"max_abs":4.15296125,"top20_max_abs":2.60333824,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0593865961},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.524s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.stage.ndjson new file mode 100644 index 000000000..89156a9bb --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep4.stage.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:45465 Q2 22:output","payload_bytes":76903324,"prefill_sec":9.247454,"stage_sec":0.238412,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0593865961},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:45465 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":9.247454,"stage_sec_max":0.238412,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0593865961},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.348 ms, residency requested in 184.071 ms, warmup 4.548 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:32998 data_port=45465 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:45465 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:45465, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=504.620ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=366.143ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=380.188ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=379.843ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=385.968ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=391.005ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=397.628ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=404.433ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=401.263ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=401.826ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=400.882ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=401.644ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=406.144ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=404.089ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=410.946ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=73.791ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.247s 415.69 t/s local=8.755s send=0.347s 692.11 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=45.315ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=44.041ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=43.483ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.ndjson new file mode 100644 index 000000000..36cfa6cac --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":76903324,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.089869,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":57,"rms":0.691504538,"max_abs":4.01153183,"top20_max_abs":1.10848045,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0933624879},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":76903324,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.089869,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":4,"top20_overlap":16,"top64_overlap":57,"rms":0.691504538,"max_abs":4.01153183,"top20_max_abs":1.10848045,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0933624879},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.560s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.stage.ndjson new file mode 100644 index 000000000..34f4f736e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-long_code_audit-r6-rep5.stage.ndjson @@ -0,0 +1,36 @@ +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:34245 Q2 22:output","payload_bytes":76903324,"prefill_sec":9.245574,"stage_sec":0.247454,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0933624879},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"long_code_audit","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:34245 Q2 22:output","payload_bytes_max":76903324,"prefill_sec_max":9.245574,"stage_sec_max":0.247454,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":671,"top1_cand":671,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0933624879},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.357 ms, residency requested in 186.271 ms, warmup 4.169 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:59136 data_port=34245 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:34245 Q2 22:output +ds4: distributed coordinator: pipelined prefill 16 chunks of up to 256 tokens through 1 worker, first hop 10.77.0.2:34245, send depth 2, flow window 3 +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=256 eval=503.170ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=256 tokens=256 eval=369.873ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=512 tokens=256 eval=376.700ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=768 tokens=256 eval=380.062ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=1024 tokens=256 eval=388.468ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=6 hop=0 layers=22:42 route=0 pos=1280 tokens=256 eval=388.329ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=7 hop=0 layers=22:42 route=0 pos=1536 tokens=256 eval=396.172ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=8 hop=0 layers=22:42 route=0 pos=1792 tokens=256 eval=399.189ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=9 hop=0 layers=22:42 route=0 pos=2048 tokens=256 eval=399.763ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=10 hop=0 layers=22:42 route=0 pos=2304 tokens=256 eval=400.206ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=11 hop=0 layers=22:42 route=0 pos=2560 tokens=256 eval=400.114ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=12 hop=0 layers=22:42 route=0 pos=2816 tokens=256 eval=401.820ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=13 hop=0 layers=22:42 route=0 pos=3072 tokens=256 eval=405.621ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=14 hop=0 layers=22:42 route=0 pos=3328 tokens=256 eval=404.639ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=15 hop=0 layers=22:42 route=0 pos=3584 tokens=256 eval=410.297ms downstream_wait=0.000ms forward_send=0.000ms input=16.00MiB output=0.00MiB +ds4: distributed telemetry: request=16 hop=0 layers=22:42 route=0 pos=3840 tokens=4 eval=74.565ms downstream_wait=0.000ms forward_send=0.000ms input=0.25MiB output=0.49MiB +ds4: distributed coordinator: pipelined prefill done tokens=3844 chunks=16 total=9.245s 415.77 t/s local=8.754s send=0.383s 627.18 MiB/s +ds4: distributed telemetry: request=18 hop=0 layers=22:42 route=0 pos=3844 tokens=1 eval=44.024ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=19 hop=0 layers=22:42 route=0 pos=3845 tokens=1 eval=44.388ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=20 hop=0 layers=22:42 route=0 pos=3846 tokens=1 eval=43.766ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep1.ndjson new file mode 100644 index 000000000..b494bd019 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.761767,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.761767,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.848s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep2.ndjson new file mode 100644 index 000000000..29d308f47 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.759438,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.759438,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.746s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep3.ndjson new file mode 100644 index 000000000..22afa69cc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.752710,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.752710,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.404s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep4.ndjson new file mode 100644 index 000000000..06b1d226c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.753134,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.753134,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.779s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep5.ndjson new file mode 100644 index 000000000..9b2d5d2c7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r1-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.765507,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.765507,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":1.42368603},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.418s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep1.ndjson new file mode 100644 index 000000000..8d83c1727 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.295150,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.295150,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.928 ms, residency requested in 348.684 ms, warmup 4.177 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep2.ndjson new file mode 100644 index 000000000..29a0bc36c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.293930,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.293930,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.151 ms, residency requested in 349.988 ms, warmup 3.524 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep3.ndjson new file mode 100644 index 000000000..2842201a8 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.294036,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.294036,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.334 ms, residency requested in 347.272 ms, warmup 3.257 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep4.ndjson new file mode 100644 index 000000000..256de3860 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.293810,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.293810,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.993 ms, residency requested in 350.166 ms, warmup 3.412 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep5.ndjson new file mode 100644 index 000000000..1fb6471b1 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r2-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.294027,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.294027,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.188549042},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.265 ms, residency requested in 354.229 ms, warmup 3.354 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.ndjson new file mode 100644 index 000000000..6823c6b4e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59812 Q2 22:output","payload_bytes":0,"prefill_sec":1.041659,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59812 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.041659,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.760s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59876 data_port=59812 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59812 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=345.794ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=15.797ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=14.220ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=13.901ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59876 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.worker.log new file mode 100644 index 000000000..a5ce7ab29 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep1.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.259 ms, residency requested in 167.465 ms, warmup 3.632 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59812 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.ndjson new file mode 100644 index 000000000..e09ec2178 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59878 Q2 22:output","payload_bytes":0,"prefill_sec":1.091320,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59878 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.091320,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.595s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59943 data_port=59878 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59878 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=334.626ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=15.482ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=13.847ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=14.098ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59943 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.worker.log new file mode 100644 index 000000000..21a41ec8f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep2.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.186 ms, residency requested in 168.234 ms, warmup 4.162 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59878 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.ndjson new file mode 100644 index 000000000..2ccb6d228 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59945 Q2 22:output","payload_bytes":0,"prefill_sec":1.178696,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59945 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.178696,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.468s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60008 data_port=59945 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59945 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=329.944ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=15.792ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=14.119ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=14.242ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60008 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.worker.log new file mode 100644 index 000000000..4bf711cb4 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep3.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.228 ms, residency requested in 169.768 ms, warmup 3.506 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59945 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.ndjson new file mode 100644 index 000000000..55e177d81 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:60011 Q2 22:output","payload_bytes":0,"prefill_sec":1.042687,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:60011 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.042687,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.536s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60081 data_port=60011 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:60011 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=341.980ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=15.027ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=13.981ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=13.880ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60081 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.worker.log new file mode 100644 index 000000000..b85434405 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep4.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.379 ms, residency requested in 167.878 ms, warmup 3.912 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:60011 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.ndjson new file mode 100644 index 000000000..30c80fc77 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:60085 Q2 22:output","payload_bytes":0,"prefill_sec":0.979889,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:60085 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.979889,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.433s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60149 data_port=60085 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:60085 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=343.701ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=15.427ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=13.981ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=13.897ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60149 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.worker.log new file mode 100644 index 000000000..14f6d22c9 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r3-rep5.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.602 ms, residency requested in 168.932 ms, warmup 3.587 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:60085 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep1.ndjson new file mode 100644 index 000000000..5c8ba75cc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep1.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:41613 Q2 22:output","payload_bytes":0,"prefill_sec":0.873977,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:41613 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.873977,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.405 ms, residency requested in 181.870 ms, warmup 3.676 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:48602 data_port=41613 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:41613 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=400.206ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=37.016ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=35.029ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=34.622ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep2.ndjson new file mode 100644 index 000000000..d6b009e72 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep2.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:44933 Q2 22:output","payload_bytes":0,"prefill_sec":0.862774,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:44933 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.862774,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.353 ms, residency requested in 183.119 ms, warmup 3.704 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:47142 data_port=44933 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:44933 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=398.077ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=37.989ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=36.200ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=35.199ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep3.ndjson new file mode 100644 index 000000000..54e012f3a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep3.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:44461 Q2 22:output","payload_bytes":0,"prefill_sec":0.866188,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:44461 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.866188,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.207 ms, residency requested in 182.904 ms, warmup 3.466 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:47578 data_port=44461 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:44461 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=403.623ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=36.891ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=35.828ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=35.731ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep4.ndjson new file mode 100644 index 000000000..d506223d1 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep4.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:36325 Q2 22:output","payload_bytes":0,"prefill_sec":0.857403,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:36325 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.857403,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.278 ms, residency requested in 181.776 ms, warmup 3.775 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:52786 data_port=36325 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:36325 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=398.558ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=37.729ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=35.542ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=35.301ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep5.ndjson new file mode 100644 index 000000000..a7b2852ae --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r4-rep5.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:46499 Q2 22:output","payload_bytes":0,"prefill_sec":0.867582,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:46499 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.867582,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.485 ms, residency requested in 183.907 ms, warmup 3.848 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:38796 data_port=46499 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:46499 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=397.114ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=36.739ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=35.604ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=36.483ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.ndjson new file mode 100644 index 000000000..87c6c5ccc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001726,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001726,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.018 ms, residency requested in 398.966 ms, warmup 3.348 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.stage.ndjson new file mode 100644 index 000000000..e25aadafe --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:60185 Q2 22:output","payload_bytes":15423992,"prefill_sec":1.177875,"stage_sec":0.467422,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:60185 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":1.177875,"stage_sec_max":0.467422,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.492s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60301 data_port=60185 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:60185 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=359.044ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=25.302ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=23.499ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=23.382ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60301 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.worker.log new file mode 100644 index 000000000..eff395f49 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep1.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.236 ms, residency requested in 167.625 ms, warmup 4.184 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:60185 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.ndjson new file mode 100644 index 000000000..5cd104d2b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001841,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001841,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.135 ms, residency requested in 356.073 ms, warmup 3.784 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.stage.ndjson new file mode 100644 index 000000000..895ec0793 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:60353 Q2 22:output","payload_bytes":15423992,"prefill_sec":1.150112,"stage_sec":0.542158,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:60353 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":1.150112,"stage_sec_max":0.542158,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.628s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60472 data_port=60353 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:60353 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=366.943ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=26.667ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=23.152ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=23.123ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60472 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.worker.log new file mode 100644 index 000000000..e709ba60c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep2.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.232 ms, residency requested in 175.953 ms, warmup 4.288 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:60353 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.ndjson new file mode 100644 index 000000000..11110996e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.002259,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.002259,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.953 ms, residency requested in 351.540 ms, warmup 3.718 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.stage.ndjson new file mode 100644 index 000000000..57b700fad --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:60491 Q2 22:output","payload_bytes":15423992,"prefill_sec":1.050188,"stage_sec":0.482006,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:60491 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":1.050188,"stage_sec_max":0.482006,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.561s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60609 data_port=60491 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:60491 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=339.190ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=16.738ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=15.124ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=14.309ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60609 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.worker.log new file mode 100644 index 000000000..1e61c1fcc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep3.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.259 ms, residency requested in 178.436 ms, warmup 4.170 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:60491 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.ndjson new file mode 100644 index 000000000..e985bb187 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001951,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001951,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.809 ms, residency requested in 352.523 ms, warmup 4.139 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.stage.ndjson new file mode 100644 index 000000000..80611a3b7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:60631 Q2 22:output","payload_bytes":15423992,"prefill_sec":1.019775,"stage_sec":0.624789,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:60631 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":1.019775,"stage_sec_max":0.624789,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.627s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60740 data_port=60631 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:60631 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=362.651ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=25.548ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=23.096ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=36.060ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60740 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.worker.log new file mode 100644 index 000000000..c4693d939 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep4.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.245 ms, residency requested in 188.452 ms, warmup 4.214 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:60631 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.ndjson new file mode 100644 index 000000000..b7f944ba2 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.002125,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.002125,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":69,"top1_cand":37,"top5_overlap":3,"top20_overlap":14,"top64_overlap":54,"rms":1.25698996,"max_abs":6.82095432,"top20_max_abs":3.86825752,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.774877012},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.725 ms, residency requested in 343.774 ms, warmup 3.740 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.stage.ndjson new file mode 100644 index 000000000..a3c518f22 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:60760 Q2 22:output","payload_bytes":15423992,"prefill_sec":1.044991,"stage_sec":0.529109,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:60760 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":1.044991,"stage_sec_max":0.529109,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":false,"selected_mismatch_step":1,"missing_top_count":0,"max_logprob_delta":0.85852015},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.642s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:60876 data_port=60760 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:60760 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=355.367ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=24.344ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=23.082ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=22.871ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:60876 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.worker.log new file mode 100644 index 000000000..8d7d14283 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r5-rep5.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.341 ms, residency requested in 175.878 ms, warmup 4.478 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:60760 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.ndjson new file mode 100644 index 000000000..7ce78d1a7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.017603,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.017603,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.409s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.stage.ndjson new file mode 100644 index 000000000..ed7708db7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep1.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:39139 Q2 22:output","payload_bytes":15423992,"prefill_sec":0.871168,"stage_sec":0.058521,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:39139 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":0.871168,"stage_sec_max":0.058521,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.387 ms, residency requested in 181.823 ms, warmup 4.212 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:34234 data_port=39139 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:39139 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=406.664ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=34.972ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=33.410ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=33.051ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.ndjson new file mode 100644 index 000000000..59d495a22 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.077695,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.077695,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.511s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.stage.ndjson new file mode 100644 index 000000000..b5a9287da --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep2.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:37197 Q2 22:output","payload_bytes":15423992,"prefill_sec":0.857564,"stage_sec":0.055549,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:37197 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":0.857564,"stage_sec_max":0.055549,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.545 ms, residency requested in 178.726 ms, warmup 4.284 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:46346 data_port=37197 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:37197 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=399.660ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=37.550ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=33.123ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=33.535ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.ndjson new file mode 100644 index 000000000..ae9e9d7d7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.090599,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.090599,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.261s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.stage.ndjson new file mode 100644 index 000000000..d70ba69b9 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep3.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:46749 Q2 22:output","payload_bytes":15423992,"prefill_sec":0.867843,"stage_sec":0.053800,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:46749 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":0.867843,"stage_sec_max":0.053800,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.276 ms, residency requested in 178.378 ms, warmup 3.734 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:57738 data_port=46749 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:46749 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=398.301ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=35.749ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=34.185ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=34.411ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.ndjson new file mode 100644 index 000000000..28f742ac0 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.021906,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.021906,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.573s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.stage.ndjson new file mode 100644 index 000000000..37650ca94 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep4.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:37203 Q2 22:output","payload_bytes":15423992,"prefill_sec":0.851142,"stage_sec":0.081221,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:37203 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":0.851142,"stage_sec_max":0.081221,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.393 ms, residency requested in 180.542 ms, warmup 3.961 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:52478 data_port=37203 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:37203 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=397.923ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=36.500ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=34.104ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=35.021ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.ndjson new file mode 100644 index 000000000..dd1381e02 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":15423992,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.018999,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":15423992,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.018999,"parity":{"envelope":"fail","first_top1_mismatch_step":1,"top1_ref":37,"top1_cand":69,"top5_overlap":3,"top20_overlap":14,"top64_overlap":49,"rms":1.30479431,"max_abs":6.16060066,"top20_max_abs":4.51215744,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.370s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.stage.ndjson new file mode 100644 index 000000000..983a65eba --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_code_completion-r6-rep5.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:42005 Q2 22:output","payload_bytes":15423992,"prefill_sec":0.856440,"stage_sec":0.091218,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_code_completion","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:42005 Q2 22:output","payload_bytes_max":15423992,"prefill_sec_max":0.856440,"stage_sec_max":0.091218,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":9854,"top1_cand":9854,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.178744242},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.319 ms, residency requested in 179.127 ms, warmup 3.742 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:40422 data_port=42005 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:42005 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=27 eval=395.554ms downstream_wait=0.000ms forward_send=0.000ms input=1.69MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=27 tokens=1 eval=35.907ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=28 tokens=1 eval=34.823ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=29 tokens=1 eval=35.579ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep1.ndjson new file mode 100644 index 000000000..2c727843c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.631759,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.631759,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.377s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep2.ndjson new file mode 100644 index 000000000..682a202b8 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.633585,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.633585,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.290s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep3.ndjson new file mode 100644 index 000000000..d209ef2b7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.628849,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.628849,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.390s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep4.ndjson new file mode 100644 index 000000000..915fddc8a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.679279,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.679279,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.300s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep5.ndjson new file mode 100644 index 000000000..c1679bcb5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r1-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.645262,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.645262,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000240828318},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.332s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep1.ndjson new file mode 100644 index 000000000..74eacb946 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.263814,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.263814,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.068 ms, residency requested in 347.025 ms, warmup 3.410 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep2.ndjson new file mode 100644 index 000000000..650c2fa0e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.260945,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.260945,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.553 ms, residency requested in 347.785 ms, warmup 3.434 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep3.ndjson new file mode 100644 index 000000000..41a43e3fc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.262827,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.262827,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.283 ms, residency requested in 345.970 ms, warmup 4.166 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep4.ndjson new file mode 100644 index 000000000..5e1525a04 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.262581,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.262581,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.912 ms, residency requested in 338.250 ms, warmup 3.242 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep5.ndjson new file mode 100644 index 000000000..8884f970f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r2-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.262970,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.262970,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000227290249},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.195 ms, residency requested in 344.469 ms, warmup 3.872 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.ndjson new file mode 100644 index 000000000..645b80278 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:58700 Q2 22:output","payload_bytes":0,"prefill_sec":1.157031,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:58700 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.157031,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.626s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:58801 data_port=58700 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:58700 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=313.160ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.696ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.845ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=15.057ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:58801 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.worker.log new file mode 100644 index 000000000..09299a402 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep1.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.356 ms, residency requested in 167.602 ms, warmup 4.040 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:58700 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.ndjson new file mode 100644 index 000000000..cecfd536f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:58803 Q2 22:output","payload_bytes":0,"prefill_sec":1.020994,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:58803 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.020994,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.424s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:58910 data_port=58803 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:58803 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=324.654ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.767ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.986ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.758ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:58910 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.worker.log new file mode 100644 index 000000000..04f5ba83b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep2.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.203 ms, residency requested in 168.527 ms, warmup 4.069 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:58803 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.ndjson new file mode 100644 index 000000000..50332743c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:58912 Q2 22:output","payload_bytes":0,"prefill_sec":1.106206,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:58912 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.106206,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.668s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59029 data_port=58912 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:58912 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=326.655ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.721ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.888ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.947ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59029 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.worker.log new file mode 100644 index 000000000..2a4a6ed15 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep3.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.287 ms, residency requested in 167.496 ms, warmup 3.620 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:58912 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.ndjson new file mode 100644 index 000000000..41c21e2fb --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59032 Q2 22:output","payload_bytes":0,"prefill_sec":1.029336,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59032 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.029336,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.558s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59151 data_port=59032 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59032 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=333.581ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.518ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.762ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.855ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59151 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.worker.log new file mode 100644 index 000000000..d54c6c407 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep4.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.482 ms, residency requested in 166.017 ms, warmup 4.233 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59032 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.ndjson new file mode 100644 index 000000000..822b2e508 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59153 Q2 22:output","payload_bytes":0,"prefill_sec":1.065392,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59153 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.065392,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.435s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59266 data_port=59153 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59153 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=334.561ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.786ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.691ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.300ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59266 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.worker.log new file mode 100644 index 000000000..aa9543d2d --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r3-rep5.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 2.551 ms, residency requested in 165.748 ms, warmup 3.445 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59153 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep1.ndjson new file mode 100644 index 000000000..c4b23fdac --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep1.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:34485 Q2 22:output","payload_bytes":0,"prefill_sec":0.862674,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:34485 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.862674,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.457 ms, residency requested in 180.671 ms, warmup 4.011 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:54948 data_port=34485 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:34485 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=388.850ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=36.201ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=36.950ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=36.455ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep2.ndjson new file mode 100644 index 000000000..84341d9c9 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep2.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:35191 Q2 22:output","payload_bytes":0,"prefill_sec":0.832267,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:35191 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.832267,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.258 ms, residency requested in 182.825 ms, warmup 4.072 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:44636 data_port=35191 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:35191 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=376.541ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=34.519ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=33.550ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=34.256ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep3.ndjson new file mode 100644 index 000000000..6acab10e7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep3.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:39737 Q2 22:output","payload_bytes":0,"prefill_sec":0.823492,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:39737 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.823492,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.492 ms, residency requested in 181.951 ms, warmup 3.348 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:39092 data_port=39737 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:39737 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=385.906ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=36.746ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=34.235ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=36.005ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep4.ndjson new file mode 100644 index 000000000..abe7e5405 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep4.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:40165 Q2 22:output","payload_bytes":0,"prefill_sec":0.822151,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:40165 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.822151,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.306 ms, residency requested in 182.767 ms, warmup 3.447 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:45556 data_port=40165 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:40165 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=379.988ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=36.278ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=34.286ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=36.881ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep5.ndjson new file mode 100644 index 000000000..7875a90a5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r4-rep5.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:35375 Q2 22:output","payload_bytes":0,"prefill_sec":0.841012,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:35375 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.841012,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.411 ms, residency requested in 182.307 ms, warmup 3.589 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:49832 data_port=35375 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:35375 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=385.658ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=2 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=38.377ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=36.171ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=36.083ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.ndjson new file mode 100644 index 000000000..c943173e3 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.002197,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.002197,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.650 ms, residency requested in 336.124 ms, warmup 4.034 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.stage.ndjson new file mode 100644 index 000000000..9f04322dd --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59288 Q2 22:output","payload_bytes":14841824,"prefill_sec":0.902896,"stage_sec":0.433833,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59288 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":0.902896,"stage_sec_max":0.433833,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.691s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59353 data_port=59288 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59288 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=330.724ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.683ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=14.263ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.801ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59353 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.worker.log new file mode 100644 index 000000000..fb130855c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep1.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.263 ms, residency requested in 164.477 ms, warmup 3.545 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59288 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.ndjson new file mode 100644 index 000000000..a824eae03 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001650,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001650,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.016 ms, residency requested in 391.262 ms, warmup 4.059 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.stage.ndjson new file mode 100644 index 000000000..0e8bc8364 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59365 Q2 22:output","payload_bytes":14841824,"prefill_sec":1.024837,"stage_sec":0.521133,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59365 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":1.024837,"stage_sec_max":0.521133,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.809s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59435 data_port=59365 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59365 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=332.690ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=23.456ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=14.837ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.981ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59435 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.worker.log new file mode 100644 index 000000000..ab43786f6 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep2.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.277 ms, residency requested in 167.294 ms, warmup 4.038 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59365 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.ndjson new file mode 100644 index 000000000..f54fd5c14 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.002357,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.002357,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.741 ms, residency requested in 337.212 ms, warmup 3.778 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.stage.ndjson new file mode 100644 index 000000000..d82331db8 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59447 Q2 22:output","payload_bytes":14841824,"prefill_sec":1.019648,"stage_sec":0.441911,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59447 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":1.019648,"stage_sec_max":0.441911,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.529s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59510 data_port=59447 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59447 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=314.484ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.630ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.734ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.786ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59510 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.worker.log new file mode 100644 index 000000000..2aa2b4e19 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep3.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.159 ms, residency requested in 167.513 ms, warmup 3.901 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59447 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.ndjson new file mode 100644 index 000000000..8e0fea2b4 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001848,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001848,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.765 ms, residency requested in 332.914 ms, warmup 3.312 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.stage.ndjson new file mode 100644 index 000000000..6b8ec5df9 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59522 Q2 22:output","payload_bytes":14841824,"prefill_sec":1.047459,"stage_sec":0.438060,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59522 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":1.047459,"stage_sec_max":0.438060,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.675s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59587 data_port=59522 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59522 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=318.027ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.993ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.802ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.707ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59587 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.worker.log new file mode 100644 index 000000000..622c7f5d7 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep4.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.257 ms, residency requested in 165.422 ms, warmup 3.971 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59522 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.ndjson new file mode 100644 index 000000000..1d781a16c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001689,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001689,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":56,"rms":0.663591683,"max_abs":3.45166492,"top20_max_abs":2.00315094,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 31.306 ms, residency requested in 348.980 ms, warmup 3.309 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.stage.ndjson new file mode 100644 index 000000000..71c0eb25b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.stage.ndjson @@ -0,0 +1,23 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:59598 Q2 22:output","payload_bytes":14841824,"prefill_sec":0.981441,"stage_sec":0.466192,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:59598 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":0.981441,"stage_sec_max":0.466192,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000264710223},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.538s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:59691 data_port=59598 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:59598 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=331.668ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=14.767ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=13.263ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=14.212ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:59691 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.worker.log new file mode 100644 index 000000000..47fcca905 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r5-rep5.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.269 ms, residency requested in 165.201 ms, warmup 3.514 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:59598 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.ndjson new file mode 100644 index 000000000..c0c3be756 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.074400,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.074400,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.647s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.stage.ndjson new file mode 100644 index 000000000..7a2605710 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep1.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:37761 Q2 22:output","payload_bytes":14841824,"prefill_sec":0.829840,"stage_sec":0.087672,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:37761 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":0.829840,"stage_sec_max":0.087672,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.467 ms, residency requested in 181.738 ms, warmup 4.073 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:41780 data_port=37761 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:37761 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=371.441ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=36.571ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=34.822ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=35.476ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.ndjson new file mode 100644 index 000000000..54d06a016 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.082793,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.082793,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.642s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.stage.ndjson new file mode 100644 index 000000000..534728273 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep2.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:37961 Q2 22:output","payload_bytes":14841824,"prefill_sec":0.839199,"stage_sec":0.050324,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:37961 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":0.839199,"stage_sec_max":0.050324,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.247 ms, residency requested in 179.448 ms, warmup 4.058 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:55054 data_port=37961 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:37961 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=380.826ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=37.486ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=34.256ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=36.517ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.ndjson new file mode 100644 index 000000000..9a8cce5c1 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.016623,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.016623,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.642s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.stage.ndjson new file mode 100644 index 000000000..578ff4539 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep3.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:46863 Q2 22:output","payload_bytes":14841824,"prefill_sec":0.839939,"stage_sec":0.089898,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:46863 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":0.839939,"stage_sec_max":0.089898,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.317 ms, residency requested in 183.485 ms, warmup 3.985 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:52918 data_port=46863 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:46863 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=382.685ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=35.322ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=36.051ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=36.627ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.ndjson new file mode 100644 index 000000000..244ce714e --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.018788,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.018788,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.700s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.stage.ndjson new file mode 100644 index 000000000..1c5606642 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep4.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:38313 Q2 22:output","payload_bytes":14841824,"prefill_sec":0.833431,"stage_sec":0.054434,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:38313 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":0.833431,"stage_sec_max":0.054434,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.604 ms, residency requested in 184.735 ms, warmup 3.285 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:42402 data_port=38313 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:38313 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=379.322ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=37.707ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=34.905ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=35.419ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.ndjson new file mode 100644 index 000000000..e8cf8f427 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14841824,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.019796,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14841824,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.019796,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":4,"top20_overlap":18,"top64_overlap":58,"rms":0.688694775,"max_abs":4.14918375,"top20_max_abs":2.99796295,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.575s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.stage.ndjson new file mode 100644 index 000000000..66b49246d --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_italian_fact-r6-rep5.stage.ndjson @@ -0,0 +1,19 @@ +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:43073 Q2 22:output","payload_bytes":14841824,"prefill_sec":0.842974,"stage_sec":0.049425,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_italian_fact","ctx":16384,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:43073 Q2 22:output","payload_bytes_max":14841824,"prefill_sec_max":0.842974,"stage_sec_max":0.049425,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":108149,"top1_cand":108149,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.000175568683},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.318 ms, residency requested in 180.307 ms, warmup 4.069 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:42884 data_port=43073 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=16384 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:43073 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=21 eval=380.988ms downstream_wait=0.000ms forward_send=0.000ms input=1.31MiB output=0.49MiB +ds4: distributed telemetry: request=3 hop=0 layers=22:42 route=0 pos=21 tokens=1 eval=36.067ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=4 hop=0 layers=22:42 route=0 pos=22 tokens=1 eval=36.099ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed telemetry: request=5 hop=0 layers=22:42 route=0 pos=23 tokens=1 eval=36.256ms downstream_wait=0.000ms forward_send=0.000ms input=0.06MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep1.ndjson new file mode 100644 index 000000000..4f01d1a44 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.624351,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.624351,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.497s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep2.ndjson new file mode 100644 index 000000000..85461d7bd --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.621226,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.621226,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.807s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep3.ndjson new file mode 100644 index 000000000..8df6d0890 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.632652,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.632652,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.428s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep4.ndjson new file mode 100644 index 000000000..0e476e89b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.623621,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.623621,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.563s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep5.ndjson new file mode 100644 index 000000000..d15fa674b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r1-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.625412,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.625412,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0258535184},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.413s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep1.ndjson new file mode 100644 index 000000000..0b6200dc9 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.257710,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.257710,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.114 ms, residency requested in 341.749 ms, warmup 4.078 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep2.ndjson new file mode 100644 index 000000000..5c7bc0ab8 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.257719,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.257719,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.234 ms, residency requested in 343.539 ms, warmup 3.485 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep3.ndjson new file mode 100644 index 000000000..e672265e3 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.256206,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.256206,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.315 ms, residency requested in 339.298 ms, warmup 3.969 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep4.ndjson new file mode 100644 index 000000000..9985ab746 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.256841,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.256841,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.031 ms, residency requested in 346.578 ms, warmup 3.346 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep5.ndjson new file mode 100644 index 000000000..3189daf55 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r2-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local","payload_bytes":0,"prefill_sec":0.257989,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"local","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local","payload_bytes_max":0,"prefill_sec_max":0.257989,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0112166749},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.976 ms, residency requested in 345.833 ms, warmup 4.244 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.ndjson new file mode 100644 index 000000000..cc2674f0b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61048 Q2 22:output","payload_bytes":0,"prefill_sec":1.128012,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61048 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.128012,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.519s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61162 data_port=61048 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61048 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=327.804ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61162 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.worker.log new file mode 100644 index 000000000..f4244d8d5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep1.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.652 ms, residency requested in 168.391 ms, warmup 3.550 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61048 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.ndjson new file mode 100644 index 000000000..6195b3d67 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61165 Q2 22:output","payload_bytes":0,"prefill_sec":1.077613,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61165 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.077613,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.622s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61280 data_port=61165 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61165 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=333.400ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61280 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.worker.log new file mode 100644 index 000000000..2da5424bc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep2.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.181 ms, residency requested in 168.026 ms, warmup 3.684 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61165 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.ndjson new file mode 100644 index 000000000..b27103033 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61282 Q2 22:output","payload_bytes":0,"prefill_sec":0.929333,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61282 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.929333,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.597s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61402 data_port=61282 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61282 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=329.367ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61402 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.worker.log new file mode 100644 index 000000000..bd2dd375f --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep3.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.307 ms, residency requested in 165.375 ms, warmup 3.552 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61282 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.ndjson new file mode 100644 index 000000000..3aa2bd004 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61406 Q2 22:output","payload_bytes":0,"prefill_sec":1.035445,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61406 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":1.035445,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.731s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61526 data_port=61406 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61406 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=326.681ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61526 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.worker.log new file mode 100644 index 000000000..c82d5c366 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep4.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.225 ms, residency requested in 167.586 ms, warmup 3.871 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61406 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.ndjson new file mode 100644 index 000000000..4113fa7e5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61528 Q2 22:output","payload_bytes":0,"prefill_sec":0.981804,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61528 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.981804,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.639s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61646 data_port=61528 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61528 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=325.095ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61646 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.worker.log new file mode 100644 index 000000000..6d0a004e5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r3-rep5.worker.log @@ -0,0 +1,12 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.281 ms, residency requested in 167.705 ms, warmup 3.642 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61528 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep1.ndjson new file mode 100644 index 000000000..056fc654c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep1.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:41731 Q2 22:output","payload_bytes":0,"prefill_sec":0.826231,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:41731 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.826231,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.451 ms, residency requested in 179.294 ms, warmup 4.248 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:42504 data_port=41731 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:41731 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=371.987ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep2.ndjson new file mode 100644 index 000000000..376cb733c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep2.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:43371 Q2 22:output","payload_bytes":0,"prefill_sec":0.822523,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:43371 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.822523,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.399 ms, residency requested in 181.026 ms, warmup 4.295 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:50350 data_port=43371 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:43371 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=367.597ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep3.ndjson new file mode 100644 index 000000000..3bcbe0f70 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep3.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:44009 Q2 22:output","payload_bytes":0,"prefill_sec":0.826617,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:44009 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.826617,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.322 ms, residency requested in 179.948 ms, warmup 3.500 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:36366 data_port=44009 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:44009 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=374.254ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep4.ndjson new file mode 100644 index 000000000..86cbaeecb --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep4.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:34911 Q2 22:output","payload_bytes":0,"prefill_sec":0.809934,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:34911 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.809934,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.634 ms, residency requested in 187.339 ms, warmup 3.711 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:49344 data_port=34911 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:34911 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=365.682ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep5.ndjson new file mode 100644 index 000000000..87962d0c2 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r4-rep5.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:37841 Q2 22:output","payload_bytes":0,"prefill_sec":0.809573,"stage_sec":0.000000,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:37841 Q2 22:output","payload_bytes_max":0,"prefill_sec_max":0.809573,"stage_sec_max":0.000000,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.389 ms, residency requested in 184.053 ms, warmup 3.906 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:52634 data_port=37841 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:37841 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=368.559ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.ndjson new file mode 100644 index 000000000..d9ebf7b47 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001790,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001790,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.734 ms, residency requested in 349.299 ms, warmup 4.100 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.stage.ndjson new file mode 100644 index 000000000..b2cdb15cd --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.stage.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61669 Q2 22:output","payload_bytes":14523860,"prefill_sec":1.026689,"stage_sec":0.521396,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61669 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":1.026689,"stage_sec_max":0.521396,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.586s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61785 data_port=61669 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61669 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=321.903ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61785 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.worker.log new file mode 100644 index 000000000..8b31de844 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep1.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.378 ms, residency requested in 170.942 ms, warmup 3.424 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61669 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.ndjson new file mode 100644 index 000000000..7fedda8f2 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001780,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001780,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.931 ms, residency requested in 347.253 ms, warmup 3.950 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.stage.ndjson new file mode 100644 index 000000000..6cb4aca96 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.stage.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61801 Q2 22:output","payload_bytes":14523860,"prefill_sec":1.171744,"stage_sec":0.434752,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61801 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":1.171744,"stage_sec_max":0.434752,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.709s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61865 data_port=61801 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61801 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=321.295ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61865 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.worker.log new file mode 100644 index 000000000..ec2be2b6a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep2.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.389 ms, residency requested in 164.907 ms, warmup 3.937 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61801 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.ndjson new file mode 100644 index 000000000..72a9c77bc --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001725,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001725,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.355 ms, residency requested in 358.804 ms, warmup 3.907 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.stage.ndjson new file mode 100644 index 000000000..85df76d5c --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.stage.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61875 Q2 22:output","payload_bytes":14523860,"prefill_sec":0.999637,"stage_sec":0.451525,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61875 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":0.999637,"stage_sec_max":0.451525,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.515s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:61947 data_port=61875 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61875 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=328.651ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:61947 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.worker.log new file mode 100644 index 000000000..bd27c7b71 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep3.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.455 ms, residency requested in 171.784 ms, warmup 3.685 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61875 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.ndjson new file mode 100644 index 000000000..5e4e46cbd --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.001539,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.001539,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 2.157 ms, residency requested in 351.848 ms, warmup 3.640 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.stage.ndjson new file mode 100644 index 000000000..1691de53a --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.stage.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:61962 Q2 22:output","payload_bytes":14523860,"prefill_sec":1.089644,"stage_sec":0.469303,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:61962 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":1.089644,"stage_sec_max":0.469303,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.705s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:62083 data_port=61962 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:61962 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=315.092ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:62083 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.worker.log new file mode 100644 index 000000000..39c56bd01 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep4.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.303 ms, residency requested in 169.365 ms, warmup 4.144 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:61962 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.ndjson new file mode 100644 index 000000000..9e43419b5 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.ndjson @@ -0,0 +1,10 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.002033,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.002033,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":61,"rms":0.382280707,"max_abs":2.11430359,"top20_max_abs":0.671966553,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: Metal model views created in 1.718 ms, residency requested in 352.916 ms, warmup 3.807 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.stage.ndjson new file mode 100644 index 000000000..c8b927568 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.stage.ndjson @@ -0,0 +1,20 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 192.168.1.218:62101 Q2 22:output","payload_bytes":14523860,"prefill_sec":0.931191,"stage_sec":0.481326,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 192.168.1.218:62101 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":0.931191,"stage_sec_max":0.481326,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.034484677},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.541s +ds4: cuda backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 192.168.1.98:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 192.168.1.218:62218 data_port=62101 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 192.168.1.218:62101 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=307.863ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: removed worker 192.168.1.218:62218 layers=22:42+output +ds4: distributed coordinator: route incomplete; next needed layer 22 diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.worker.log b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.worker.log new file mode 100644 index 000000000..f270a6624 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r5-rep5.worker.log @@ -0,0 +1,13 @@ +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 22:output (46 spans, 39.25 GiB tensor span) +ds4: Metal model views created in 1.443 ms, residency requested in 166.635 ms, warmup 4.013 ms (mapped 40194.02 MiB from offset 38029.96 MiB) +ds4: Metal mapped mmaped model as 46 disjoint shared buffers across 46 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed worker: layers 22:output model_id=0 data_listen=*:62101 connecting to coordinator 192.168.1.98:1234 +ds4: distributed worker: connected to coordinator 192.168.1.98:1234 +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: receive prefetch depth 2 enabled +ds4: distributed worker: cleared 1 sessions after coordinator disconnect +ds4: distributed worker: coordinator disconnected; reconnecting diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.ndjson new file mode 100644 index 000000000..d9506d384 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.017289,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.017289,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.875s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.stage.ndjson new file mode 100644 index 000000000..e1cbfc687 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep1.stage.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:46563 Q2 22:output","payload_bytes":14523860,"prefill_sec":0.808564,"stage_sec":0.082003,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:46563 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":0.808564,"stage_sec_max":0.082003,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.458 ms, residency requested in 181.408 ms, warmup 3.768 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:57776 data_port=46563 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:46563 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=372.413ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.ndjson new file mode 100644 index 000000000..9a9f542bf --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.017476,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.017476,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.394s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.stage.ndjson new file mode 100644 index 000000000..760546b03 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep2.stage.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:40755 Q2 22:output","payload_bytes":14523860,"prefill_sec":0.809955,"stage_sec":0.051421,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:40755 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":0.809955,"stage_sec_max":0.051421,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.511 ms, residency requested in 182.573 ms, warmup 3.578 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:60180 data_port=40755 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:40755 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=364.388ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.ndjson new file mode 100644 index 000000000..1cc66baaf --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.016869,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.016869,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.552s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.stage.ndjson new file mode 100644 index 000000000..bf4d647a9 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep3.stage.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:41045 Q2 22:output","payload_bytes":14523860,"prefill_sec":0.824750,"stage_sec":0.051403,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:41045 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":0.824750,"stage_sec_max":0.051403,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.401 ms, residency requested in 182.394 ms, warmup 3.775 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:51600 data_port=41045 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:41045 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=374.764ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.ndjson new file mode 100644 index 000000000..55e2d8196 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.066301,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.066301,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.480s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.stage.ndjson new file mode 100644 index 000000000..f99ad426b --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep4.stage.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:33553 Q2 22:output","payload_bytes":14523860,"prefill_sec":0.812139,"stage_sec":0.056230,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:33553 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":0.812139,"stage_sec_max":0.056230,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.523 ms, residency requested in 183.647 ms, warmup 3.574 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:39482 data_port=33553 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:33553 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=369.892ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.ndjson new file mode 100644 index 000000000..f7d3c5d38 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.ndjson @@ -0,0 +1,20 @@ +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"payload","payload_bytes":14523860,"prefill_sec":0.000000,"stage_sec":0.000000,"load_sec":0.068022,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"payload","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"payload","payload_bytes_max":14523860,"prefill_sec_max":0.000000,"stage_sec_max":0.000000,"load_sec_max":0.068022,"parity":{"envelope":"tolerant","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":18,"top64_overlap":59,"rms":0.504765928,"max_abs":2.56024551,"top20_max_abs":0.883335114,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings +ds4: CUDA loading model tensors into device cache +ds4: CUDA loading model tensors 16.02 GiB cached +ds4: CUDA prepared model tensor mappings 16.37 GiB +ds4: CUDA loading model tensors 32.06 GiB cached +ds4: CUDA prepared model tensor mappings 32.07 GiB +ds4: CUDA loading model tensors 48.02 GiB cached +ds4: CUDA prepared model tensor mappings 48.43 GiB +ds4: CUDA loading model tensors 64.06 GiB cached +ds4: CUDA prepared model tensor mappings 64.13 GiB +ds4: CUDA loading model tensors 80.04 GiB cached +ds4: CUDA prepared model tensor mappings 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.539s +ds4: cuda backend initialized for graph diagnostics diff --git a/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.stage.ndjson b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.stage.ndjson new file mode 100644 index 000000000..9eaafb3cb --- /dev/null +++ b/artifacts/issue-304/phase35/raw/official-short_reasoning_plain-r6-rep5.stage.ndjson @@ -0,0 +1,16 @@ +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"repeat":1,"ok":true,"route_summary":"local 0:21 -> 10.77.0.2:42605 Q2 22:output","payload_bytes":14523860,"prefill_sec":0.818807,"stage_sec":0.051638,"load_sec":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0},"error":""} +{"mode":"distributed","suite":"official","case":"short_reasoning_plain","ctx":4096,"worst_at_1":{"passes":1,"route_summary":"local 0:21 -> 10.77.0.2:42605 Q2 22:output","payload_bytes_max":14523860,"prefill_sec_max":0.818807,"stage_sec_max":0.051638,"load_sec_max":0.000000,"parity":{"envelope":"strict","first_top1_mismatch_step":-1,"top1_ref":926,"top1_cand":926,"top5_overlap":5,"top20_overlap":20,"top64_overlap":64,"rms":0,"max_abs":0,"top20_max_abs":0,"nonfinite":0},"official":{"pass":true,"selected_mismatch_step":-1,"missing_top_count":0,"max_logprob_delta":0.0139614902},"golden":{"pass":false,"top1":0,"top5_overlap":0,"top20_overlap":0,"top64_overlap":0,"top20_max_abs":0}}} + +# STDERR +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: restricting metal model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: Metal model views created in 1.787 ms, residency requested in 185.801 ms, warmup 4.115 ms (mapped 43041.81 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 48 disjoint shared buffers across 48 tensor spans +ds4: metal backend initialized for graph diagnostics +ds4: distributed coordinator API: listening on 10.77.0.1:1234 model_id=0 layers=43 local=0:21 activation_bits=32 +ds4: distributed coordinator: registered worker 10.77.0.2:44852 data_port=42605 model_id=0 quant=Q2 layers=22:output hidden=1 ctx=4096 +ds4: distributed coordinator: complete route ready: local 0:21 -> 10.77.0.2:42605 Q2 22:output +ds4: distributed telemetry: request=1 hop=0 layers=22:42 route=0 pos=0 tokens=18 eval=362.121ms downstream_wait=0.000ms forward_send=0.000ms input=1.13MiB output=0.49MiB +ds4: distributed coordinator: accept failed: Software caused connection abort diff --git a/artifacts/issue-304/phase35/raw/phase35-summary.ndjson b/artifacts/issue-304/phase35/raw/phase35-summary.ndjson new file mode 100644 index 000000000..7843dba84 --- /dev/null +++ b/artifacts/issue-304/phase35/raw/phase35-summary.ndjson @@ -0,0 +1,6 @@ +{"route": "route1", "mode": "local", "suite": "local-golden", "case": "long_story_4096", "ctx": 5000, "worst_at_5": {"passes": 5, "route_summary": "local", "payload_bytes_max": 0, "prefill_sec_max": 19.855204, "stage_sec_max": 0.0, "load_sec_max": 0.0, "parity": {"envelope": "fail", "first_top1_mismatch_step": -1, "top1_ref": 4371, "top1_cand": 4371, "top5_overlap": 2, "top20_overlap": 13, "top64_overlap": 44, "rms": 2.12094522, "max_abs": 15.0152826, "top20_max_abs": 8.60928154, "nonfinite": 0}, "official": {"pass": false, "selected_mismatch_step": -1, "missing_top_count": 0, "max_logprob_delta": 0.0}, "golden": {"pass": true, "top1": 4371, "top5_overlap": 4, "top20_overlap": 17, "top64_overlap": 52, "top20_max_abs": 3.07355976}}} +{"route": "route2", "mode": "local", "suite": "local-golden", "case": "long_story_4096", "ctx": 5000, "worst_at_5": {"passes": 5, "route_summary": "local", "payload_bytes_max": 0, "prefill_sec_max": 8.933015, "stage_sec_max": 0.0, "load_sec_max": 0.0, "parity": {"envelope": "strict", "first_top1_mismatch_step": -1, "top1_ref": 4371, "top1_cand": 4371, "top5_overlap": 5, "top20_overlap": 20, "top64_overlap": 64, "rms": 0.0, "max_abs": 0.0, "top20_max_abs": 0.0, "nonfinite": 0}, "official": {"pass": false, "selected_mismatch_step": -1, "missing_top_count": 0, "max_logprob_delta": 0.0}, "golden": {"pass": false, "top1": 4371, "top5_overlap": 3, "top20_overlap": 16, "top64_overlap": 46, "top20_max_abs": 5.2168293}}} +{"route": "route3", "mode": "distributed", "suite": "local-golden", "case": "long_story_4096", "ctx": 5000, "worst_at_5": {"passes": 5, "route_summary": "local 0:21 -> 192.168.1.218:64488 Q2 22:output", "payload_bytes_max": 0, "prefill_sec_max": 15.193016, "stage_sec_max": 0.0, "load_sec_max": 0.0, "parity": {"envelope": "strict", "first_top1_mismatch_step": -1, "top1_ref": 4371, "top1_cand": 4371, "top5_overlap": 5, "top20_overlap": 20, "top64_overlap": 64, "rms": 0.0, "max_abs": 0.0, "top20_max_abs": 0.0, "nonfinite": 0}, "official": {"pass": false, "selected_mismatch_step": -1, "missing_top_count": 0, "max_logprob_delta": 0.0}, "golden": {"pass": true, "top1": 4371, "top5_overlap": 4, "top20_overlap": 16, "top64_overlap": 50, "top20_max_abs": 3.56194687}}} +{"route": "route4", "mode": "distributed", "suite": "local-golden", "case": "long_story_4096", "ctx": 5000, "worst_at_5": {"passes": 5, "route_summary": "local 0:21 -> 10.77.0.2:46557 Q2 22:output", "payload_bytes_max": 0, "prefill_sec_max": 11.275562, "stage_sec_max": 0.0, "load_sec_max": 0.0, "parity": {"envelope": "strict", "first_top1_mismatch_step": -1, "top1_ref": 4371, "top1_cand": 4371, "top5_overlap": 5, "top20_overlap": 20, "top64_overlap": 64, "rms": 0.0, "max_abs": 0.0, "top20_max_abs": 0.0, "nonfinite": 0}, "official": {"pass": false, "selected_mismatch_step": -1, "missing_top_count": 0, "max_logprob_delta": 0.0}, "golden": {"pass": true, "top1": 4371, "top5_overlap": 4, "top20_overlap": 16, "top64_overlap": 53, "top20_max_abs": 3.55953407}}} +{"route": "route5", "mode": "payload", "suite": "local-golden", "case": "long_story_4096", "ctx": 5000, "worst_at_5": {"passes": 5, "route_summary": "payload", "payload_bytes_max": 80373132, "prefill_sec_max": 0.0, "stage_sec_max": 0.0, "load_sec_max": 0.011227, "parity": {"envelope": "fail", "first_top1_mismatch_step": -1, "top1_ref": 4371, "top1_cand": 4371, "top5_overlap": 3, "top20_overlap": 13, "top64_overlap": 42, "rms": 2.14919782, "max_abs": 14.7165461, "top20_max_abs": 5.82323074, "nonfinite": 0}, "official": {"pass": false, "selected_mismatch_step": -1, "missing_top_count": 0, "max_logprob_delta": 0.0}, "golden": {"pass": true, "top1": 4371, "top5_overlap": 4, "top20_overlap": 16, "top64_overlap": 51, "top20_max_abs": 2.24486637}}} +{"route": "route6", "mode": "payload", "suite": "local-golden", "case": "long_story_4096", "ctx": 5000, "worst_at_5": {"passes": 5, "route_summary": "payload", "payload_bytes_max": 80373132, "prefill_sec_max": 0.0, "stage_sec_max": 0.0, "load_sec_max": 0.088323, "parity": {"envelope": "tolerant", "first_top1_mismatch_step": -1, "top1_ref": 4371, "top1_cand": 4371, "top5_overlap": 3, "top20_overlap": 14, "top64_overlap": 40, "rms": 1.60283542, "max_abs": 8.42455864, "top20_max_abs": 4.52456474, "nonfinite": 0}, "official": {"pass": false, "selected_mismatch_step": -1, "missing_top_count": 0, "max_logprob_delta": 0.0}, "golden": {"pass": true, "top1": 4371, "top5_overlap": 4, "top20_overlap": 16, "top64_overlap": 52, "top20_max_abs": 3.03334045}}} diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index 2fc0aa51e..97a6af4c0 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -9,8 +9,9 @@ This file tracks phase-wise findings for the staged investigation in `PLAN.md`. | Phase 0 | Complete | The DGX/Mac baseline ran end-to-end, and the earlier merged-`DSV4` stage failure was narrowed to a worker/coordinator `ctx` mismatch rather than a backend or route-format incompatibility. | | Phase 1 | Complete | The payload resume matrix is now filled: `Metal -> Metal`, `CUDA -> CUDA`, and `Metal -> CUDA` passed, while `CUDA -> Metal` preserved restore-point logits but diverged during subsequent greedy decode. | | Phase 2 | Complete | Distributed prefill -> merged `DSV4` -> fresh local Metal load now validates end-to-end on the DGX/Mac route. Handoff logits and 16-token greedy continuation matched, but forced-token logits still diverged at the first post-load eval step. | -| Phase 3 | Not started | Re-scoped to prove distributed-prefill-to-local decode matches fully local inference on the same decode engine against the official-vector/local-golden correctness surfaces, while classifying any remaining cross-engine forced-logit drift. | -| Later phases | Not started | Engine residency, user-facing workflow, and pipelined KV return remain open after Phase 3 classification. | +| Phase 3 | Complete | Same-backend Phase 3 parity was measured and rejected. The official-vector gate kept passing, but distributed-prefill-to-local decode did not match a fresh fully local Metal baseline closely enough, and the long local-golden continuation failed outright on same-backend parity. | +| Phase 3.5 | Complete | The six-route worst@5 matrix is now measured. Official top-logprob variance is route-dependent on short prompts, resumed payload routes remain the weakest parity cells, and the stored local-golden fixture is not anchored purely to the local Metal route. | +| Later phases | Deferred | Engine residency, user-facing workflow, and pipelined KV return stay deferred until the same-backend resumed-decode mismatch is fixed or localized. | ## Phase 0: Establish distributed baseline @@ -238,21 +239,57 @@ Phase 2 is no longer blocked on distributed gather, payload staging, or initial ## Phase 3: Handoff equivalence and drift isolation -### Current status +### What was completed -Not started. +- Added `tests/issue304_phase3_vectors` and built it locally and on `dgx-direct:~/ds4`. +- Verified the local and DGX GGUF hashes matched exactly: + - `efc7ed607ff27076e3e501fc3fefefa33c0ed8cf1eff483a2b7fdc0c2e616668` +- Re-ran the local control gates: + - `./ds4_test --logprob-vectors`: pass + - `./ds4_test --local-golden-vectors`: pass +- Ran Phase 3 against the authoritative DGX/Mac topology in three aligned layout groups: + - official vectors at `ctx=4096`, worker `DS4_METAL_PREFILL_CHUNK=2048` + - official vectors at `ctx=16384`, worker `DS4_METAL_PREFILL_CHUNK=2048` + - local golden vector at `ctx=5000`, worker `DS4_METAL_PREFILL_CHUNK=4096` +- Repeated each group five times with one-shot coordinator runs and short pauses between runs to avoid coordinator port reuse races. -### Revised goal +### Findings -- Use `tests/test-vectors/official.vec` and the existing local golden-vector checks as the correctness reference. -- Compare distributed-prefill-to-local decode against fully local inference on the same decode backend before treating cross-engine drift as a defect. -- Keep forced-token traces as diagnostic evidence, but do not require bit-exact cross-engine logits if selected tokens and official/local-golden gates remain stable. +1. Phase 3 rejects the “cross-engine variance only” explanation. + - The decode engine on the coordinator side stayed Metal for both the fresh local baseline and the resumed local handoff path. + - Despite that same-backend comparison, the resumed handoff path still drifted materially from the fresh local baseline. + +2. Official-vector acceptance is weaker than same-backend parity. + - Every official-vector case passed the existing selected-token/top-logprob gate on all five runs. + - The same runs still showed stable same-backend logit drift relative to a fresh local Metal baseline. + - Worst observed same-backend parity over the five official runs: + - `short_code_completion`: top20 overlap `17/20`, top64 `62/64`, `rms=0.356403291`, `max_abs=1.69900322` + - `short_reasoning_plain`: top20 overlap `20/20`, top64 `62/64`, `rms=0.327032387`, `max_abs=1.77348614` + - `short_italian_fact`: top20 overlap `19/20`, top64 `62/64`, `rms=0.21716401`, `max_abs=1.00239372` + - `long_code_audit`: top5 overlap `4/5`, top20 `15/20`, top64 `55/64`, `rms=0.876981199`, `max_abs=4.63468361` + +3. The long local-golden continuation fails same-backend parity decisively. + - The resumed handoff still passed the existing local-golden fixture on every run: + - top1 `4371` + - top20 overlap `16-17/20` + - top64 overlap `56/64` + - top20 max abs up to `3.20196915` + - But when compared directly to a fresh local Metal baseline over the next eight greedy steps, the worst-of-five parity was much looser: + - top5 overlap `3/5` + - top20 overlap `12/20` + - top64 overlap `46/64` + - `rms=2.1708498` + - `max_abs=12.3051796` + - top20 max abs `7.73109055` + +4. Phase 3 also surfaced an operational constraint beyond `ctx`. + - Merged `DSV4` staging requires worker and coordinator shard layouts to match on `prefill_cap`, not just on `ctx`. + - For the official suite this required setting worker `DS4_METAL_PREFILL_CHUNK=2048` to match the strict local vector environment. + - For the local-golden suite this required worker `DS4_METAL_PREFILL_CHUNK=4096`. -### Acceptance direction +### Implication -- Distributed prefill -> merged `DSV4` -> local decode should match fully local inference on the same decode backend for the official-vector prompt set. -- The same path should satisfy the existing official top-logprob tolerance and local-golden drift thresholds, allowing the already documented `long_memory_archive` API/official graph caveat. -- Remaining `CUDA -> Metal` forced-logit drift should be classified as accepted backend variance only after the same-backend distributed handoff checks pass. +Phase 3 did its job: the remaining drift is not just a CUDA-vs-Metal variance story. The handoff path itself differs from a same-backend fresh local Metal decode path after resumed evaluation begins. Later productization phases should stay blocked until that resumed-decode mismatch is localized or fixed. ## Pointers @@ -260,3 +297,75 @@ Not started. - [compatibility-matrix.md](/Users/lobanov/Projects/ds4/artifacts/issue-304/compatibility-matrix.md) - [logit-comparisons.md](/Users/lobanov/Projects/ds4/artifacts/issue-304/logit-comparisons.md) - [shard-metadata.md](/Users/lobanov/Projects/ds4/artifacts/issue-304/shard-metadata.md) + +## Phase 3.5: Six-route variance matrix + +### What was completed + +- Added `tests/issue304_phase35_vectors` and `tests/issue304_phase35_matrix.py`. +- Synced the tree to `dgx-direct:~/ds4`, rebuilt locally and remotely, and ran the DGX-side helper and worker with `--power 50`. +- Completed worst@5 across all six routes for: + - official vectors: `short_code_completion`, `short_reasoning_plain`, `short_italian_fact`, `long_code_audit` + - local-golden frontier: `long_story_4096` + +### Findings + +1. Official-vector variance depends on the route/backend pair. + - `short_code_completion` failed official acceptance on: + - route `1` pure local CUDA + - route `3` distributed generation `CUDA -> Metal` + - route `5` resumed `CUDA -> Metal` + - The same case passed on: + - route `2` pure local Metal + - route `4` distributed generation `Metal -> CUDA` + - route `6` resumed `Metal -> CUDA` + - The remaining official cases passed on all six routes. + +2. Resumed payload routes remain the weakest official-route cells even when they pass the official gate. + - `short_reasoning_plain`: + - route `5`: `top64=61/64`, `rms=0.382280707`, `max_abs=2.11430359` + - route `6`: `top20=18/20`, `top64=59/64`, `rms=0.504765928`, `max_abs=2.56024551` + - `short_italian_fact`: + - route `5`: `top5=4/5`, `top20=18/20`, `top64=56/64`, `rms=0.663591683` + - route `6`: `top5=4/5`, `top20=18/20`, `top64=58/64`, `rms=0.688694775` + - `long_code_audit`: + - route `5`: `top5=4/5`, `top20=16/20`, `top64=50/64`, `rms=0.972514927` + - route `6`: `top5=4/5`, `top20=15/20`, `top64=53/64`, `rms=0.903749108` + +3. Pure CUDA generation also carries visible drift on longer prompts. + - `long_code_audit` route `1` pure local CUDA still passed the official gate, but parity against its local reference was already loose: + - `top5=4/5` + - `top20=16/20` + - `top64=52/64` + - `rms=0.893455684` + - `max_abs=4.59287167` + - That matters because the resumed-route numbers are not emerging from nowhere; some longer-prompt variance is already present in the pure CUDA path. + +4. The stored local-golden fixture is not “local Metal canonical”. + - `long_story_4096` route `2` pure local Metal missed the fixture at worst@5: + - `top5=3/5` + - `top20=16/20` + - `top64=46/64` + - `top20_max_abs=5.2168293` + - Routes `1`, `3`, `4`, `5`, and `6` all passed the coarse fixture, even though the resumed routes still showed loose parity against their direct-route references. + +5. Phase 3 and Phase 3.5 together narrow the real blocker. + - Phase 3 already showed that distributed-prefill-to-local Metal resume diverges from a fresh local Metal baseline. + - Phase 3.5 adds that: + - official acceptance can still hold across several visibly different parity profiles, + - short-prompt failures are route-specific, + - longer-prompt resumed routes are still among the weakest cells. + +### Implication + +The next classification boundary is clearer now: + +- do not treat official-vector acceptance alone as proof of route equivalence, +- do not treat the stored local-golden fixture as a local-Metal oracle, +- and do not attribute all resumed-route drift to the handoff path alone without considering the existing longer-prompt CUDA variance. + +The remaining work should separate: + +- backend-specific generation variance on long prompts, +- fixture drift in `local-golden.vec`, +- and any additional error introduced specifically by distributed payload resume. diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md index fb9bcd312..35bc17fa4 100644 --- a/artifacts/issue-304/runbook.md +++ b/artifacts/issue-304/runbook.md @@ -87,7 +87,9 @@ Observed requirements and results: - Model: `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` - Local model path: `/Users/lobanov/Projects/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` - DGX model path: `/home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` -- Model hash: not recorded in this pass; `shasum -a 256` was skipped because the file is too large for a short verification loop +- Model hash: + - local: `efc7ed607ff27076e3e501fc3fefefa33c0ed8cf1eff483a2b7fdc0c2e616668` + - DGX: `efc7ed607ff27076e3e501fc3fefefa33c0ed8cf1eff483a2b7fdc0c2e616668` ## Commands @@ -223,6 +225,130 @@ Acceptance: - distributed-handoff output remains inside the local-golden drift envelope where full local logits are available - any remaining `CUDA -> Metal` forced-logit drift is classified separately as backend variance unless it causes same-backend handoff parity or official/local-vector checks to fail +### Phase 3 actual build and sync + +Build the new helper locally: + +```sh +make tests/issue304_phase3_vectors +``` + +Ship the local source tree, excluding the GGUF and local build products: + +```sh +rsync -az --delete \ + --exclude='.git/' \ + --exclude='gguf/' \ + --exclude='ds4flash.gguf' \ + --exclude='*.o' \ + --exclude='ds4' \ + --exclude='ds4-server' \ + --exclude='ds4-bench' \ + --exclude='ds4-eval' \ + --exclude='ds4-agent' \ + --exclude='ds4_test' \ + --exclude='tests/cuda_long_context_smoke' \ + --exclude='tests/test_q4k_dot' \ + --exclude='tests/issue304_phase0_local' \ + --exclude='tests/issue304_phase0_dgx' \ + --exclude='tests/issue304_phase1_matrix' \ + --exclude='tests/issue304_phase2_handoff' \ + --exclude='tests/issue304_phase3_vectors' \ + ./ dgx-direct:~/ds4/ +``` + +Build the helper remotely before starting the worker: + +```sh +ssh dgx-direct 'cd ~/ds4 && make tests/issue304_phase3_vectors' +``` + +### Phase 3 actual worker launches + +Official vectors at `ctx=4096` and `ctx=16384` require worker `prefill_cap=2048` to match the strict local vector environment: + +```sh +ssh dgx-direct 'pkill -9 ds4 >/dev/null 2>&1 || true; sh -c "cd ~/ds4; DS4_METAL_PREFILL_CHUNK=2048 nohup ./ds4 -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 4096 --role worker --layers 22:output --coordinator 10.77.0.1 1234 >/tmp/ds4-worker-4096.log 2>&1 < /dev/null &"' +ssh dgx-direct 'pkill -9 ds4 >/dev/null 2>&1 || true; sh -c "cd ~/ds4; DS4_METAL_PREFILL_CHUNK=2048 nohup ./ds4 -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --coordinator 10.77.0.1 1234 >/tmp/ds4-worker-16384.log 2>&1 < /dev/null &"' +``` + +The local-golden frontier requires worker `prefill_cap=4096`: + +```sh +ssh dgx-direct 'pkill -9 ds4 >/dev/null 2>&1 || true; sh -c "cd ~/ds4; DS4_METAL_PREFILL_CHUNK=4096 nohup ./ds4 -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 5000 --role worker --layers 22:output --coordinator 10.77.0.1 1234 >/tmp/ds4-worker-5000.log 2>&1 < /dev/null &"' +``` + +### Phase 3 actual one-shot loops + +The authoritative worst@5 data used five one-shot coordinator runs with short pauses between runs. This avoided coordinator port reuse races on `10.77.0.1:1234`. + +Official `ctx=4096`: + +```sh +for i in 1 2 3 4 5; do + sleep 2 + DS4_METAL_DISABLE_METAL4=1 DS4_METAL_PREFILL_CHUNK=2048 \ + ./tests/issue304_phase3_vectors \ + --suite official \ + --repeat 1 \ + --ctx-filter 4096 \ + --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf \ + --listen-host 10.77.0.1 \ + --listen-port 1234 \ + --vector-file tests/test-vectors/official.vec \ + --prefill-chunk 256 \ + --activation-bits 32 \ + --coordinator-layers 0:21 \ + --worker-layers 22:output \ + 2>&1 | tee /tmp/issue304-phase3-official-4096-run${i}.log +done +``` + +Official `ctx=16384`: + +```sh +for i in 1 2 3 4 5; do + sleep 2 + DS4_METAL_DISABLE_METAL4=1 DS4_METAL_PREFILL_CHUNK=2048 \ + ./tests/issue304_phase3_vectors \ + --suite official \ + --repeat 1 \ + --ctx-filter 16384 \ + --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf \ + --listen-host 10.77.0.1 \ + --listen-port 1234 \ + --vector-file tests/test-vectors/official.vec \ + --prefill-chunk 256 \ + --activation-bits 32 \ + --coordinator-layers 0:21 \ + --worker-layers 22:output \ + 2>&1 | tee /tmp/issue304-phase3-official-16384-run${i}.log +done +``` + +Local golden `ctx=5000`: + +```sh +for i in 1 2 3 4 5; do + sleep 2 + DS4_METAL_DISABLE_METAL4=1 DS4_METAL_PREFILL_CHUNK=4096 \ + ./tests/issue304_phase3_vectors \ + --suite local-golden \ + --repeat 1 \ + --ctx-filter 5000 \ + --greedy-steps 8 \ + --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf \ + --listen-host 10.77.0.1 \ + --listen-port 1234 \ + --local-golden-file tests/test-vectors/local-golden.vec \ + --prefill-chunk 256 \ + --activation-bits 32 \ + --coordinator-layers 0:21 \ + --worker-layers 22:output \ + 2>&1 | tee /tmp/issue304-phase3-local-golden-5000-run${i}.log +done +``` + ## Runtime knobs used by `--local-payload-resume` - `DS4_METAL_PREFILL_CHUNK=4096` @@ -233,6 +359,62 @@ Acceptance: The Phase 1 probe creates a session with `ctx=16384` and saves a 1-token local checkpoint to inspect the durable `DSV4` layout. +## Phase 3.5 six-route matrix + +Build the Phase 3.5 tools locally: + +```sh +make tests/issue304_phase35_vectors +``` + +Sync the tree to the DGX host: + +```sh +rsync -az --delete \ + --exclude='.git/' \ + --exclude='gguf/' \ + --exclude='*.o' \ + --exclude='ds4' \ + --exclude='ds4_test' \ + ./ dgx-direct:~/ds4/ +``` + +Build remotely: + +```sh +ssh dgx-direct 'cd ~/ds4 && make tests/issue304_phase35_vectors ds4' +``` + +Run the full matrix with the stable remote host form and DGX power limit: + +```sh +python3 tests/issue304_phase35_matrix.py \ + --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf \ + --remote-host ilo037@10.77.0.2 \ + --remote-root ~/ds4 \ + --repeat 5 \ + --power 50 +``` + +Targeted reruns are case-filterable: + +```sh +python3 tests/issue304_phase35_matrix.py \ + --model ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf \ + --remote-host ilo037@10.77.0.2 \ + --remote-root ~/ds4 \ + --suite official \ + --case short_code_completion \ + --repeat 5 \ + --power 50 +``` + +Observed operating notes: + +- `ssh dgx-direct` aliasing was less reliable through the driver subprocess path than the explicit `ilo037@10.77.0.2` form. +- Route `6` needs worker shutdown before opening the remote CUDA payload-resume engine. +- Raw outputs were written under `artifacts/issue-304/phase35/raw/`. + - `ctx_size=16384` - `prefill_cap=4096` - `raw_cap=4352` diff --git a/artifacts/issue-304/shard-metadata.md b/artifacts/issue-304/shard-metadata.md index 0c9875958..f116b4fb7 100644 --- a/artifacts/issue-304/shard-metadata.md +++ b/artifacts/issue-304/shard-metadata.md @@ -137,3 +137,81 @@ Current status: | `vocab` | 129,280 | | `raw_live` | 128 | | note | `token_count` and `token_hash` were captured after the 16-token distributed reference continuation; the serialized payload itself still reflects the immediate post-prefill checkpoint with `saved_tokens=14,318`. | + +## Phase 3 authoritative route/layout rows + +Phase 3 added one more hard layout constraint beyond matching `ctx`: merged `DSV4` staging also requires worker/coordinator `prefill_cap` equality. + +### Official vectors at `ctx=4096` + +| Field | Value | +| --- | --- | +| route summary | `local 0:21 -> 10.77.0.2:38705 Q2 22:output` | +| route hops | 1 | +| output owner | worker | +| worker `ctx` | 4,096 | +| coordinator `ctx` | 4,096 | +| worker `prefill_cap` | 2,048 | +| coordinator `prefill_cap` | 2,048 | +| payload bytes, `short_code_completion` | 15,423,992 | +| payload bytes, `short_reasoning_plain` | 14,523,860 | +| note | The first attempted Phase 3 official run failed until worker `DS4_METAL_PREFILL_CHUNK` was aligned to `2048` with the strict local vector environment. | + +### Official vectors at `ctx=16384` + +| Field | Value | +| --- | --- | +| route summary | `local 0:21 -> 10.77.0.2:32907 Q2 22:output` | +| route hops | 1 | +| output owner | worker | +| worker `ctx` | 16,384 | +| coordinator `ctx` | 16,384 | +| worker `prefill_cap` | 2,048 | +| coordinator `prefill_cap` | 2,048 | +| payload bytes, `short_italian_fact` | 14,841,824 | +| payload bytes, `long_code_audit` | 76,903,324 | +| note | The official-vector environment still pinned `DS4_METAL_PREFILL_CHUNK=2048` even at `ctx=16384`, so the worker had to match that lower `prefill_cap` for merged staging to succeed. | + +### Local-golden frontier at `ctx=5000` + +| Field | Value | +| --- | --- | +| route summary | `local 0:21 -> 10.77.0.2:36505 Q2 22:output` | +| route hops | 1 | +| output owner | worker | +| worker `ctx` | 5,000 | +| coordinator `ctx` | 5,000 | +| worker `prefill_cap` | 4,096 | +| coordinator `prefill_cap` | 4,096 | +| payload bytes, `long_story_4096` | 80,373,132 | +| note | The local-golden environment reused `DS4_METAL_PREFILL_CHUNK=4096`, so this group needed a different worker launch from the official-vector groups. | + +## Phase 3.5 route matrix metadata + +Phase 3.5 reused the same model and layer split, but broadened the execution topology to six routes and ran the DGX worker and DGX-side helper at `--power 50`. + +### Route mapping + +| Route | Meaning | Payload bytes | +| --- | --- | ---: | +| `1` | pure local CUDA prefill+generation | `0` | +| `2` | pure local Metal prefill+generation | `0` | +| `3` | distributed generation `CUDA -> Metal` | `0` | +| `4` | distributed generation `Metal -> CUDA` | `0` | +| `5` | distributed prefill `CUDA -> Metal`, then resumed pure Metal generation | case-dependent merged `DSV4` | +| `6` | distributed prefill `Metal -> CUDA`, then resumed pure CUDA generation | case-dependent merged `DSV4` | + +### Phase 3.5 payload rows + +| Case | Payload bytes | +| --- | ---: | +| `short_code_completion` | 15,423,992 | +| `short_reasoning_plain` | 14,523,860 | +| `short_italian_fact` | 14,841,824 | +| `long_code_audit` | 76,903,324 | +| `long_story_4096` | 80,373,132 | + +Notes: + +- Routes `5` and `6` share payload byte counts per case because each pair resumes the same staged `DSV4` checkpoint on opposite hosts. +- Phase 3.5 did not expose new shard-layout incompatibilities beyond the already-known `ctx` and `prefill_cap` alignment constraints. diff --git a/tests/issue304_phase35_matrix.py b/tests/issue304_phase35_matrix.py new file mode 100644 index 000000000..98c0df837 --- /dev/null +++ b/tests/issue304_phase35_matrix.py @@ -0,0 +1,535 @@ +#!/usr/bin/env python3 + +import argparse +import json +import os +import pathlib +import shlex +import subprocess +import sys +import tempfile +import time + + +ROOT = pathlib.Path(__file__).resolve().parents[1] +DEFAULT_MODEL = "./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf" +DEFAULT_REMOTE_MODEL = "/home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf" +RAW_DIR = ROOT / "artifacts" / "issue-304" / "phase35" / "raw" + + +def run(cmd, *, cwd=None, env=None, check=True): + proc = subprocess.run( + cmd, + cwd=cwd, + env=env, + text=True, + capture_output=True, + ) + if check and proc.returncode != 0: + raise RuntimeError(f"command failed ({proc.returncode}): {' '.join(cmd)}\n{proc.stderr}") + return proc + + +def ssh(host, command, *, check=True): + quoted = f"ssh {shlex.quote(host)} {shlex.quote(command)}" + proc = subprocess.run( + quoted, + cwd=ROOT, + text=True, + capture_output=True, + shell=True, + executable="/bin/bash", + ) + if check and proc.returncode != 0: + raise RuntimeError(f"command failed ({proc.returncode}): {quoted}\n{proc.stderr}") + return proc + + +def scp(src, dst, *, check=True): + quoted = f"scp {shlex.quote(src)} {shlex.quote(dst)}" + proc = subprocess.run( + quoted, + cwd=ROOT, + text=True, + capture_output=True, + shell=True, + executable="/bin/bash", + ) + if check and proc.returncode != 0: + raise RuntimeError(f"command failed ({proc.returncode}): {quoted}\n{proc.stderr}") + return proc + + +def shlex_join(parts): + return " ".join(shlex.quote(p) for p in parts) + + +def parse_official_cases(path): + cases = [] + with open(path, "r", encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#"): + continue + if line.startswith("case "): + _, case_id, ctx, _nsteps, _prompt = line.split(maxsplit=4) + if case_id == "long_memory_archive": + continue + cases.append({"id": case_id, "ctx": int(ctx), "suite": "official"}) + return cases + + +def parse_golden_cases(path): + cases = [] + with open(path, "r", encoding="utf-8") as fh: + for line in fh: + line = line.strip() + if not line or line.startswith("#"): + continue + if line.startswith("case "): + _, case_id, _mode, ctx, _frontier, _prompt, _ntop = line.split(maxsplit=6) + cases.append({"id": case_id, "ctx": int(ctx), "suite": "local-golden"}) + return cases + + +def model_hash_local(path): + out = run(["shasum", "-a", "256", path], cwd=ROOT).stdout.strip() + return out.split()[0] + + +def model_hash_remote(host, path): + cmd = ( + f"sh -lc 'if command -v sha256sum >/dev/null 2>&1; then " + f"sha256sum {shlex.quote(path)}; else shasum -a 256 {shlex.quote(path)}; fi'" + ) + out = ssh(host, cmd).stdout.strip() + return out.split()[0] + + +def remote_ipv4(host): + cmd = "python3 -c \"import socket; name=socket.gethostname(); " \ + "ips=[info[4][0] for info in socket.getaddrinfo(name, None, socket.AF_INET, socket.SOCK_STREAM) " \ + "if not info[4][0].startswith('127.')]; print(ips[0] if ips else '')\"" + out = ssh(host, cmd).stdout.strip() + if not out: + raise RuntimeError("failed to determine remote IPv4") + return out.splitlines()[-1].strip() + + +def local_prefill_cap(suite, ctx): + if suite == "local-golden" and ctx == 5000: + return 4096 + return 2048 + + +def local_env(prefill_cap): + env = os.environ.copy() + env["DS4_METAL_PREFILL_CHUNK"] = str(prefill_cap) + return env + + +def build_local(): + run(["make", "tests/issue304_phase35_vectors", "ds4"], cwd=ROOT) + + +def sync_and_build_remote(host): + rsync_cmd = [ + "rsync", "-az", "--delete", + "--exclude=.git/", + "--exclude=gguf/", + "--exclude=*.o", + "--exclude=ds4", + "--exclude=ds4-*", + "--exclude=ds4_test", + "--exclude=tests/issue304_phase2_handoff", + "--exclude=tests/issue304_phase3_vectors", + "--exclude=tests/issue304_phase35_vectors", + "./", f"{host}:~/ds4/", + ] + run(rsync_cmd, cwd=ROOT) + ssh(host, "cd ~/ds4 && make tests/issue304_phase35_vectors ds4") + + +def start_local_worker(model_path, ctx, coordinator_ip, port, prefill_cap, log_path): + env = local_env(prefill_cap) + env["DS4_LOCK_FILE"] = "/tmp/ds4-phase35-worker.lock" + logf = open(log_path, "w", encoding="utf-8") + proc = subprocess.Popen( + [ + "./ds4", + "-m", model_path, + "--ctx", str(ctx), + "--role", "worker", + "--layers", "22:output", + "--coordinator", coordinator_ip, str(port), + ], + cwd=ROOT, + env=env, + stdout=logf, + stderr=subprocess.STDOUT, + text=True, + ) + return proc, logf + + +def stop_local_worker(proc, logf): + if proc and proc.poll() is None: + proc.terminate() + try: + proc.wait(timeout=5) + except subprocess.TimeoutExpired: + proc.kill() + proc.wait(timeout=5) + if logf: + logf.close() + + +def start_remote_worker(host, model_path, ctx, coordinator_ip, port, prefill_cap, log_path): + cmd = ( + "pkill -9 ds4 >/dev/null 2>&1 || true; " + f"sh -lc 'cd ~/ds4 && export DS4_METAL_PREFILL_CHUNK={prefill_cap}; export DS4_LOCK_FILE=/tmp/ds4-phase35-worker.lock; " + f"nohup ./ds4 -m {shlex.quote(model_path)} --power 50 --ctx {ctx} --role worker --layers 22:output " + f"--coordinator {shlex.quote(coordinator_ip)} {port} >{shlex.quote(log_path)} 2>&1 < /dev/null &'" + ) + ssh(host, cmd) + + +def stop_remote_worker(host): + ssh(host, "pkill -9 ds4 >/dev/null 2>&1 || true", check=False) + + +def base_helper_args(case, repeat): + return [ + "--suite", case["suite"], + "--case-filter", case["id"], + "--ctx-filter", str(case["ctx"]), + "--repeat", str(repeat), + ] + + +def run_local_helper(case, repeat, model_path): + cap = local_prefill_cap(case["suite"], case["ctx"]) + env = local_env(cap) + cmd = [ + "./tests/issue304_phase35_vectors", + "--mode", "local", + "--model", model_path, + *base_helper_args(case, repeat), + ] + return run(cmd, cwd=ROOT, env=env, check=False) + + +def run_remote_local_helper(host, case, repeat, model_path): + cap = local_prefill_cap(case["suite"], case["ctx"]) + cmd = ( + f"cd ~/ds4 && DS4_METAL_PREFILL_CHUNK={cap} " + f"./tests/issue304_phase35_vectors --mode local --power 50 --model {shlex.quote(model_path)} " + f"{shlex_join(base_helper_args(case, repeat))}" + ) + return ssh(host, cmd, check=False) + + +def run_distributed_helper_local(case, repeat, model_path, listen_host, port, payload_out=None): + cap = local_prefill_cap(case["suite"], case["ctx"]) + env = local_env(cap) + cmd = [ + "./tests/issue304_phase35_vectors", + "--mode", "distributed", + "--model", model_path, + "--listen-host", listen_host, + "--listen-port", str(port), + "--coordinator-layers", "0:21", + "--worker-layers", "22:output", + *base_helper_args(case, repeat), + ] + if payload_out: + cmd += ["--payload-out", payload_out] + return run(cmd, cwd=ROOT, env=env, check=False) + + +def run_distributed_helper_remote(host, case, repeat, model_path, listen_host, port, payload_out=None): + cap = local_prefill_cap(case["suite"], case["ctx"]) + cmd = ( + f"cd ~/ds4 && DS4_METAL_PREFILL_CHUNK={cap} " + f"./tests/issue304_phase35_vectors --mode distributed --power 50 --model {shlex.quote(model_path)} " + f"--listen-host {shlex.quote(listen_host)} --listen-port {port} " + f"--coordinator-layers 0:21 --worker-layers 22:output " + f"{shlex_join(base_helper_args(case, repeat))}" + ) + if payload_out: + cmd += f" --payload-out {shlex.quote(payload_out)}" + return ssh(host, cmd, check=False) + + +def run_payload_helper_local(case, repeat, model_path, payload_file): + cap = local_prefill_cap(case["suite"], case["ctx"]) + env = local_env(cap) + cmd = [ + "./tests/issue304_phase35_vectors", + "--mode", "payload", + "--model", model_path, + "--payload-file", payload_file, + *base_helper_args(case, repeat), + ] + return run(cmd, cwd=ROOT, env=env, check=False) + + +def run_payload_helper_remote(host, case, repeat, model_path, payload_file): + cap = local_prefill_cap(case["suite"], case["ctx"]) + cmd = ( + f"cd ~/ds4 && DS4_METAL_PREFILL_CHUNK={cap} " + f"./tests/issue304_phase35_vectors --mode payload --power 50 --model {shlex.quote(model_path)} " + f"--payload-file {shlex.quote(payload_file)} " + f"{shlex_join(base_helper_args(case, repeat))}" + ) + return ssh(host, cmd, check=False) + + +def parse_summary(stdout): + rows = [json.loads(line) for line in stdout.splitlines() if line.strip().startswith("{")] + if not rows: + raise RuntimeError("no JSON output produced") + for row in reversed(rows): + for key in row.keys(): + if key.startswith("worst_at_"): + return row + return rows[-1] + + +def aggregate(route_name, summaries): + first = summaries[0] + worst_key = next(k for k in first.keys() if k.startswith("worst_at_")) + out = { + "route": route_name, + "mode": first["mode"], + "suite": first["suite"], + "case": first["case"], + "ctx": first["ctx"], + "worst_at_5": { + "passes": 0, + "route_summary": first[worst_key]["route_summary"], + "payload_bytes_max": 0, + "prefill_sec_max": 0.0, + "stage_sec_max": 0.0, + "load_sec_max": 0.0, + "parity": dict(first[worst_key]["parity"]), + "official": dict(first[worst_key]["official"]), + "golden": dict(first[worst_key]["golden"]), + }, + } + p = out["worst_at_5"]["parity"] + p["top5_overlap"] = 999 + p["top20_overlap"] = 999 + p["top64_overlap"] = 999 + p["nonfinite"] = 0 + p["rms"] = 0.0 + p["max_abs"] = 0.0 + p["top20_max_abs"] = 0.0 + p["first_top1_mismatch_step"] = -1 + official = out["worst_at_5"]["official"] + official["pass"] = True + official["selected_mismatch_step"] = -1 + official["missing_top_count"] = 0 + official["max_logprob_delta"] = 0.0 + golden = out["worst_at_5"]["golden"] + golden["pass"] = True + golden["top5_overlap"] = 999 + golden["top20_overlap"] = 999 + golden["top64_overlap"] = 999 + golden["top20_max_abs"] = 0.0 + + for summary in summaries: + w = summary[worst_key] + out["worst_at_5"]["passes"] += w["passes"] + out["worst_at_5"]["payload_bytes_max"] = max(out["worst_at_5"]["payload_bytes_max"], w["payload_bytes_max"]) + out["worst_at_5"]["prefill_sec_max"] = max(out["worst_at_5"]["prefill_sec_max"], w["prefill_sec_max"]) + out["worst_at_5"]["stage_sec_max"] = max(out["worst_at_5"]["stage_sec_max"], w["stage_sec_max"]) + out["worst_at_5"]["load_sec_max"] = max(out["worst_at_5"]["load_sec_max"], w["load_sec_max"]) + wp = w["parity"] + p["top5_overlap"] = min(p["top5_overlap"], wp["top5_overlap"]) + p["top20_overlap"] = min(p["top20_overlap"], wp["top20_overlap"]) + p["top64_overlap"] = min(p["top64_overlap"], wp["top64_overlap"]) + p["nonfinite"] = max(p["nonfinite"], wp["nonfinite"]) + p["rms"] = max(p["rms"], wp["rms"]) + p["max_abs"] = max(p["max_abs"], wp["max_abs"]) + p["top20_max_abs"] = max(p["top20_max_abs"], wp["top20_max_abs"]) + if p["first_top1_mismatch_step"] < 0 and wp["first_top1_mismatch_step"] >= 0: + p["first_top1_mismatch_step"] = wp["first_top1_mismatch_step"] + p["top1_ref"] = wp["top1_ref"] + p["top1_cand"] = wp["top1_cand"] + official["pass"] = official["pass"] and w["official"]["pass"] + if official["selected_mismatch_step"] < 0 and w["official"]["selected_mismatch_step"] >= 0: + official["selected_mismatch_step"] = w["official"]["selected_mismatch_step"] + official["missing_top_count"] += w["official"]["missing_top_count"] + official["max_logprob_delta"] = max(official["max_logprob_delta"], w["official"]["max_logprob_delta"]) + golden["pass"] = golden["pass"] and w["golden"]["pass"] + golden["top1"] = w["golden"]["top1"] + golden["top5_overlap"] = min(golden["top5_overlap"], w["golden"]["top5_overlap"]) + golden["top20_overlap"] = min(golden["top20_overlap"], w["golden"]["top20_overlap"]) + golden["top64_overlap"] = min(golden["top64_overlap"], w["golden"]["top64_overlap"]) + golden["top20_max_abs"] = max(golden["top20_max_abs"], w["golden"]["top20_max_abs"]) + return out + + +def write_raw(path, proc): + path.parent.mkdir(parents=True, exist_ok=True) + with open(path, "w", encoding="utf-8") as fh: + fh.write(proc.stdout) + if proc.stderr: + fh.write("\n# STDERR\n") + fh.write(proc.stderr) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--local-model", default=DEFAULT_MODEL) + ap.add_argument("--remote-model", default=DEFAULT_REMOTE_MODEL) + ap.add_argument("--remote-host", default="dgx-direct") + ap.add_argument("--local-ip", default="10.77.0.1") + ap.add_argument("--port", type=int, default=1234) + ap.add_argument("--repeats", type=int, default=5) + ap.add_argument("--routes", default="1,2,3,4,5,6") + ap.add_argument("--suites", default="official,local-golden") + ap.add_argument("--case-filter", default="") + ap.add_argument("--skip-hash-check", action="store_true") + ap.add_argument("--skip-build", action="store_true") + args = ap.parse_args() + + official_cases = parse_official_cases(ROOT / "tests" / "test-vectors" / "official.vec") + golden_cases = parse_golden_cases(ROOT / "tests" / "test-vectors" / "local-golden.vec") + cases = [] + suites = set(x.strip() for x in args.suites.split(",") if x.strip()) + if "official" in suites: + cases.extend(official_cases) + if "local-golden" in suites: + cases.extend(golden_cases) + if args.case_filter: + cases = [case for case in cases if args.case_filter in case["id"]] + + routes = [int(x) for x in args.routes.split(",") if x.strip()] + RAW_DIR.mkdir(parents=True, exist_ok=True) + requires_remote = any(route in {1, 3, 4, 5, 6} for route in routes) + remote_ip = None + if requires_remote: + remote_ip = remote_ipv4(args.remote_host) + if not args.skip_hash_check: + local_hash = model_hash_local(args.local_model) + remote_hash = model_hash_remote(args.remote_host, args.remote_model) + if local_hash != remote_hash: + raise RuntimeError(f"model hash mismatch: local={local_hash} remote={remote_hash}") + + if not args.skip_build: + build_local() + if requires_remote: + sync_and_build_remote(args.remote_host) + + summaries = [] + + for case in cases: + for route in routes: + per_repeat = [] + for repeat_idx in range(1, args.repeats + 1): + stamp = f"{case['suite']}-{case['id']}-r{route}-rep{repeat_idx}" + raw_path = RAW_DIR / f"{stamp}.ndjson" + if route in {1, 3, 4, 5, 6}: + stop_remote_worker(args.remote_host) + if route == 1: + proc = run_remote_local_helper(args.remote_host, case, 1, args.remote_model) + elif route == 2: + proc = run_local_helper(case, 1, args.local_model) + elif route == 3: + proc_worker, logf = start_local_worker( + args.local_model, + case["ctx"], + remote_ip, + args.port, + local_prefill_cap(case["suite"], case["ctx"]), + str(RAW_DIR / f"{stamp}.worker.log"), + ) + time.sleep(2) + try: + proc = run_distributed_helper_remote( + args.remote_host, case, 1, args.remote_model, remote_ip, args.port + ) + finally: + stop_local_worker(proc_worker, logf) + elif route == 4: + start_remote_worker( + args.remote_host, + args.remote_model, + case["ctx"], + args.local_ip, + args.port, + local_prefill_cap(case["suite"], case["ctx"]), + f"/tmp/{stamp}.worker.log", + ) + time.sleep(2) + try: + proc = run_distributed_helper_local( + case, 1, args.local_model, args.local_ip, args.port + ) + finally: + stop_remote_worker(args.remote_host) + elif route == 5: + remote_payload = f"/tmp/{stamp}.dsv4" + local_payload = str(RAW_DIR / f"{stamp}.dsv4") + proc_worker, logf = start_local_worker( + args.local_model, + case["ctx"], + remote_ip, + args.port, + local_prefill_cap(case["suite"], case["ctx"]), + str(RAW_DIR / f"{stamp}.worker.log"), + ) + time.sleep(2) + try: + stage_proc = run_distributed_helper_remote( + args.remote_host, case, 1, args.remote_model, remote_ip, args.port, remote_payload + ) + write_raw(raw_path.with_suffix(".stage.ndjson"), stage_proc) + scp(f"{args.remote_host}:{remote_payload}", local_payload) + proc = run_payload_helper_local(case, 1, args.local_model, local_payload) + finally: + stop_local_worker(proc_worker, logf) + elif route == 6: + local_payload = str(RAW_DIR / f"{stamp}.dsv4") + remote_payload = f"/tmp/{stamp}.dsv4" + start_remote_worker( + args.remote_host, + args.remote_model, + case["ctx"], + args.local_ip, + args.port, + local_prefill_cap(case["suite"], case["ctx"]), + f"/tmp/{stamp}.worker.log", + ) + time.sleep(2) + try: + stage_proc = run_distributed_helper_local( + case, 1, args.local_model, args.local_ip, args.port, local_payload + ) + write_raw(raw_path.with_suffix(".stage.ndjson"), stage_proc) + scp(local_payload, f"{args.remote_host}:{remote_payload}") + stop_remote_worker(args.remote_host) + proc = run_payload_helper_remote(args.remote_host, case, 1, args.remote_model, remote_payload) + finally: + stop_remote_worker(args.remote_host) + else: + raise RuntimeError(f"unknown route {route}") + + write_raw(raw_path, proc) + per_repeat.append(parse_summary(proc.stdout)) + time.sleep(2) + + summary = aggregate(f"route{route}", per_repeat) + summaries.append(summary) + print(json.dumps(summary)) + + out_path = RAW_DIR / "phase35-summary.ndjson" + with open(out_path, "w", encoding="utf-8") as fh: + for row in summaries: + fh.write(json.dumps(row) + "\n") + + +if __name__ == "__main__": + main() diff --git a/tests/issue304_phase35_vectors.c b/tests/issue304_phase35_vectors.c new file mode 100644 index 000000000..ba9c59016 --- /dev/null +++ b/tests/issue304_phase35_vectors.c @@ -0,0 +1,1742 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHASE35_MAX_TOP 128 +#define PHASE35_MAX_STEPS 16 +#define PHASE35_MAX_TOKEN_BYTES 128 + +typedef enum { + PHASE35_SUITE_OFFICIAL, + PHASE35_SUITE_LOCAL_GOLDEN, +} phase35_suite; + +typedef enum { + PHASE35_MODE_LOCAL, + PHASE35_MODE_DISTRIBUTED, + PHASE35_MODE_PAYLOAD, +} phase35_mode; + +typedef struct { + const char *model_path; + const char *mode_name; + const char *listen_host; + const char *vector_file; + const char *local_golden_file; + const char *case_filter; + const char *coordinator_layers; + const char *worker_layers; + const char *payload_file; + const char *payload_out; + int listen_port; + int repeat; + int ctx_filter; + int greedy_steps; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + int power_percent; + bool debug; + phase35_suite suite; + phase35_mode mode; +} phase35_cfg; + +typedef struct { + unsigned char bytes[PHASE35_MAX_TOKEN_BYTES]; + int len; + float logprob; +} official_top; + +typedef struct { + unsigned char selected[PHASE35_MAX_TOKEN_BYTES]; + int selected_len; + int ntop; + official_top top[32]; +} official_step; + +typedef struct { + char id[96]; + char prompt_path[512]; + int ctx; + int nsteps; + official_step steps[PHASE35_MAX_STEPS]; +} official_case; + +typedef struct { + int id; + float logit; +} golden_top; + +typedef struct { + char id[96]; + char mode[16]; + char prompt_path[512]; + int ctx; + int frontier; + int ntop; + golden_top top[PHASE35_MAX_TOP]; +} golden_case; + +typedef struct { + int top1_ref; + int top1_cand; + int top5_overlap; + int top20_overlap; + int top64_overlap; + int nonfinite; + float rms; + float max_abs; + float top20_max_abs; +} parity_metrics; + +typedef struct { + bool initialized; + int top1_ref; + int top1_cand; + int top5_overlap; + int top20_overlap; + int top64_overlap; + int nonfinite; + float rms; + float max_abs; + float top20_max_abs; + int first_top1_mismatch_step; + int first_ref_token; + int first_cand_token; +} parity_summary; + +typedef struct { + bool ok; + char error[256]; + char route_summary[1024]; + uint32_t route_hops; + bool output_on_coordinator; + uint64_t payload_bytes; + double prefill_sec; + double stage_sec; + double load_sec; + parity_summary parity; + int steps_checked; + bool official_pass; + int official_selected_mismatch_step; + int official_missing_top_count; + float official_max_logprob_delta; + bool golden_pass; + int golden_top1; + int golden_top5_overlap; + int golden_top20_overlap; + int golden_top64_overlap; + float golden_top20_max_abs; +} repeat_result; + +typedef struct { + int repeats; + int passes; + parity_summary worst_parity; + bool official_pass; + int official_selected_mismatch_step; + int official_missing_top_count; + float official_max_logprob_delta; + bool golden_pass; + int golden_top1; + int golden_top5_overlap; + int golden_top20_overlap; + int golden_top64_overlap; + float golden_top20_max_abs; + uint64_t payload_bytes_max; + double prefill_sec_max; + double stage_sec_max; + double load_sec_max; + char route_summary[1024]; + uint32_t route_hops; + bool output_on_coordinator; +} case_summary; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase35-vectors: %s\n", msg); + exit(1); +} + +static void die_errno(const char *msg) { + fprintf(stderr, "issue304-phase35-vectors: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static void usage(const char *argv0) { + fprintf(stderr, + "usage: %s --mode local|distributed|payload --suite official|local-golden --model FILE " + "[--listen-host IPV4 --listen-port N --coordinator-layers A:B|A:output --worker-layers A:B|A:output] " + "[--payload-file FILE] [--payload-out FILE] " + "[--vector-file FILE] [--local-golden-file FILE] [--repeat N] [--ctx-filter N] " + "[--greedy-steps N] [--prefill-chunk N] [--prefill-window N] [--activation-bits N] [--power N] [--no-debug]\n", + argv0); + exit(2); +} + +static const char *suite_name(phase35_suite suite) { + return suite == PHASE35_SUITE_OFFICIAL ? "official" : "local-golden"; +} + +static const char *mode_name(phase35_mode mode) { + switch (mode) { + case PHASE35_MODE_LOCAL: return "local"; + case PHASE35_MODE_DISTRIBUTED: return "distributed"; + case PHASE35_MODE_PAYLOAD: return "payload"; + } + return "unknown"; +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (len != 0 && fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static char *trim_line(char *line) { + while (*line && isspace((unsigned char)*line)) line++; + size_t n = strlen(line); + while (n && isspace((unsigned char)line[n - 1])) line[--n] = '\0'; + return line; +} + +static int hex_digit(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + return -1; +} + +static bool hex_to_bytes(const char *hex, unsigned char *out, int cap, int *len) { + int n = 0; + while (*hex && !isspace((unsigned char)*hex)) { + int hi = hex_digit(hex[0]); + int lo = hex_digit(hex[1]); + if (hi < 0 || lo < 0 || n >= cap) return false; + out[n++] = (unsigned char)((hi << 4) | lo); + hex += 2; + } + *len = n; + return true; +} + +static bool token_bytes_equal(ds4_engine *engine, int token, + const unsigned char *want, int want_len) { + size_t got_len = 0; + char *got = ds4_token_text(engine, token, &got_len); + bool eq = got && got_len == (size_t)want_len && + memcmp(got, want, (size_t)want_len) == 0; + free(got); + return eq; +} + +static void logits_topk(const float *logits, int n, int *out, int k) { + for (int i = 0; i < k; i++) out[i] = -1; + for (int i = 0; i < n; i++) { + const float v = logits[i]; + for (int j = 0; j < k; j++) { + if (out[j] < 0 || v > logits[out[j]]) { + for (int t = k - 1; t > j; t--) out[t] = out[t - 1]; + out[j] = i; + break; + } + } + } +} + +static bool topk_contains(const int *top, int k, int id) { + for (int i = 0; i < k; i++) { + if (top[i] == id) return true; + } + return false; +} + +static parity_metrics compare_logits(const float *ref, const float *cand, int vocab) { + int ref_top[64]; + int cand_top[64]; + logits_topk(ref, vocab, ref_top, 64); + logits_topk(cand, vocab, cand_top, 64); + + int top5_overlap = 0; + int top20_overlap = 0; + int top64_overlap = 0; + for (int i = 0; i < 64; i++) { + if (ref_top[i] >= 0 && topk_contains(cand_top, 64, ref_top[i])) top64_overlap++; + if (i < 20 && ref_top[i] >= 0 && topk_contains(cand_top, 20, ref_top[i])) top20_overlap++; + if (i < 5 && ref_top[i] >= 0 && topk_contains(cand_top, 5, ref_top[i])) top5_overlap++; + } + + int nonfinite = 0; + double sumsq = 0.0; + float max_abs = 0.0f; + float top20_max_abs = 0.0f; + for (int i = 0; i < vocab; i++) { + if (!isfinite(ref[i]) || !isfinite(cand[i])) { + nonfinite++; + continue; + } + float delta = cand[i] - ref[i]; + float abs_delta = fabsf(delta); + if (abs_delta > max_abs) max_abs = abs_delta; + sumsq += (double)delta * (double)delta; + } + for (int i = 0; i < 20; i++) { + const int id = ref_top[i]; + if (id < 0) continue; + const float abs_delta = fabsf(cand[id] - ref[id]); + if (abs_delta > top20_max_abs) top20_max_abs = abs_delta; + } + + parity_metrics out = { + .top1_ref = ref_top[0], + .top1_cand = cand_top[0], + .top5_overlap = top5_overlap, + .top20_overlap = top20_overlap, + .top64_overlap = top64_overlap, + .nonfinite = nonfinite, + .rms = (float)sqrt(sumsq / (double)vocab), + .max_abs = max_abs, + .top20_max_abs = top20_max_abs, + }; + return out; +} + +static void parity_summary_observe(parity_summary *out, + const parity_metrics *m, + int step) { + if (!out->initialized) { + out->initialized = true; + out->top1_ref = m->top1_ref; + out->top1_cand = m->top1_cand; + out->top5_overlap = m->top5_overlap; + out->top20_overlap = m->top20_overlap; + out->top64_overlap = m->top64_overlap; + out->nonfinite = m->nonfinite; + out->rms = m->rms; + out->max_abs = m->max_abs; + out->top20_max_abs = m->top20_max_abs; + out->first_top1_mismatch_step = (m->top1_ref == m->top1_cand) ? -1 : step; + out->first_ref_token = m->top1_ref; + out->first_cand_token = m->top1_cand; + return; + } + + if (m->top5_overlap < out->top5_overlap) out->top5_overlap = m->top5_overlap; + if (m->top20_overlap < out->top20_overlap) out->top20_overlap = m->top20_overlap; + if (m->top64_overlap < out->top64_overlap) out->top64_overlap = m->top64_overlap; + if (m->nonfinite > out->nonfinite) out->nonfinite = m->nonfinite; + if (m->rms > out->rms) out->rms = m->rms; + if (m->max_abs > out->max_abs) out->max_abs = m->max_abs; + if (m->top20_max_abs > out->top20_max_abs) out->top20_max_abs = m->top20_max_abs; + if (out->first_top1_mismatch_step < 0 && m->top1_ref != m->top1_cand) { + out->first_top1_mismatch_step = step; + out->top1_ref = m->top1_ref; + out->top1_cand = m->top1_cand; + out->first_ref_token = m->top1_ref; + out->first_cand_token = m->top1_cand; + } +} + +static bool parity_pass_strict(const parity_summary *p) { + return p->initialized && + p->first_top1_mismatch_step < 0 && + p->top5_overlap == 5 && + p->top20_overlap == 20 && + p->top64_overlap >= 60 && + p->nonfinite == 0 && + p->top20_max_abs <= 2.0f && + p->rms <= 0.1f; +} + +static bool parity_pass_medium(const parity_summary *p) { + return p->initialized && + p->first_top1_mismatch_step < 0 && + p->top5_overlap == 5 && + p->top20_overlap == 20 && + p->top64_overlap >= 56 && + p->nonfinite == 0 && + p->top20_max_abs <= 4.0f && + p->rms <= 0.25f; +} + +static bool parity_pass_tolerant(const parity_summary *p) { + return p->initialized && + p->first_top1_mismatch_step < 0 && + p->top5_overlap >= 4 && + p->top20_overlap >= 15 && + p->top64_overlap >= 40 && + p->nonfinite == 0 && + p->top20_max_abs <= 8.0f; +} + +static const char *parity_envelope(const parity_summary *p) { + if (parity_pass_strict(p)) return "strict"; + if (parity_pass_medium(p)) return "medium"; + if (parity_pass_tolerant(p)) return "tolerant"; + return "fail"; +} + +static bool official_case_disabled(const official_case *vc) { + return !strcmp(vc->id, "long_memory_archive"); +} + +static bool case_selected(const char *id, const char *filter) { + if (!filter || !filter[0]) return true; + return strstr(id, filter) != NULL; +} + +static bool read_official_case(FILE *fp, official_case *vc) { + char line[2048]; + memset(vc, 0, sizeof(*vc)); + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (sscanf(p, "case %95s %d %d %511s", + vc->id, &vc->ctx, &vc->nsteps, vc->prompt_path) == 4) { + return vc->nsteps > 0 && vc->nsteps <= PHASE35_MAX_STEPS; + } + return false; + } + return false; +} + +static bool fill_official_case(FILE *fp, official_case *vc) { + char line[2048]; + int step_index = -1; + int top_index = 0; + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (!strcmp(p, "end")) return true; + if (!strncmp(p, "step ", 5)) { + char hex[PHASE35_MAX_TOKEN_BYTES * 2 + 2]; + int ntop = 0; + if (sscanf(p, "step %d %257s %d", &step_index, hex, &ntop) != 3) { + return false; + } + if (step_index < 0 || step_index >= vc->nsteps || ntop < 0 || ntop > 32) { + return false; + } + vc->steps[step_index].ntop = ntop; + if (!hex_to_bytes(hex, + vc->steps[step_index].selected, + PHASE35_MAX_TOKEN_BYTES, + &vc->steps[step_index].selected_len)) { + return false; + } + top_index = 0; + continue; + } + if (!strncmp(p, "top ", 4)) { + char hex[PHASE35_MAX_TOKEN_BYTES * 2 + 2]; + float lp = 0.0f; + if (step_index < 0 || step_index >= vc->nsteps || + top_index >= vc->steps[step_index].ntop) { + return false; + } + if (sscanf(p, "top %257s %f", hex, &lp) != 2) { + return false; + } + official_top *top = &vc->steps[step_index].top[top_index++]; + top->logprob = lp; + if (!hex_to_bytes(hex, top->bytes, PHASE35_MAX_TOKEN_BYTES, &top->len)) { + return false; + } + continue; + } + return false; + } + return false; +} + +static bool read_golden_case(FILE *fp, golden_case *tc) { + char line[2048]; + memset(tc, 0, sizeof(*tc)); + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (sscanf(p, "case %95s %15s %d %d %511s %d", + tc->id, tc->mode, &tc->ctx, &tc->frontier, + tc->prompt_path, &tc->ntop) == 6) { + return tc->ctx > tc->frontier && + tc->frontier > 0 && + tc->ntop > 0 && + tc->ntop <= PHASE35_MAX_TOP; + } + return false; + } + return false; +} + +static bool fill_golden_case(FILE *fp, golden_case *tc) { + char line[2048]; + int seen = 0; + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (!strcmp(p, "end")) return seen == tc->ntop; + int rank = -1; + int id = -1; + float logit = 0.0f; + if (sscanf(p, "top %d %d %f", &rank, &id, &logit) != 3) return false; + if (rank != seen || seen >= tc->ntop) return false; + tc->top[seen].id = id; + tc->top[seen].logit = logit; + seen++; + } + return false; +} + +static bool parse_layer_spec(const char *spec, ds4_distributed_layers *out) { + if (!spec || !out) return false; + const char *colon = strchr(spec, ':'); + if (!colon || colon == spec || colon[1] == '\0') return false; + + errno = 0; + char *end = NULL; + unsigned long start = strtoul(spec, &end, 10); + if (errno != 0 || end != colon || start > UINT32_MAX) return false; + + ds4_distributed_layers layers = {0}; + layers.start = (uint32_t)start; + layers.set = true; + if (!strcmp(colon + 1, "output")) { + layers.has_output = true; + layers.end = 0; + } else { + errno = 0; + unsigned long layer_end = strtoul(colon + 1, &end, 10); + if (errno != 0 || *end != '\0' || layer_end > UINT32_MAX) return false; + layers.end = (uint32_t)layer_end; + } + *out = layers; + return true; +} + +static int wait_route(ds4_session *session, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase35-vectors: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase35-vectors: timed out waiting for route\n"); + return 0; +} + +static bool set_process_lock_file(const char *path, char *err, size_t errlen) { + if (!path || !path[0]) { + snprintf(err, errlen, "invalid lock file path"); + return false; + } + if (setenv("DS4_LOCK_FILE", path, 1) != 0) { + snprintf(err, errlen, "failed to set DS4_LOCK_FILE: %s", strerror(errno)); + return false; + } + return true; +} + +static bool load_payload_into_session(ds4_session *session, + const ds4_session_payload_file *payload, + char *err, + size_t errlen) { + FILE *fp = fopen(payload->path, "rb"); + if (!fp) { + snprintf(err, errlen, "failed to open staged payload: %s", strerror(errno)); + return false; + } + const int rc = ds4_session_load_payload(session, fp, payload->bytes, err, errlen); + fclose(fp); + return rc == 0; +} + +static bool load_payload_path_into_session(ds4_session *session, + const char *payload_path, + uint64_t *payload_bytes_out, + char *err, + size_t errlen) { + FILE *fp = fopen(payload_path, "rb"); + if (!fp) { + snprintf(err, errlen, "failed to open payload file: %s", strerror(errno)); + return false; + } + if (fseek(fp, 0, SEEK_END) != 0) { + snprintf(err, errlen, "failed to seek payload file: %s", strerror(errno)); + fclose(fp); + return false; + } + long payload_bytes = ftell(fp); + if (payload_bytes < 0) { + snprintf(err, errlen, "failed to measure payload file: %s", strerror(errno)); + fclose(fp); + return false; + } + rewind(fp); + const int rc = ds4_session_load_payload(session, fp, (uint64_t)payload_bytes, err, errlen); + fclose(fp); + if (rc != 0) return false; + if (payload_bytes_out) *payload_bytes_out = (uint64_t)payload_bytes; + return true; +} + +static bool write_payload_copy(const ds4_session_payload_file *payload, + const char *dst_path, + char *err, + size_t errlen) { + FILE *fp = fopen(dst_path, "wb"); + if (!fp) { + snprintf(err, errlen, "failed to open payload output: %s", strerror(errno)); + return false; + } + const int rc = ds4_session_write_staged_payload(payload, fp, err, errlen); + if (fclose(fp) != 0 && rc == 0) { + snprintf(err, errlen, "failed to close payload output: %s", strerror(errno)); + return false; + } + return rc == 0; +} + +static bool tokenize_official_prompt(ds4_engine *engine, + const official_case *vc, + ds4_tokens *out) { + memset(out, 0, sizeof(*out)); + char *prompt_text = read_file(vc->prompt_path); + if (!prompt_text) return false; + ds4_encode_chat_prompt(engine, "", prompt_text, DS4_THINK_NONE, out); + free(prompt_text); + return out->len > 0; +} + +static bool tokenize_golden_prompt(ds4_engine *engine, + const golden_case *tc, + ds4_tokens *full_prompt, + ds4_tokens *prefix) { + memset(full_prompt, 0, sizeof(*full_prompt)); + memset(prefix, 0, sizeof(*prefix)); + char *prompt_text = read_file(tc->prompt_path); + if (!prompt_text) return false; + if (!strcmp(tc->mode, "text")) { + ds4_tokenize_text(engine, prompt_text, full_prompt); + } else if (!strcmp(tc->mode, "rendered")) { + ds4_tokenize_rendered_chat(engine, prompt_text, full_prompt); + } else if (!strcmp(tc->mode, "chat")) { + ds4_encode_chat_prompt(engine, "", prompt_text, DS4_THINK_NONE, full_prompt); + } else { + free(prompt_text); + return false; + } + free(prompt_text); + if (full_prompt->len < tc->frontier) return false; + prefix->v = full_prompt->v; + prefix->len = tc->frontier; + prefix->cap = tc->frontier; + return prefix->len > 0; +} + +static bool open_host_local_engine(const phase35_cfg *cfg, ds4_engine **engine_out) { + *engine_out = NULL; + ds4_engine_options local_opt = { + .model_path = cfg->model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .power_percent = cfg->power_percent, + .quality = false, + }; + return ds4_engine_open(engine_out, &local_opt) == 0 && *engine_out; +} + +static bool open_distributed_session(const phase35_cfg *cfg, + int ctx, + ds4_distributed_layers coordinator_layers, + ds4_engine **engine_out, + ds4_session **session_out, + char *route_summary, + size_t route_summary_len, + uint32_t *route_hops, + bool *output_on_coordinator) { + *engine_out = NULL; + *session_out = NULL; + char err[256] = {0}; + ds4_engine_options dist_opt = { + .model_path = cfg->model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .power_percent = cfg->power_percent, + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = coordinator_layers, + .listen_host = cfg->listen_host, + .listen_port = cfg->listen_port, + .prefill_chunk = cfg->prefill_chunk, + .prefill_window = cfg->prefill_window, + .activation_bits = cfg->activation_bits, + .debug = cfg->debug, + }, + }; + if (ds4_dist_prepare_engine_options(&dist_opt.distributed, &dist_opt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase35-vectors: distributed options failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + if (ds4_engine_open(engine_out, &dist_opt) != 0 || !*engine_out) return false; + if (ds4_session_create(session_out, *engine_out, ctx) != 0 || !*session_out) return false; + if (wait_route(*session_out, 60.0) != 1) return false; + if (ds4_session_distributed_route_summary(*session_out, + route_summary, + route_summary_len, + route_hops, + output_on_coordinator, + err, + sizeof(err)) != 1) { + fprintf(stderr, "issue304-phase35-vectors: route summary failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + return true; +} + +static bool stage_distributed_payload(ds4_session *dist_session, + const ds4_tokens *prompt, + repeat_result *res, + ds4_session_payload_file *payload) { + char err[256] = {0}; + double t0 = now_sec(); + if (ds4_session_sync(dist_session, prompt, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed prefill failed: %s", + err[0] ? err : "unknown error"); + return false; + } + res->prefill_sec = now_sec() - t0; + + t0 = now_sec(); + if (ds4_session_stage_payload(dist_session, payload, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed payload stage failed: %s", + err[0] ? err : "unknown error"); + return false; + } + res->stage_sec = now_sec() - t0; + res->payload_bytes = payload->bytes; + return true; +} + +static bool run_official_repeat(const phase35_cfg *cfg, + ds4_distributed_layers coordinator_layers, + const official_case *vc, + repeat_result *res) { + memset(res, 0, sizeof(*res)); + res->official_pass = true; + res->official_selected_mismatch_step = -1; + + if (cfg->mode == PHASE35_MODE_DISTRIBUTED) { + ds4_engine *dist_engine = NULL; + ds4_session *cand_session = NULL; + ds4_session_payload_file payload = {0}; + ds4_tokens prompt = {0}; + float *cand_logits = NULL; + ds4_token_score scores[20]; + char err[256] = {0}; + bool ok = false; + + if (!set_process_lock_file("/tmp/ds4-phase35-dist.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto dist_cleanup; + } + if (!open_distributed_session(cfg, vc->ctx, coordinator_layers, + &dist_engine, &cand_session, + res->route_summary, sizeof(res->route_summary), + &res->route_hops, &res->output_on_coordinator)) { + snprintf(res->error, sizeof(res->error), "failed to open distributed session"); + goto dist_cleanup; + } + if (!tokenize_official_prompt(dist_engine, vc, &prompt)) { + snprintf(res->error, sizeof(res->error), "failed to tokenize official prompt"); + goto dist_cleanup; + } + if (prompt.len >= vc->ctx) { + snprintf(res->error, sizeof(res->error), "prompt exceeds ctx"); + goto dist_cleanup; + } + double t0 = now_sec(); + if (ds4_session_sync(cand_session, &prompt, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed prefill failed: %s", + err[0] ? err : "unknown error"); + goto dist_cleanup; + } + res->prefill_sec = now_sec() - t0; + if (cfg->payload_out) { + t0 = now_sec(); + if (ds4_session_stage_payload(cand_session, &payload, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed payload stage failed: %s", + err[0] ? err : "unknown error"); + goto dist_cleanup; + } + res->stage_sec = now_sec() - t0; + res->payload_bytes = payload.bytes; + if (!write_payload_copy(&payload, cfg->payload_out, err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "payload export failed: %s", + err[0] ? err : "unknown error"); + goto dist_cleanup; + } + } + + const int vocab = ds4_engine_vocab_size(dist_engine); + cand_logits = malloc((size_t)vocab * sizeof(cand_logits[0])); + if (!cand_logits) { + snprintf(res->error, sizeof(res->error), "out of memory for logits"); + goto dist_cleanup; + } + + for (int step = 0; step < vc->nsteps; step++) { + if (ds4_session_copy_logits(cand_session, cand_logits, vocab) != vocab) { + snprintf(res->error, sizeof(res->error), "failed to copy logits"); + goto dist_cleanup; + } + parity_metrics cmp = compare_logits(cand_logits, cand_logits, vocab); + parity_summary_observe(&res->parity, &cmp, step); + res->steps_checked = step + 1; + + const int cand_token = ds4_session_argmax(cand_session); + if (!token_bytes_equal(dist_engine, cand_token, + vc->steps[step].selected, + vc->steps[step].selected_len)) { + if (res->official_selected_mismatch_step < 0) { + res->official_selected_mismatch_step = step; + } + res->official_pass = false; + } + + const int nscore = ds4_session_top_logprobs(cand_session, scores, 20); + for (int i = 0; i < vc->steps[step].ntop; i++) { + bool found = false; + float local_lp = 0.0f; + for (int j = 0; j < nscore; j++) { + if (scores[j].id < 0) continue; + if (token_bytes_equal(dist_engine, scores[j].id, + vc->steps[step].top[i].bytes, + vc->steps[step].top[i].len)) { + found = true; + local_lp = scores[j].logprob; + break; + } + } + if (!found) { + res->official_missing_top_count++; + res->official_pass = false; + continue; + } + const float delta = fabsf(local_lp - vc->steps[step].top[i].logprob); + if (delta > res->official_max_logprob_delta) { + res->official_max_logprob_delta = delta; + } + if (delta > 4.0f) res->official_pass = false; + } + + if (step + 1 < vc->nsteps) { + if (ds4_session_eval(cand_session, cand_token, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "eval failed after step %d: %s", + step, err[0] ? err : "unknown error"); + goto dist_cleanup; + } + } + } + + res->ok = true; + ok = true; + +dist_cleanup: + free(cand_logits); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(cand_session); + ds4_engine_close(dist_engine); + return ok; + } + + ds4_engine *local_engine = NULL; + ds4_engine *dist_engine = NULL; + ds4_session *ref_session = NULL; + ds4_session *cand_session = NULL; + ds4_session_payload_file payload = {0}; + ds4_tokens prompt = {0}; + float *ref_logits = NULL; + float *cand_logits = NULL; + ds4_token_score scores[20]; + char err[256] = {0}; + bool ok = false; + + if (!set_process_lock_file("/tmp/ds4-phase35-local.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto cleanup; + } + if (!open_host_local_engine(cfg, &local_engine)) { + snprintf(res->error, sizeof(res->error), "failed to open local engine"); + goto cleanup; + } + if (!tokenize_official_prompt(local_engine, vc, &prompt)) { + snprintf(res->error, sizeof(res->error), "failed to tokenize official prompt"); + goto cleanup; + } + if (prompt.len >= vc->ctx) { + snprintf(res->error, sizeof(res->error), "prompt exceeds ctx"); + goto cleanup; + } + if (ds4_session_create(&ref_session, local_engine, vc->ctx) != 0 || !ref_session) { + snprintf(res->error, sizeof(res->error), "failed to create local reference session"); + goto cleanup; + } + if (ds4_session_sync(ref_session, &prompt, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "local baseline prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + + if (cfg->mode == PHASE35_MODE_LOCAL) { + if (ds4_session_create(&cand_session, local_engine, vc->ctx) != 0 || !cand_session) { + snprintf(res->error, sizeof(res->error), "failed to create local candidate session"); + goto cleanup; + } + double t0 = now_sec(); + if (ds4_session_sync(cand_session, &prompt, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "local candidate prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->prefill_sec = now_sec() - t0; + snprintf(res->route_summary, sizeof(res->route_summary), "local"); + res->route_hops = 0; + res->output_on_coordinator = true; + } else if (cfg->mode == PHASE35_MODE_DISTRIBUTED) { + if (!set_process_lock_file("/tmp/ds4-phase35-dist.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto cleanup; + } + if (!open_distributed_session(cfg, vc->ctx, coordinator_layers, + &dist_engine, &cand_session, + res->route_summary, sizeof(res->route_summary), + &res->route_hops, &res->output_on_coordinator)) { + snprintf(res->error, sizeof(res->error), "failed to open distributed session"); + goto cleanup; + } + double t0 = now_sec(); + if (ds4_session_sync(cand_session, &prompt, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->prefill_sec = now_sec() - t0; + if (cfg->payload_out) { + t0 = now_sec(); + if (ds4_session_stage_payload(cand_session, &payload, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed payload stage failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->stage_sec = now_sec() - t0; + res->payload_bytes = payload.bytes; + if (!write_payload_copy(&payload, cfg->payload_out, err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "payload export failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + } + } else if (cfg->mode == PHASE35_MODE_PAYLOAD) { + if (!cfg->payload_file) { + snprintf(res->error, sizeof(res->error), "payload mode requires --payload-file"); + goto cleanup; + } + if (ds4_session_create(&cand_session, local_engine, vc->ctx) != 0 || !cand_session) { + snprintf(res->error, sizeof(res->error), "failed to create payload candidate session"); + goto cleanup; + } + double t0 = now_sec(); + if (!load_payload_path_into_session(cand_session, cfg->payload_file, &res->payload_bytes, + err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "payload load failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->load_sec = now_sec() - t0; + snprintf(res->route_summary, sizeof(res->route_summary), "payload"); + res->route_hops = 0; + res->output_on_coordinator = true; + } + + const int vocab = ds4_engine_vocab_size(local_engine); + ref_logits = malloc((size_t)vocab * sizeof(ref_logits[0])); + cand_logits = malloc((size_t)vocab * sizeof(cand_logits[0])); + if (!ref_logits || !cand_logits) { + snprintf(res->error, sizeof(res->error), "out of memory for logits"); + goto cleanup; + } + + for (int step = 0; step < vc->nsteps; step++) { + if (ds4_session_copy_logits(ref_session, ref_logits, vocab) != vocab || + ds4_session_copy_logits(cand_session, cand_logits, vocab) != vocab) { + snprintf(res->error, sizeof(res->error), "failed to copy logits"); + goto cleanup; + } + + parity_metrics cmp = compare_logits(ref_logits, cand_logits, vocab); + parity_summary_observe(&res->parity, &cmp, step); + res->steps_checked = step + 1; + + const int ref_token = ds4_session_argmax(ref_session); + const int cand_token = ds4_session_argmax(cand_session); + if (!token_bytes_equal(local_engine, cand_token, + vc->steps[step].selected, + vc->steps[step].selected_len)) { + if (res->official_selected_mismatch_step < 0) { + res->official_selected_mismatch_step = step; + } + res->official_pass = false; + } + + const int nscore = ds4_session_top_logprobs(cand_session, scores, 20); + for (int i = 0; i < vc->steps[step].ntop; i++) { + bool found = false; + float local_lp = 0.0f; + for (int j = 0; j < nscore; j++) { + if (scores[j].id < 0) continue; + if (token_bytes_equal(local_engine, scores[j].id, + vc->steps[step].top[i].bytes, + vc->steps[step].top[i].len)) { + found = true; + local_lp = scores[j].logprob; + break; + } + } + if (!found) { + res->official_missing_top_count++; + res->official_pass = false; + continue; + } + const float delta = fabsf(local_lp - vc->steps[step].top[i].logprob); + if (delta > res->official_max_logprob_delta) { + res->official_max_logprob_delta = delta; + } + if (delta > 4.0f) res->official_pass = false; + } + + if (step + 1 < vc->nsteps) { + if (ds4_session_eval(ref_session, ref_token, err, sizeof(err)) != 0 || + ds4_session_eval(cand_session, ref_token, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "eval failed after step %d: %s", + step, err[0] ? err : "unknown error"); + goto cleanup; + } + } + } + + res->ok = true; + ok = true; + +cleanup: + free(cand_logits); + free(ref_logits); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(cand_session); + ds4_session_free(ref_session); + ds4_engine_close(dist_engine); + ds4_engine_close(local_engine); + return ok; +} + +static int golden_overlap(const golden_case *tc, const int *cand_top, int n) { + int overlap = 0; + if (n > tc->ntop) n = tc->ntop; + for (int i = 0; i < n; i++) { + if (topk_contains(cand_top, n, tc->top[i].id)) overlap++; + } + return overlap; +} + +static float golden_top20_max_abs(const golden_case *tc, const float *cand_logits) { + float max_abs = 0.0f; + int n = tc->ntop < 20 ? tc->ntop : 20; + for (int i = 0; i < n; i++) { + const int id = tc->top[i].id; + if (id < 0) continue; + const float abs_delta = fabsf(cand_logits[id] - tc->top[i].logit); + if (abs_delta > max_abs) max_abs = abs_delta; + } + return max_abs; +} + +static bool run_golden_repeat(const phase35_cfg *cfg, + ds4_distributed_layers coordinator_layers, + const golden_case *tc, + repeat_result *res) { + memset(res, 0, sizeof(*res)); + res->official_selected_mismatch_step = -1; + res->golden_pass = true; + + if (cfg->mode == PHASE35_MODE_DISTRIBUTED) { + ds4_engine *dist_engine = NULL; + ds4_session *cand_session = NULL; + ds4_session_payload_file payload = {0}; + ds4_tokens full_prompt = {0}; + ds4_tokens prefix = {0}; + float *cand_logits = NULL; + char err[256] = {0}; + bool ok = false; + + if (!set_process_lock_file("/tmp/ds4-phase35-dist.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto dist_cleanup; + } + if (!open_distributed_session(cfg, tc->ctx, coordinator_layers, + &dist_engine, &cand_session, + res->route_summary, sizeof(res->route_summary), + &res->route_hops, &res->output_on_coordinator)) { + snprintf(res->error, sizeof(res->error), "failed to open distributed session"); + goto dist_cleanup; + } + if (!tokenize_golden_prompt(dist_engine, tc, &full_prompt, &prefix)) { + snprintf(res->error, sizeof(res->error), "failed to tokenize local golden prompt"); + goto dist_cleanup; + } + double t0 = now_sec(); + if (ds4_session_sync(cand_session, &prefix, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed prefill failed: %s", + err[0] ? err : "unknown error"); + goto dist_cleanup; + } + res->prefill_sec = now_sec() - t0; + if (cfg->payload_out) { + t0 = now_sec(); + if (ds4_session_stage_payload(cand_session, &payload, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed payload stage failed: %s", + err[0] ? err : "unknown error"); + goto dist_cleanup; + } + res->stage_sec = now_sec() - t0; + res->payload_bytes = payload.bytes; + if (!write_payload_copy(&payload, cfg->payload_out, err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "payload export failed: %s", + err[0] ? err : "unknown error"); + goto dist_cleanup; + } + } + + const int vocab = ds4_engine_vocab_size(dist_engine); + cand_logits = malloc((size_t)vocab * sizeof(cand_logits[0])); + if (!cand_logits) { + snprintf(res->error, sizeof(res->error), "out of memory for logits"); + goto dist_cleanup; + } + + for (int step = 0; step <= cfg->greedy_steps; step++) { + if (ds4_session_copy_logits(cand_session, cand_logits, vocab) != vocab) { + snprintf(res->error, sizeof(res->error), "failed to copy logits"); + goto dist_cleanup; + } + parity_metrics cmp = compare_logits(cand_logits, cand_logits, vocab); + parity_summary_observe(&res->parity, &cmp, step); + res->steps_checked = step + 1; + + if (step == 0) { + int cand_top[64]; + logits_topk(cand_logits, vocab, cand_top, 64); + res->golden_top1 = cand_top[0]; + res->golden_top5_overlap = golden_overlap(tc, cand_top, 5); + res->golden_top20_overlap = golden_overlap(tc, cand_top, 20); + res->golden_top64_overlap = golden_overlap(tc, cand_top, 64); + res->golden_top20_max_abs = golden_top20_max_abs(tc, cand_logits); + res->golden_pass = cand_top[0] == tc->top[0].id && + res->golden_top5_overlap >= 4 && + res->golden_top20_overlap >= 15 && + res->golden_top64_overlap >= 40 && + res->golden_top20_max_abs <= 8.0f; + } + + if (step == cfg->greedy_steps) break; + const int cand_token = ds4_session_argmax(cand_session); + if (ds4_session_eval(cand_session, cand_token, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "eval failed after step %d: %s", + step, err[0] ? err : "unknown error"); + goto dist_cleanup; + } + } + + res->ok = true; + ok = true; + +dist_cleanup: + free(cand_logits); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&full_prompt); + ds4_session_free(cand_session); + ds4_engine_close(dist_engine); + return ok; + } + + ds4_engine *local_engine = NULL; + ds4_engine *dist_engine = NULL; + ds4_session *ref_session = NULL; + ds4_session *cand_session = NULL; + ds4_session_payload_file payload = {0}; + ds4_tokens full_prompt = {0}; + ds4_tokens prefix = {0}; + float *ref_logits = NULL; + float *cand_logits = NULL; + char err[256] = {0}; + bool ok = false; + + if (!set_process_lock_file("/tmp/ds4-phase35-local.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto cleanup; + } + if (!open_host_local_engine(cfg, &local_engine)) { + snprintf(res->error, sizeof(res->error), "failed to open local engine"); + goto cleanup; + } + if (!tokenize_golden_prompt(local_engine, tc, &full_prompt, &prefix)) { + snprintf(res->error, sizeof(res->error), "failed to tokenize local golden prompt"); + goto cleanup; + } + if (ds4_session_create(&ref_session, local_engine, tc->ctx) != 0 || !ref_session) { + snprintf(res->error, sizeof(res->error), "failed to create local reference session"); + goto cleanup; + } + if (ds4_session_sync(ref_session, &prefix, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "local baseline prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + + if (cfg->mode == PHASE35_MODE_LOCAL) { + if (ds4_session_create(&cand_session, local_engine, tc->ctx) != 0 || !cand_session) { + snprintf(res->error, sizeof(res->error), "failed to create local candidate session"); + goto cleanup; + } + double t0 = now_sec(); + if (ds4_session_sync(cand_session, &prefix, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "local candidate prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->prefill_sec = now_sec() - t0; + snprintf(res->route_summary, sizeof(res->route_summary), "local"); + res->route_hops = 0; + res->output_on_coordinator = true; + } else if (cfg->mode == PHASE35_MODE_DISTRIBUTED) { + if (!set_process_lock_file("/tmp/ds4-phase35-dist.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto cleanup; + } + if (!open_distributed_session(cfg, tc->ctx, coordinator_layers, + &dist_engine, &cand_session, + res->route_summary, sizeof(res->route_summary), + &res->route_hops, &res->output_on_coordinator)) { + snprintf(res->error, sizeof(res->error), "failed to open distributed session"); + goto cleanup; + } + double t0 = now_sec(); + if (ds4_session_sync(cand_session, &prefix, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->prefill_sec = now_sec() - t0; + if (cfg->payload_out) { + t0 = now_sec(); + if (ds4_session_stage_payload(cand_session, &payload, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed payload stage failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->stage_sec = now_sec() - t0; + res->payload_bytes = payload.bytes; + if (!write_payload_copy(&payload, cfg->payload_out, err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "payload export failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + } + } else if (cfg->mode == PHASE35_MODE_PAYLOAD) { + if (!cfg->payload_file) { + snprintf(res->error, sizeof(res->error), "payload mode requires --payload-file"); + goto cleanup; + } + if (ds4_session_create(&cand_session, local_engine, tc->ctx) != 0 || !cand_session) { + snprintf(res->error, sizeof(res->error), "failed to create payload candidate session"); + goto cleanup; + } + double t0 = now_sec(); + if (!load_payload_path_into_session(cand_session, cfg->payload_file, &res->payload_bytes, + err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "payload load failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->load_sec = now_sec() - t0; + snprintf(res->route_summary, sizeof(res->route_summary), "payload"); + res->route_hops = 0; + res->output_on_coordinator = true; + } + + const int vocab = ds4_engine_vocab_size(local_engine); + ref_logits = malloc((size_t)vocab * sizeof(ref_logits[0])); + cand_logits = malloc((size_t)vocab * sizeof(cand_logits[0])); + if (!ref_logits || !cand_logits) { + snprintf(res->error, sizeof(res->error), "out of memory for logits"); + goto cleanup; + } + + for (int step = 0; step <= cfg->greedy_steps; step++) { + if (ds4_session_copy_logits(ref_session, ref_logits, vocab) != vocab || + ds4_session_copy_logits(cand_session, cand_logits, vocab) != vocab) { + snprintf(res->error, sizeof(res->error), "failed to copy logits"); + goto cleanup; + } + + parity_metrics cmp = compare_logits(ref_logits, cand_logits, vocab); + parity_summary_observe(&res->parity, &cmp, step); + res->steps_checked = step + 1; + + if (step == 0) { + int cand_top[64]; + logits_topk(cand_logits, vocab, cand_top, 64); + res->golden_top1 = cand_top[0]; + res->golden_top5_overlap = golden_overlap(tc, cand_top, 5); + res->golden_top20_overlap = golden_overlap(tc, cand_top, 20); + res->golden_top64_overlap = golden_overlap(tc, cand_top, 64); + res->golden_top20_max_abs = golden_top20_max_abs(tc, cand_logits); + res->golden_pass = cand_top[0] == tc->top[0].id && + res->golden_top5_overlap >= 4 && + res->golden_top20_overlap >= 15 && + res->golden_top64_overlap >= 40 && + res->golden_top20_max_abs <= 8.0f; + } + + if (step == cfg->greedy_steps) break; + const int ref_token = ds4_session_argmax(ref_session); + if (ds4_session_eval(ref_session, ref_token, err, sizeof(err)) != 0 || + ds4_session_eval(cand_session, ref_token, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "eval failed after step %d: %s", + step, err[0] ? err : "unknown error"); + goto cleanup; + } + } + + res->ok = true; + ok = true; + +cleanup: + free(cand_logits); + free(ref_logits); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&full_prompt); + ds4_session_free(cand_session); + ds4_session_free(ref_session); + ds4_engine_close(dist_engine); + ds4_engine_close(local_engine); + return ok; +} + +static void summary_observe_repeat(case_summary *sum, const repeat_result *res) { + if (sum->repeats == 0) { + sum->worst_parity = res->parity; + sum->official_pass = res->official_pass; + sum->official_selected_mismatch_step = res->official_selected_mismatch_step; + sum->official_missing_top_count = res->official_missing_top_count; + sum->official_max_logprob_delta = res->official_max_logprob_delta; + sum->golden_pass = res->golden_pass; + sum->golden_top1 = res->golden_top1; + sum->golden_top5_overlap = res->golden_top5_overlap; + sum->golden_top20_overlap = res->golden_top20_overlap; + sum->golden_top64_overlap = res->golden_top64_overlap; + sum->golden_top20_max_abs = res->golden_top20_max_abs; + snprintf(sum->route_summary, sizeof(sum->route_summary), "%s", res->route_summary); + sum->route_hops = res->route_hops; + sum->output_on_coordinator = res->output_on_coordinator; + } else { + if (res->parity.top5_overlap < sum->worst_parity.top5_overlap) { + sum->worst_parity.top5_overlap = res->parity.top5_overlap; + } + if (res->parity.top20_overlap < sum->worst_parity.top20_overlap) { + sum->worst_parity.top20_overlap = res->parity.top20_overlap; + } + if (res->parity.top64_overlap < sum->worst_parity.top64_overlap) { + sum->worst_parity.top64_overlap = res->parity.top64_overlap; + } + if (res->parity.nonfinite > sum->worst_parity.nonfinite) { + sum->worst_parity.nonfinite = res->parity.nonfinite; + } + if (res->parity.rms > sum->worst_parity.rms) { + sum->worst_parity.rms = res->parity.rms; + } + if (res->parity.max_abs > sum->worst_parity.max_abs) { + sum->worst_parity.max_abs = res->parity.max_abs; + } + if (res->parity.top20_max_abs > sum->worst_parity.top20_max_abs) { + sum->worst_parity.top20_max_abs = res->parity.top20_max_abs; + } + if (sum->worst_parity.first_top1_mismatch_step < 0 && + res->parity.first_top1_mismatch_step >= 0) { + sum->worst_parity.first_top1_mismatch_step = res->parity.first_top1_mismatch_step; + sum->worst_parity.top1_ref = res->parity.top1_ref; + sum->worst_parity.top1_cand = res->parity.top1_cand; + sum->worst_parity.first_ref_token = res->parity.first_ref_token; + sum->worst_parity.first_cand_token = res->parity.first_cand_token; + } + sum->official_pass = sum->official_pass && res->official_pass; + if (sum->official_selected_mismatch_step < 0 || + (res->official_selected_mismatch_step >= 0 && + res->official_selected_mismatch_step < sum->official_selected_mismatch_step)) { + if (res->official_selected_mismatch_step >= 0) { + sum->official_selected_mismatch_step = res->official_selected_mismatch_step; + } + } + sum->official_missing_top_count += res->official_missing_top_count; + if (res->official_max_logprob_delta > sum->official_max_logprob_delta) { + sum->official_max_logprob_delta = res->official_max_logprob_delta; + } + sum->golden_pass = sum->golden_pass && res->golden_pass; + if (res->golden_top5_overlap < sum->golden_top5_overlap) { + sum->golden_top5_overlap = res->golden_top5_overlap; + } + if (res->golden_top20_overlap < sum->golden_top20_overlap) { + sum->golden_top20_overlap = res->golden_top20_overlap; + } + if (res->golden_top64_overlap < sum->golden_top64_overlap) { + sum->golden_top64_overlap = res->golden_top64_overlap; + } + if (res->golden_top20_max_abs > sum->golden_top20_max_abs) { + sum->golden_top20_max_abs = res->golden_top20_max_abs; + } + } + if (res->ok) sum->passes++; + sum->repeats++; + if (res->payload_bytes > sum->payload_bytes_max) sum->payload_bytes_max = res->payload_bytes; + if (res->prefill_sec > sum->prefill_sec_max) sum->prefill_sec_max = res->prefill_sec; + if (res->stage_sec > sum->stage_sec_max) sum->stage_sec_max = res->stage_sec; + if (res->load_sec > sum->load_sec_max) sum->load_sec_max = res->load_sec; +} + +static void print_repeat_result(const phase35_cfg *cfg, + const char *case_id, + int ctx, + int repeat_index, + const repeat_result *res) { + printf("{\"mode\":\"%s\",\"suite\":\"%s\",\"case\":\"%s\",\"ctx\":%d,\"repeat\":%d," + "\"ok\":%s,\"route_summary\":\"%s\",\"payload_bytes\":%llu," + "\"prefill_sec\":%.6f,\"stage_sec\":%.6f,\"load_sec\":%.6f," + "\"parity\":{\"envelope\":\"%s\",\"first_top1_mismatch_step\":%d," + "\"top1_ref\":%d,\"top1_cand\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"rms\":%.9g," + "\"max_abs\":%.9g,\"top20_max_abs\":%.9g,\"nonfinite\":%d}," + "\"official\":{\"pass\":%s,\"selected_mismatch_step\":%d," + "\"missing_top_count\":%d,\"max_logprob_delta\":%.9g}," + "\"golden\":{\"pass\":%s,\"top1\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"top20_max_abs\":%.9g}," + "\"error\":\"%s\"}\n", + mode_name(cfg->mode), + suite_name(cfg->suite), + case_id, + ctx, + repeat_index, + res->ok ? "true" : "false", + res->route_summary, + (unsigned long long)res->payload_bytes, + res->prefill_sec, + res->stage_sec, + res->load_sec, + parity_envelope(&res->parity), + res->parity.first_top1_mismatch_step, + res->parity.top1_ref, + res->parity.top1_cand, + res->parity.top5_overlap, + res->parity.top20_overlap, + res->parity.top64_overlap, + res->parity.rms, + res->parity.max_abs, + res->parity.top20_max_abs, + res->parity.nonfinite, + res->official_pass ? "true" : "false", + res->official_selected_mismatch_step, + res->official_missing_top_count, + res->official_max_logprob_delta, + res->golden_pass ? "true" : "false", + res->golden_top1, + res->golden_top5_overlap, + res->golden_top20_overlap, + res->golden_top64_overlap, + res->golden_top20_max_abs, + res->error); +} + +static void print_case_summary(const phase35_cfg *cfg, + const char *case_id, + int ctx, + const case_summary *sum) { + printf("{\"mode\":\"%s\",\"suite\":\"%s\",\"case\":\"%s\",\"ctx\":%d,\"worst_at_%d\":{" + "\"passes\":%d,\"route_summary\":\"%s\",\"payload_bytes_max\":%llu," + "\"prefill_sec_max\":%.6f,\"stage_sec_max\":%.6f,\"load_sec_max\":%.6f," + "\"parity\":{\"envelope\":\"%s\",\"first_top1_mismatch_step\":%d," + "\"top1_ref\":%d,\"top1_cand\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"rms\":%.9g," + "\"max_abs\":%.9g,\"top20_max_abs\":%.9g,\"nonfinite\":%d}," + "\"official\":{\"pass\":%s,\"selected_mismatch_step\":%d," + "\"missing_top_count\":%d,\"max_logprob_delta\":%.9g}," + "\"golden\":{\"pass\":%s,\"top1\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"top20_max_abs\":%.9g}}}\n", + mode_name(cfg->mode), + suite_name(cfg->suite), + case_id, + ctx, + sum->repeats, + sum->passes, + sum->route_summary, + (unsigned long long)sum->payload_bytes_max, + sum->prefill_sec_max, + sum->stage_sec_max, + sum->load_sec_max, + parity_envelope(&sum->worst_parity), + sum->worst_parity.first_top1_mismatch_step, + sum->worst_parity.top1_ref, + sum->worst_parity.top1_cand, + sum->worst_parity.top5_overlap, + sum->worst_parity.top20_overlap, + sum->worst_parity.top64_overlap, + sum->worst_parity.rms, + sum->worst_parity.max_abs, + sum->worst_parity.top20_max_abs, + sum->worst_parity.nonfinite, + sum->official_pass ? "true" : "false", + sum->official_selected_mismatch_step, + sum->official_missing_top_count, + sum->official_max_logprob_delta, + sum->golden_pass ? "true" : "false", + sum->golden_top1, + sum->golden_top5_overlap, + sum->golden_top20_overlap, + sum->golden_top64_overlap, + sum->golden_top20_max_abs); +} + +static void parse_args(phase35_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--mode") && i + 1 < argc) { + cfg->mode_name = argv[++i]; + if (!strcmp(cfg->mode_name, "local")) { + cfg->mode = PHASE35_MODE_LOCAL; + } else if (!strcmp(cfg->mode_name, "distributed")) { + cfg->mode = PHASE35_MODE_DISTRIBUTED; + } else if (!strcmp(cfg->mode_name, "payload")) { + cfg->mode = PHASE35_MODE_PAYLOAD; + } else { + usage(argv[0]); + } + } else if (!strcmp(argv[i], "--suite") && i + 1 < argc) { + const char *suite = argv[++i]; + if (!strcmp(suite, "official")) { + cfg->suite = PHASE35_SUITE_OFFICIAL; + } else if (!strcmp(suite, "local-golden")) { + cfg->suite = PHASE35_SUITE_LOCAL_GOLDEN; + } else { + usage(argv[0]); + } + } else if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--listen-host") && i + 1 < argc) { + cfg->listen_host = argv[++i]; + } else if (!strcmp(argv[i], "--listen-port") && i + 1 < argc) { + cfg->listen_port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--vector-file") && i + 1 < argc) { + cfg->vector_file = argv[++i]; + } else if (!strcmp(argv[i], "--local-golden-file") && i + 1 < argc) { + cfg->local_golden_file = argv[++i]; + } else if (!strcmp(argv[i], "--case-filter") && i + 1 < argc) { + cfg->case_filter = argv[++i]; + } else if (!strcmp(argv[i], "--repeat") && i + 1 < argc) { + cfg->repeat = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx-filter") && i + 1 < argc) { + cfg->ctx_filter = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--greedy-steps") && i + 1 < argc) { + cfg->greedy_steps = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--power") && i + 1 < argc) { + cfg->power_percent = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { + cfg->coordinator_layers = argv[++i]; + } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { + cfg->worker_layers = argv[++i]; + } else if (!strcmp(argv[i], "--payload-file") && i + 1 < argc) { + cfg->payload_file = argv[++i]; + } else if (!strcmp(argv[i], "--payload-out") && i + 1 < argc) { + cfg->payload_out = argv[++i]; + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + usage(argv[0]); + } + } +} + +int main(int argc, char **argv) { + phase35_cfg cfg = { + .model_path = NULL, + .mode_name = "local", + .listen_host = NULL, + .vector_file = "tests/test-vectors/official.vec", + .local_golden_file = "tests/test-vectors/local-golden.vec", + .case_filter = NULL, + .coordinator_layers = "0:21", + .worker_layers = "22:output", + .payload_file = NULL, + .payload_out = NULL, + .listen_port = 1234, + .repeat = 5, + .ctx_filter = 0, + .greedy_steps = 8, + .prefill_chunk = 256, + .prefill_window = 0, + .activation_bits = 32, + .power_percent = 100, + .debug = true, + .suite = PHASE35_SUITE_OFFICIAL, + .mode = PHASE35_MODE_LOCAL, + }; + parse_args(&cfg, argc, argv); + if (!cfg.model_path || cfg.repeat <= 0) { + usage(argv[0]); + } + if (cfg.power_percent < 1 || cfg.power_percent > 100) { + die("--power must be between 1 and 100"); + } + + ds4_distributed_layers coordinator_layers = {0}; + if (cfg.mode == PHASE35_MODE_DISTRIBUTED) { + if (!cfg.listen_host || cfg.listen_port <= 0) usage(argv[0]); + struct in_addr addr; + if (inet_pton(AF_INET, cfg.listen_host, &addr) != 1) { + die("listen host must be an IPv4 address reachable from the worker"); + } + if (!parse_layer_spec(cfg.coordinator_layers, &coordinator_layers)) { + die("invalid coordinator layer spec"); + } + } else if (cfg.mode == PHASE35_MODE_PAYLOAD) { + if (!cfg.payload_file) usage(argv[0]); + } + + int failures = 0; + if (cfg.suite == PHASE35_SUITE_OFFICIAL) { + FILE *fp = fopen(cfg.vector_file, "rb"); + if (!fp) die_errno("open official vectors"); + official_case vc; + while (read_official_case(fp, &vc)) { + if (!fill_official_case(fp, &vc)) die("parse official vector case"); + if (official_case_disabled(&vc)) continue; + if (!case_selected(vc.id, cfg.case_filter)) continue; + if (cfg.ctx_filter > 0 && vc.ctx != cfg.ctx_filter) continue; + + case_summary sum = {0}; + sum.official_selected_mismatch_step = -1; + for (int i = 0; i < cfg.repeat; i++) { + repeat_result res = {0}; + if (!run_official_repeat(&cfg, coordinator_layers, &vc, &res)) { + print_repeat_result(&cfg, vc.id, vc.ctx, i + 1, &res); + fclose(fp); + return 1; + } + summary_observe_repeat(&sum, &res); + print_repeat_result(&cfg, vc.id, vc.ctx, i + 1, &res); + if (i + 1 < cfg.repeat && + (cfg.mode == PHASE35_MODE_DISTRIBUTED || cfg.mode == PHASE35_MODE_PAYLOAD)) { + sleep(2); + } + } + print_case_summary(&cfg, vc.id, vc.ctx, &sum); + if (!sum.official_pass) failures++; + } + fclose(fp); + } else { + FILE *fp = fopen(cfg.local_golden_file, "rb"); + if (!fp) die_errno("open local golden vectors"); + golden_case tc; + while (read_golden_case(fp, &tc)) { + if (!fill_golden_case(fp, &tc)) die("parse local golden vector case"); + if (!case_selected(tc.id, cfg.case_filter)) continue; + if (cfg.ctx_filter > 0 && tc.ctx != cfg.ctx_filter) continue; + + case_summary sum = {0}; + sum.official_selected_mismatch_step = -1; + for (int i = 0; i < cfg.repeat; i++) { + repeat_result res = {0}; + if (!run_golden_repeat(&cfg, coordinator_layers, &tc, &res)) { + print_repeat_result(&cfg, tc.id, tc.ctx, i + 1, &res); + fclose(fp); + return 1; + } + summary_observe_repeat(&sum, &res); + print_repeat_result(&cfg, tc.id, tc.ctx, i + 1, &res); + if (i + 1 < cfg.repeat && + (cfg.mode == PHASE35_MODE_DISTRIBUTED || cfg.mode == PHASE35_MODE_PAYLOAD)) { + sleep(2); + } + } + print_case_summary(&cfg, tc.id, tc.ctx, &sum); + if (!sum.golden_pass) failures++; + } + fclose(fp); + } + return failures == 0 ? 0 : 1; +} diff --git a/tests/issue304_phase3_vectors.c b/tests/issue304_phase3_vectors.c new file mode 100644 index 000000000..9c1ab884a --- /dev/null +++ b/tests/issue304_phase3_vectors.c @@ -0,0 +1,1309 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHASE3_MAX_TOP 128 +#define PHASE3_MAX_STEPS 16 +#define PHASE3_MAX_TOKEN_BYTES 128 + +typedef enum { + PHASE3_SUITE_OFFICIAL, + PHASE3_SUITE_LOCAL_GOLDEN, +} phase3_suite; + +typedef struct { + const char *model_path; + const char *listen_host; + const char *vector_file; + const char *local_golden_file; + const char *coordinator_layers; + const char *worker_layers; + int listen_port; + int repeat; + int ctx_filter; + int greedy_steps; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + bool debug; + phase3_suite suite; +} phase3_cfg; + +typedef struct { + unsigned char bytes[PHASE3_MAX_TOKEN_BYTES]; + int len; + float logprob; +} official_top; + +typedef struct { + unsigned char selected[PHASE3_MAX_TOKEN_BYTES]; + int selected_len; + int ntop; + official_top top[32]; +} official_step; + +typedef struct { + char id[96]; + char prompt_path[512]; + int ctx; + int nsteps; + official_step steps[PHASE3_MAX_STEPS]; +} official_case; + +typedef struct { + int id; + float logit; +} golden_top; + +typedef struct { + char id[96]; + char mode[16]; + char prompt_path[512]; + int ctx; + int frontier; + int ntop; + golden_top top[PHASE3_MAX_TOP]; +} golden_case; + +typedef struct { + int top1_ref; + int top1_cand; + int top5_overlap; + int top20_overlap; + int top64_overlap; + int nonfinite; + float rms; + float max_abs; + float top20_max_abs; +} parity_metrics; + +typedef struct { + bool initialized; + int top1_ref; + int top1_cand; + int top5_overlap; + int top20_overlap; + int top64_overlap; + int nonfinite; + float rms; + float max_abs; + float top20_max_abs; + int first_top1_mismatch_step; + int first_ref_token; + int first_cand_token; +} parity_summary; + +typedef struct { + bool ok; + char error[256]; + char route_summary[1024]; + uint32_t route_hops; + bool output_on_coordinator; + uint64_t payload_bytes; + double prefill_sec; + double stage_sec; + double load_sec; + parity_summary parity; + int steps_checked; + bool official_pass; + int official_selected_mismatch_step; + int official_missing_top_count; + float official_max_logprob_delta; + bool golden_pass; + int golden_top1; + int golden_top5_overlap; + int golden_top20_overlap; + int golden_top64_overlap; + float golden_top20_max_abs; +} repeat_result; + +typedef struct { + int repeats; + int passes; + parity_summary worst_parity; + bool official_pass; + int official_selected_mismatch_step; + int official_missing_top_count; + float official_max_logprob_delta; + bool golden_pass; + int golden_top1; + int golden_top5_overlap; + int golden_top20_overlap; + int golden_top64_overlap; + float golden_top20_max_abs; + uint64_t payload_bytes_max; + double prefill_sec_max; + double stage_sec_max; + double load_sec_max; + char route_summary[1024]; + uint32_t route_hops; + bool output_on_coordinator; +} case_summary; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase3-vectors: %s\n", msg); + exit(1); +} + +static void die_errno(const char *msg) { + fprintf(stderr, "issue304-phase3-vectors: %s: %s\n", msg, strerror(errno)); + exit(1); +} + +static void usage(const char *argv0) { + fprintf(stderr, + "usage: %s --suite official|local-golden --model FILE --listen-host IPV4 --listen-port N " + "[--vector-file FILE] [--local-golden-file FILE] [--repeat N] [--ctx-filter N] " + "[--greedy-steps N] [--prefill-chunk N] [--prefill-window N] [--activation-bits N] " + "[--coordinator-layers A:B|A:output] [--worker-layers A:B|A:output] [--no-debug]\n", + argv0); + exit(2); +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (len != 0 && fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static char *trim_line(char *line) { + while (*line && isspace((unsigned char)*line)) line++; + size_t n = strlen(line); + while (n && isspace((unsigned char)line[n - 1])) line[--n] = '\0'; + return line; +} + +static int hex_digit(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + c - 'a'; + if (c >= 'A' && c <= 'F') return 10 + c - 'A'; + return -1; +} + +static bool hex_to_bytes(const char *hex, unsigned char *out, int cap, int *len) { + int n = 0; + while (*hex && !isspace((unsigned char)*hex)) { + int hi = hex_digit(hex[0]); + int lo = hex_digit(hex[1]); + if (hi < 0 || lo < 0 || n >= cap) return false; + out[n++] = (unsigned char)((hi << 4) | lo); + hex += 2; + } + *len = n; + return true; +} + +static bool token_bytes_equal(ds4_engine *engine, int token, + const unsigned char *want, int want_len) { + size_t got_len = 0; + char *got = ds4_token_text(engine, token, &got_len); + bool eq = got && got_len == (size_t)want_len && + memcmp(got, want, (size_t)want_len) == 0; + free(got); + return eq; +} + +static void logits_topk(const float *logits, int n, int *out, int k) { + for (int i = 0; i < k; i++) out[i] = -1; + for (int i = 0; i < n; i++) { + const float v = logits[i]; + for (int j = 0; j < k; j++) { + if (out[j] < 0 || v > logits[out[j]]) { + for (int t = k - 1; t > j; t--) out[t] = out[t - 1]; + out[j] = i; + break; + } + } + } +} + +static bool topk_contains(const int *top, int k, int id) { + for (int i = 0; i < k; i++) { + if (top[i] == id) return true; + } + return false; +} + +static parity_metrics compare_logits(const float *ref, const float *cand, int vocab) { + int ref_top[64]; + int cand_top[64]; + logits_topk(ref, vocab, ref_top, 64); + logits_topk(cand, vocab, cand_top, 64); + + int top5_overlap = 0; + int top20_overlap = 0; + int top64_overlap = 0; + for (int i = 0; i < 64; i++) { + if (ref_top[i] >= 0 && topk_contains(cand_top, 64, ref_top[i])) top64_overlap++; + if (i < 20 && ref_top[i] >= 0 && topk_contains(cand_top, 20, ref_top[i])) top20_overlap++; + if (i < 5 && ref_top[i] >= 0 && topk_contains(cand_top, 5, ref_top[i])) top5_overlap++; + } + + int nonfinite = 0; + double sumsq = 0.0; + float max_abs = 0.0f; + float top20_max_abs = 0.0f; + for (int i = 0; i < vocab; i++) { + if (!isfinite(ref[i]) || !isfinite(cand[i])) { + nonfinite++; + continue; + } + float delta = cand[i] - ref[i]; + float abs_delta = fabsf(delta); + if (abs_delta > max_abs) max_abs = abs_delta; + sumsq += (double)delta * (double)delta; + } + for (int i = 0; i < 20; i++) { + const int id = ref_top[i]; + if (id < 0) continue; + const float abs_delta = fabsf(cand[id] - ref[id]); + if (abs_delta > top20_max_abs) top20_max_abs = abs_delta; + } + + parity_metrics out = { + .top1_ref = ref_top[0], + .top1_cand = cand_top[0], + .top5_overlap = top5_overlap, + .top20_overlap = top20_overlap, + .top64_overlap = top64_overlap, + .nonfinite = nonfinite, + .rms = (float)sqrt(sumsq / (double)vocab), + .max_abs = max_abs, + .top20_max_abs = top20_max_abs, + }; + return out; +} + +static void parity_summary_observe(parity_summary *out, + const parity_metrics *m, + int step) { + if (!out->initialized) { + out->initialized = true; + out->top1_ref = m->top1_ref; + out->top1_cand = m->top1_cand; + out->top5_overlap = m->top5_overlap; + out->top20_overlap = m->top20_overlap; + out->top64_overlap = m->top64_overlap; + out->nonfinite = m->nonfinite; + out->rms = m->rms; + out->max_abs = m->max_abs; + out->top20_max_abs = m->top20_max_abs; + out->first_top1_mismatch_step = (m->top1_ref == m->top1_cand) ? -1 : step; + out->first_ref_token = m->top1_ref; + out->first_cand_token = m->top1_cand; + return; + } + + if (m->top5_overlap < out->top5_overlap) out->top5_overlap = m->top5_overlap; + if (m->top20_overlap < out->top20_overlap) out->top20_overlap = m->top20_overlap; + if (m->top64_overlap < out->top64_overlap) out->top64_overlap = m->top64_overlap; + if (m->nonfinite > out->nonfinite) out->nonfinite = m->nonfinite; + if (m->rms > out->rms) out->rms = m->rms; + if (m->max_abs > out->max_abs) out->max_abs = m->max_abs; + if (m->top20_max_abs > out->top20_max_abs) out->top20_max_abs = m->top20_max_abs; + if (out->first_top1_mismatch_step < 0 && m->top1_ref != m->top1_cand) { + out->first_top1_mismatch_step = step; + out->top1_ref = m->top1_ref; + out->top1_cand = m->top1_cand; + out->first_ref_token = m->top1_ref; + out->first_cand_token = m->top1_cand; + } +} + +static bool parity_pass_strict(const parity_summary *p) { + return p->initialized && + p->first_top1_mismatch_step < 0 && + p->top5_overlap == 5 && + p->top20_overlap == 20 && + p->top64_overlap >= 60 && + p->nonfinite == 0 && + p->top20_max_abs <= 2.0f && + p->rms <= 0.1f; +} + +static bool parity_pass_medium(const parity_summary *p) { + return p->initialized && + p->first_top1_mismatch_step < 0 && + p->top5_overlap == 5 && + p->top20_overlap == 20 && + p->top64_overlap >= 56 && + p->nonfinite == 0 && + p->top20_max_abs <= 4.0f && + p->rms <= 0.25f; +} + +static bool parity_pass_tolerant(const parity_summary *p) { + return p->initialized && + p->first_top1_mismatch_step < 0 && + p->top5_overlap >= 4 && + p->top20_overlap >= 15 && + p->top64_overlap >= 40 && + p->nonfinite == 0 && + p->top20_max_abs <= 8.0f; +} + +static const char *parity_envelope(const parity_summary *p) { + if (parity_pass_strict(p)) return "strict"; + if (parity_pass_medium(p)) return "medium"; + if (parity_pass_tolerant(p)) return "tolerant"; + return "fail"; +} + +static bool official_case_disabled(const official_case *vc) { + return !strcmp(vc->id, "long_memory_archive"); +} + +static bool read_official_case(FILE *fp, official_case *vc) { + char line[2048]; + memset(vc, 0, sizeof(*vc)); + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (sscanf(p, "case %95s %d %d %511s", + vc->id, &vc->ctx, &vc->nsteps, vc->prompt_path) == 4) { + return vc->nsteps > 0 && vc->nsteps <= PHASE3_MAX_STEPS; + } + return false; + } + return false; +} + +static bool fill_official_case(FILE *fp, official_case *vc) { + char line[2048]; + int step_index = -1; + int top_index = 0; + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (!strcmp(p, "end")) return true; + if (!strncmp(p, "step ", 5)) { + char hex[PHASE3_MAX_TOKEN_BYTES * 2 + 2]; + int ntop = 0; + if (sscanf(p, "step %d %257s %d", &step_index, hex, &ntop) != 3) { + return false; + } + if (step_index < 0 || step_index >= vc->nsteps || ntop < 0 || ntop > 32) { + return false; + } + vc->steps[step_index].ntop = ntop; + if (!hex_to_bytes(hex, + vc->steps[step_index].selected, + PHASE3_MAX_TOKEN_BYTES, + &vc->steps[step_index].selected_len)) { + return false; + } + top_index = 0; + continue; + } + if (!strncmp(p, "top ", 4)) { + char hex[PHASE3_MAX_TOKEN_BYTES * 2 + 2]; + float lp = 0.0f; + if (step_index < 0 || step_index >= vc->nsteps || + top_index >= vc->steps[step_index].ntop) { + return false; + } + if (sscanf(p, "top %257s %f", hex, &lp) != 2) { + return false; + } + official_top *top = &vc->steps[step_index].top[top_index++]; + top->logprob = lp; + if (!hex_to_bytes(hex, top->bytes, PHASE3_MAX_TOKEN_BYTES, &top->len)) { + return false; + } + continue; + } + return false; + } + return false; +} + +static bool read_golden_case(FILE *fp, golden_case *tc) { + char line[2048]; + memset(tc, 0, sizeof(*tc)); + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (sscanf(p, "case %95s %15s %d %d %511s %d", + tc->id, tc->mode, &tc->ctx, &tc->frontier, + tc->prompt_path, &tc->ntop) == 6) { + return tc->ctx > tc->frontier && + tc->frontier > 0 && + tc->ntop > 0 && + tc->ntop <= PHASE3_MAX_TOP; + } + return false; + } + return false; +} + +static bool fill_golden_case(FILE *fp, golden_case *tc) { + char line[2048]; + int seen = 0; + while (fgets(line, sizeof(line), fp)) { + char *p = trim_line(line); + if (!p[0] || p[0] == '#') continue; + if (!strcmp(p, "end")) return seen == tc->ntop; + int rank = -1; + int id = -1; + float logit = 0.0f; + if (sscanf(p, "top %d %d %f", &rank, &id, &logit) != 3) return false; + if (rank != seen || seen >= tc->ntop) return false; + tc->top[seen].id = id; + tc->top[seen].logit = logit; + seen++; + } + return false; +} + +static bool parse_layer_spec(const char *spec, ds4_distributed_layers *out) { + if (!spec || !out) return false; + const char *colon = strchr(spec, ':'); + if (!colon || colon == spec || colon[1] == '\0') return false; + + errno = 0; + char *end = NULL; + unsigned long start = strtoul(spec, &end, 10); + if (errno != 0 || end != colon || start > UINT32_MAX) return false; + + ds4_distributed_layers layers = {0}; + layers.start = (uint32_t)start; + layers.set = true; + if (!strcmp(colon + 1, "output")) { + layers.has_output = true; + layers.end = 0; + } else { + errno = 0; + unsigned long layer_end = strtoul(colon + 1, &end, 10); + if (errno != 0 || *end != '\0' || layer_end > UINT32_MAX) return false; + layers.end = (uint32_t)layer_end; + } + *out = layers; + return true; +} + +static int wait_route(ds4_session *session, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase3-vectors: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase3-vectors: timed out waiting for route\n"); + return 0; +} + +static bool set_process_lock_file(const char *path, char *err, size_t errlen) { + if (!path || !path[0]) { + snprintf(err, errlen, "invalid lock file path"); + return false; + } + if (setenv("DS4_LOCK_FILE", path, 1) != 0) { + snprintf(err, errlen, "failed to set DS4_LOCK_FILE: %s", strerror(errno)); + return false; + } + return true; +} + +static bool load_payload_into_session(ds4_session *session, + const ds4_session_payload_file *payload, + char *err, + size_t errlen) { + FILE *fp = fopen(payload->path, "rb"); + if (!fp) { + snprintf(err, errlen, "failed to open staged payload: %s", strerror(errno)); + return false; + } + const int rc = ds4_session_load_payload(session, fp, payload->bytes, err, errlen); + fclose(fp); + return rc == 0; +} + +static bool tokenize_official_prompt(ds4_engine *engine, + const official_case *vc, + ds4_tokens *out) { + memset(out, 0, sizeof(*out)); + char *prompt_text = read_file(vc->prompt_path); + if (!prompt_text) return false; + ds4_encode_chat_prompt(engine, "", prompt_text, DS4_THINK_NONE, out); + free(prompt_text); + return out->len > 0; +} + +static bool tokenize_golden_prompt(ds4_engine *engine, + const golden_case *tc, + ds4_tokens *full_prompt, + ds4_tokens *prefix) { + memset(full_prompt, 0, sizeof(*full_prompt)); + memset(prefix, 0, sizeof(*prefix)); + char *prompt_text = read_file(tc->prompt_path); + if (!prompt_text) return false; + if (!strcmp(tc->mode, "text")) { + ds4_tokenize_text(engine, prompt_text, full_prompt); + } else if (!strcmp(tc->mode, "rendered")) { + ds4_tokenize_rendered_chat(engine, prompt_text, full_prompt); + } else if (!strcmp(tc->mode, "chat")) { + ds4_encode_chat_prompt(engine, "", prompt_text, DS4_THINK_NONE, full_prompt); + } else { + free(prompt_text); + return false; + } + free(prompt_text); + if (full_prompt->len < tc->frontier) return false; + prefix->v = full_prompt->v; + prefix->len = tc->frontier; + prefix->cap = tc->frontier; + return prefix->len > 0; +} + +static bool open_distributed_session(const phase3_cfg *cfg, + int ctx, + ds4_distributed_layers coordinator_layers, + ds4_engine **engine_out, + ds4_session **session_out, + char *route_summary, + size_t route_summary_len, + uint32_t *route_hops, + bool *output_on_coordinator) { + *engine_out = NULL; + *session_out = NULL; + char err[256] = {0}; + ds4_engine_options dist_opt = { + .model_path = cfg->model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = coordinator_layers, + .listen_host = cfg->listen_host, + .listen_port = cfg->listen_port, + .prefill_chunk = cfg->prefill_chunk, + .prefill_window = cfg->prefill_window, + .activation_bits = cfg->activation_bits, + .debug = cfg->debug, + }, + }; + if (ds4_dist_prepare_engine_options(&dist_opt.distributed, &dist_opt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase3-vectors: distributed options failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + if (ds4_engine_open(engine_out, &dist_opt) != 0 || !*engine_out) return false; + if (ds4_session_create(session_out, *engine_out, ctx) != 0 || !*session_out) return false; + if (wait_route(*session_out, 60.0) != 1) return false; + if (ds4_session_distributed_route_summary(*session_out, + route_summary, + route_summary_len, + route_hops, + output_on_coordinator, + err, + sizeof(err)) != 1) { + fprintf(stderr, "issue304-phase3-vectors: route summary failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + return true; +} + +static bool stage_distributed_payload(ds4_session *dist_session, + const ds4_tokens *prompt, + repeat_result *res, + ds4_session_payload_file *payload) { + char err[256] = {0}; + double t0 = now_sec(); + if (ds4_session_sync(dist_session, prompt, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed prefill failed: %s", + err[0] ? err : "unknown error"); + return false; + } + res->prefill_sec = now_sec() - t0; + + t0 = now_sec(); + if (ds4_session_stage_payload(dist_session, payload, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "distributed payload stage failed: %s", + err[0] ? err : "unknown error"); + return false; + } + res->stage_sec = now_sec() - t0; + res->payload_bytes = payload->bytes; + return true; +} + +static bool run_official_repeat(const phase3_cfg *cfg, + ds4_distributed_layers coordinator_layers, + const official_case *vc, + repeat_result *res) { + memset(res, 0, sizeof(*res)); + res->official_pass = true; + res->official_selected_mismatch_step = -1; + + ds4_engine *dist_engine = NULL; + ds4_session *dist_session = NULL; + ds4_session_payload_file payload = {0}; + ds4_tokens prompt = {0}; + ds4_engine *local_engine = NULL; + ds4_session *ref_session = NULL; + ds4_session *cand_session = NULL; + float *ref_logits = NULL; + float *cand_logits = NULL; + ds4_token_score scores[20]; + char err[256] = {0}; + bool ok = false; + + if (!open_distributed_session(cfg, vc->ctx, coordinator_layers, + &dist_engine, &dist_session, + res->route_summary, sizeof(res->route_summary), + &res->route_hops, &res->output_on_coordinator)) { + snprintf(res->error, sizeof(res->error), "failed to open distributed session"); + goto cleanup; + } + if (!tokenize_official_prompt(dist_engine, vc, &prompt)) { + snprintf(res->error, sizeof(res->error), "failed to tokenize official prompt"); + goto cleanup; + } + if (prompt.len >= vc->ctx) { + snprintf(res->error, sizeof(res->error), "prompt exceeds ctx"); + goto cleanup; + } + if (!stage_distributed_payload(dist_session, &prompt, res, &payload)) goto cleanup; + + ds4_session_free(dist_session); + dist_session = NULL; + ds4_engine_close(dist_engine); + dist_engine = NULL; + + if (!set_process_lock_file("/tmp/ds4-phase3-local.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto cleanup; + } + + ds4_engine_options local_opt = { + .model_path = cfg->model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + }; + if (ds4_engine_open(&local_engine, &local_opt) != 0 || !local_engine) { + snprintf(res->error, sizeof(res->error), "failed to open local engine"); + goto cleanup; + } + if (ds4_session_create(&ref_session, local_engine, vc->ctx) != 0 || !ref_session || + ds4_session_create(&cand_session, local_engine, vc->ctx) != 0 || !cand_session) { + snprintf(res->error, sizeof(res->error), "failed to create local sessions"); + goto cleanup; + } + if (ds4_session_sync(ref_session, &prompt, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "local baseline prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + double t0 = now_sec(); + if (!load_payload_into_session(cand_session, &payload, err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "local payload load failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->load_sec = now_sec() - t0; + + const int vocab = ds4_engine_vocab_size(local_engine); + ref_logits = malloc((size_t)vocab * sizeof(ref_logits[0])); + cand_logits = malloc((size_t)vocab * sizeof(cand_logits[0])); + if (!ref_logits || !cand_logits) { + snprintf(res->error, sizeof(res->error), "out of memory for logits"); + goto cleanup; + } + + for (int step = 0; step < vc->nsteps; step++) { + if (ds4_session_copy_logits(ref_session, ref_logits, vocab) != vocab || + ds4_session_copy_logits(cand_session, cand_logits, vocab) != vocab) { + snprintf(res->error, sizeof(res->error), "failed to copy logits"); + goto cleanup; + } + + parity_metrics cmp = compare_logits(ref_logits, cand_logits, vocab); + parity_summary_observe(&res->parity, &cmp, step); + res->steps_checked = step + 1; + + const int ref_token = ds4_session_argmax(ref_session); + const int cand_token = ds4_session_argmax(cand_session); + if (!token_bytes_equal(local_engine, cand_token, + vc->steps[step].selected, + vc->steps[step].selected_len)) { + if (res->official_selected_mismatch_step < 0) { + res->official_selected_mismatch_step = step; + } + res->official_pass = false; + } + + const int nscore = ds4_session_top_logprobs(cand_session, scores, 20); + for (int i = 0; i < vc->steps[step].ntop; i++) { + bool found = false; + float local_lp = 0.0f; + for (int j = 0; j < nscore; j++) { + if (scores[j].id < 0) continue; + if (token_bytes_equal(local_engine, scores[j].id, + vc->steps[step].top[i].bytes, + vc->steps[step].top[i].len)) { + found = true; + local_lp = scores[j].logprob; + break; + } + } + if (!found) { + res->official_missing_top_count++; + res->official_pass = false; + continue; + } + const float delta = fabsf(local_lp - vc->steps[step].top[i].logprob); + if (delta > res->official_max_logprob_delta) { + res->official_max_logprob_delta = delta; + } + if (delta > 4.0f) res->official_pass = false; + } + + if (step + 1 < vc->nsteps) { + if (ds4_session_eval(ref_session, ref_token, err, sizeof(err)) != 0 || + ds4_session_eval(cand_session, ref_token, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "eval failed after step %d: %s", + step, err[0] ? err : "unknown error"); + goto cleanup; + } + } + (void)cand_token; + } + + res->ok = true; + ok = true; + +cleanup: + free(cand_logits); + free(ref_logits); + ds4_session_free(cand_session); + ds4_session_free(ref_session); + ds4_engine_close(local_engine); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&prompt); + ds4_session_free(dist_session); + ds4_engine_close(dist_engine); + return ok; +} + +static int golden_overlap(const golden_case *tc, const int *cand_top, int n) { + int overlap = 0; + if (n > tc->ntop) n = tc->ntop; + for (int i = 0; i < n; i++) { + if (topk_contains(cand_top, n, tc->top[i].id)) overlap++; + } + return overlap; +} + +static float golden_top20_max_abs(const golden_case *tc, const float *cand_logits) { + float max_abs = 0.0f; + int n = tc->ntop < 20 ? tc->ntop : 20; + for (int i = 0; i < n; i++) { + const int id = tc->top[i].id; + if (id < 0) continue; + const float abs_delta = fabsf(cand_logits[id] - tc->top[i].logit); + if (abs_delta > max_abs) max_abs = abs_delta; + } + return max_abs; +} + +static bool run_golden_repeat(const phase3_cfg *cfg, + ds4_distributed_layers coordinator_layers, + const golden_case *tc, + repeat_result *res) { + memset(res, 0, sizeof(*res)); + res->official_selected_mismatch_step = -1; + res->golden_pass = true; + + ds4_engine *dist_engine = NULL; + ds4_session *dist_session = NULL; + ds4_session_payload_file payload = {0}; + ds4_tokens full_prompt = {0}; + ds4_tokens prefix = {0}; + ds4_engine *local_engine = NULL; + ds4_session *ref_session = NULL; + ds4_session *cand_session = NULL; + float *ref_logits = NULL; + float *cand_logits = NULL; + char err[256] = {0}; + bool ok = false; + + if (!open_distributed_session(cfg, tc->ctx, coordinator_layers, + &dist_engine, &dist_session, + res->route_summary, sizeof(res->route_summary), + &res->route_hops, &res->output_on_coordinator)) { + snprintf(res->error, sizeof(res->error), "failed to open distributed session"); + goto cleanup; + } + if (!tokenize_golden_prompt(dist_engine, tc, &full_prompt, &prefix)) { + snprintf(res->error, sizeof(res->error), "failed to tokenize local golden prompt"); + goto cleanup; + } + if (!stage_distributed_payload(dist_session, &prefix, res, &payload)) goto cleanup; + + ds4_session_free(dist_session); + dist_session = NULL; + ds4_engine_close(dist_engine); + dist_engine = NULL; + + if (!set_process_lock_file("/tmp/ds4-phase3-local.lock", err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "%s", err); + goto cleanup; + } + + ds4_engine_options local_opt = { + .model_path = cfg->model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + }; + if (ds4_engine_open(&local_engine, &local_opt) != 0 || !local_engine) { + snprintf(res->error, sizeof(res->error), "failed to open local engine"); + goto cleanup; + } + if (ds4_session_create(&ref_session, local_engine, tc->ctx) != 0 || !ref_session || + ds4_session_create(&cand_session, local_engine, tc->ctx) != 0 || !cand_session) { + snprintf(res->error, sizeof(res->error), "failed to create local sessions"); + goto cleanup; + } + if (ds4_session_sync(ref_session, &prefix, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "local baseline prefill failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + double t0 = now_sec(); + if (!load_payload_into_session(cand_session, &payload, err, sizeof(err))) { + snprintf(res->error, sizeof(res->error), "local payload load failed: %s", + err[0] ? err : "unknown error"); + goto cleanup; + } + res->load_sec = now_sec() - t0; + + const int vocab = ds4_engine_vocab_size(local_engine); + ref_logits = malloc((size_t)vocab * sizeof(ref_logits[0])); + cand_logits = malloc((size_t)vocab * sizeof(cand_logits[0])); + if (!ref_logits || !cand_logits) { + snprintf(res->error, sizeof(res->error), "out of memory for logits"); + goto cleanup; + } + + for (int step = 0; step <= cfg->greedy_steps; step++) { + if (ds4_session_copy_logits(ref_session, ref_logits, vocab) != vocab || + ds4_session_copy_logits(cand_session, cand_logits, vocab) != vocab) { + snprintf(res->error, sizeof(res->error), "failed to copy logits"); + goto cleanup; + } + + parity_metrics cmp = compare_logits(ref_logits, cand_logits, vocab); + parity_summary_observe(&res->parity, &cmp, step); + res->steps_checked = step + 1; + + if (step == 0) { + int cand_top[64]; + logits_topk(cand_logits, vocab, cand_top, 64); + res->golden_top1 = cand_top[0]; + res->golden_top5_overlap = golden_overlap(tc, cand_top, 5); + res->golden_top20_overlap = golden_overlap(tc, cand_top, 20); + res->golden_top64_overlap = golden_overlap(tc, cand_top, 64); + res->golden_top20_max_abs = golden_top20_max_abs(tc, cand_logits); + res->golden_pass = cand_top[0] == tc->top[0].id && + res->golden_top5_overlap >= 4 && + res->golden_top20_overlap >= 15 && + res->golden_top64_overlap >= 40 && + res->golden_top20_max_abs <= 8.0f; + } + + if (step == cfg->greedy_steps) break; + const int ref_token = ds4_session_argmax(ref_session); + if (ds4_session_eval(ref_session, ref_token, err, sizeof(err)) != 0 || + ds4_session_eval(cand_session, ref_token, err, sizeof(err)) != 0) { + snprintf(res->error, sizeof(res->error), "eval failed after step %d: %s", + step, err[0] ? err : "unknown error"); + goto cleanup; + } + } + + res->ok = true; + ok = true; + +cleanup: + free(cand_logits); + free(ref_logits); + ds4_session_free(cand_session); + ds4_session_free(ref_session); + ds4_engine_close(local_engine); + ds4_session_payload_file_free(&payload); + ds4_tokens_free(&full_prompt); + ds4_session_free(dist_session); + ds4_engine_close(dist_engine); + return ok; +} + +static void summary_observe_repeat(case_summary *sum, const repeat_result *res) { + if (sum->repeats == 0) { + sum->worst_parity = res->parity; + sum->official_pass = res->official_pass; + sum->official_selected_mismatch_step = res->official_selected_mismatch_step; + sum->official_missing_top_count = res->official_missing_top_count; + sum->official_max_logprob_delta = res->official_max_logprob_delta; + sum->golden_pass = res->golden_pass; + sum->golden_top1 = res->golden_top1; + sum->golden_top5_overlap = res->golden_top5_overlap; + sum->golden_top20_overlap = res->golden_top20_overlap; + sum->golden_top64_overlap = res->golden_top64_overlap; + sum->golden_top20_max_abs = res->golden_top20_max_abs; + snprintf(sum->route_summary, sizeof(sum->route_summary), "%s", res->route_summary); + sum->route_hops = res->route_hops; + sum->output_on_coordinator = res->output_on_coordinator; + } else { + if (res->parity.top5_overlap < sum->worst_parity.top5_overlap) { + sum->worst_parity.top5_overlap = res->parity.top5_overlap; + } + if (res->parity.top20_overlap < sum->worst_parity.top20_overlap) { + sum->worst_parity.top20_overlap = res->parity.top20_overlap; + } + if (res->parity.top64_overlap < sum->worst_parity.top64_overlap) { + sum->worst_parity.top64_overlap = res->parity.top64_overlap; + } + if (res->parity.nonfinite > sum->worst_parity.nonfinite) { + sum->worst_parity.nonfinite = res->parity.nonfinite; + } + if (res->parity.rms > sum->worst_parity.rms) { + sum->worst_parity.rms = res->parity.rms; + } + if (res->parity.max_abs > sum->worst_parity.max_abs) { + sum->worst_parity.max_abs = res->parity.max_abs; + } + if (res->parity.top20_max_abs > sum->worst_parity.top20_max_abs) { + sum->worst_parity.top20_max_abs = res->parity.top20_max_abs; + } + if (sum->worst_parity.first_top1_mismatch_step < 0 && + res->parity.first_top1_mismatch_step >= 0) { + sum->worst_parity.first_top1_mismatch_step = res->parity.first_top1_mismatch_step; + sum->worst_parity.top1_ref = res->parity.top1_ref; + sum->worst_parity.top1_cand = res->parity.top1_cand; + sum->worst_parity.first_ref_token = res->parity.first_ref_token; + sum->worst_parity.first_cand_token = res->parity.first_cand_token; + } + sum->official_pass = sum->official_pass && res->official_pass; + if (sum->official_selected_mismatch_step < 0 || + (res->official_selected_mismatch_step >= 0 && + res->official_selected_mismatch_step < sum->official_selected_mismatch_step)) { + if (res->official_selected_mismatch_step >= 0) { + sum->official_selected_mismatch_step = res->official_selected_mismatch_step; + } + } + sum->official_missing_top_count += res->official_missing_top_count; + if (res->official_max_logprob_delta > sum->official_max_logprob_delta) { + sum->official_max_logprob_delta = res->official_max_logprob_delta; + } + sum->golden_pass = sum->golden_pass && res->golden_pass; + if (res->golden_top5_overlap < sum->golden_top5_overlap) { + sum->golden_top5_overlap = res->golden_top5_overlap; + } + if (res->golden_top20_overlap < sum->golden_top20_overlap) { + sum->golden_top20_overlap = res->golden_top20_overlap; + } + if (res->golden_top64_overlap < sum->golden_top64_overlap) { + sum->golden_top64_overlap = res->golden_top64_overlap; + } + if (res->golden_top20_max_abs > sum->golden_top20_max_abs) { + sum->golden_top20_max_abs = res->golden_top20_max_abs; + } + } + if (res->ok) sum->passes++; + sum->repeats++; + if (res->payload_bytes > sum->payload_bytes_max) sum->payload_bytes_max = res->payload_bytes; + if (res->prefill_sec > sum->prefill_sec_max) sum->prefill_sec_max = res->prefill_sec; + if (res->stage_sec > sum->stage_sec_max) sum->stage_sec_max = res->stage_sec; + if (res->load_sec > sum->load_sec_max) sum->load_sec_max = res->load_sec; +} + +static void print_repeat_result(const phase3_cfg *cfg, + const char *case_id, + int ctx, + int repeat_index, + const repeat_result *res) { + printf("{\"suite\":\"%s\",\"case\":\"%s\",\"ctx\":%d,\"repeat\":%d," + "\"ok\":%s,\"route_summary\":\"%s\",\"payload_bytes\":%llu," + "\"prefill_sec\":%.6f,\"stage_sec\":%.6f,\"load_sec\":%.6f," + "\"parity\":{\"envelope\":\"%s\",\"first_top1_mismatch_step\":%d," + "\"top1_ref\":%d,\"top1_cand\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"rms\":%.9g," + "\"max_abs\":%.9g,\"top20_max_abs\":%.9g,\"nonfinite\":%d}," + "\"official\":{\"pass\":%s,\"selected_mismatch_step\":%d," + "\"missing_top_count\":%d,\"max_logprob_delta\":%.9g}," + "\"golden\":{\"pass\":%s,\"top1\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"top20_max_abs\":%.9g}," + "\"error\":\"%s\"}\n", + cfg->suite == PHASE3_SUITE_OFFICIAL ? "official" : "local-golden", + case_id, + ctx, + repeat_index, + res->ok ? "true" : "false", + res->route_summary, + (unsigned long long)res->payload_bytes, + res->prefill_sec, + res->stage_sec, + res->load_sec, + parity_envelope(&res->parity), + res->parity.first_top1_mismatch_step, + res->parity.top1_ref, + res->parity.top1_cand, + res->parity.top5_overlap, + res->parity.top20_overlap, + res->parity.top64_overlap, + res->parity.rms, + res->parity.max_abs, + res->parity.top20_max_abs, + res->parity.nonfinite, + res->official_pass ? "true" : "false", + res->official_selected_mismatch_step, + res->official_missing_top_count, + res->official_max_logprob_delta, + res->golden_pass ? "true" : "false", + res->golden_top1, + res->golden_top5_overlap, + res->golden_top20_overlap, + res->golden_top64_overlap, + res->golden_top20_max_abs, + res->error); +} + +static void print_case_summary(const phase3_cfg *cfg, + const char *case_id, + int ctx, + const case_summary *sum) { + printf("{\"suite\":\"%s\",\"case\":\"%s\",\"ctx\":%d,\"worst_at_%d\":{" + "\"passes\":%d,\"route_summary\":\"%s\",\"payload_bytes_max\":%llu," + "\"prefill_sec_max\":%.6f,\"stage_sec_max\":%.6f,\"load_sec_max\":%.6f," + "\"parity\":{\"envelope\":\"%s\",\"first_top1_mismatch_step\":%d," + "\"top1_ref\":%d,\"top1_cand\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"rms\":%.9g," + "\"max_abs\":%.9g,\"top20_max_abs\":%.9g,\"nonfinite\":%d}," + "\"official\":{\"pass\":%s,\"selected_mismatch_step\":%d," + "\"missing_top_count\":%d,\"max_logprob_delta\":%.9g}," + "\"golden\":{\"pass\":%s,\"top1\":%d,\"top5_overlap\":%d," + "\"top20_overlap\":%d,\"top64_overlap\":%d,\"top20_max_abs\":%.9g}}}\n", + cfg->suite == PHASE3_SUITE_OFFICIAL ? "official" : "local-golden", + case_id, + ctx, + sum->repeats, + sum->passes, + sum->route_summary, + (unsigned long long)sum->payload_bytes_max, + sum->prefill_sec_max, + sum->stage_sec_max, + sum->load_sec_max, + parity_envelope(&sum->worst_parity), + sum->worst_parity.first_top1_mismatch_step, + sum->worst_parity.top1_ref, + sum->worst_parity.top1_cand, + sum->worst_parity.top5_overlap, + sum->worst_parity.top20_overlap, + sum->worst_parity.top64_overlap, + sum->worst_parity.rms, + sum->worst_parity.max_abs, + sum->worst_parity.top20_max_abs, + sum->worst_parity.nonfinite, + sum->official_pass ? "true" : "false", + sum->official_selected_mismatch_step, + sum->official_missing_top_count, + sum->official_max_logprob_delta, + sum->golden_pass ? "true" : "false", + sum->golden_top1, + sum->golden_top5_overlap, + sum->golden_top20_overlap, + sum->golden_top64_overlap, + sum->golden_top20_max_abs); +} + +static void parse_args(phase3_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--suite") && i + 1 < argc) { + const char *suite = argv[++i]; + if (!strcmp(suite, "official")) { + cfg->suite = PHASE3_SUITE_OFFICIAL; + } else if (!strcmp(suite, "local-golden")) { + cfg->suite = PHASE3_SUITE_LOCAL_GOLDEN; + } else { + usage(argv[0]); + } + } else if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--listen-host") && i + 1 < argc) { + cfg->listen_host = argv[++i]; + } else if (!strcmp(argv[i], "--listen-port") && i + 1 < argc) { + cfg->listen_port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--vector-file") && i + 1 < argc) { + cfg->vector_file = argv[++i]; + } else if (!strcmp(argv[i], "--local-golden-file") && i + 1 < argc) { + cfg->local_golden_file = argv[++i]; + } else if (!strcmp(argv[i], "--repeat") && i + 1 < argc) { + cfg->repeat = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx-filter") && i + 1 < argc) { + cfg->ctx_filter = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--greedy-steps") && i + 1 < argc) { + cfg->greedy_steps = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { + cfg->coordinator_layers = argv[++i]; + } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { + cfg->worker_layers = argv[++i]; + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + usage(argv[0]); + } + } +} + +int main(int argc, char **argv) { + phase3_cfg cfg = { + .model_path = NULL, + .listen_host = NULL, + .vector_file = "tests/test-vectors/official.vec", + .local_golden_file = "tests/test-vectors/local-golden.vec", + .coordinator_layers = "0:21", + .worker_layers = "22:output", + .listen_port = 1234, + .repeat = 5, + .ctx_filter = 0, + .greedy_steps = 8, + .prefill_chunk = 256, + .prefill_window = 0, + .activation_bits = 32, + .debug = true, + .suite = PHASE3_SUITE_OFFICIAL, + }; + parse_args(&cfg, argc, argv); + if (!cfg.model_path || !cfg.listen_host || cfg.listen_port <= 0 || cfg.repeat <= 0) { + usage(argv[0]); + } + + struct in_addr addr; + if (inet_pton(AF_INET, cfg.listen_host, &addr) != 1) { + die("listen host must be an IPv4 address reachable from the worker"); + } + + ds4_distributed_layers coordinator_layers = {0}; + if (!parse_layer_spec(cfg.coordinator_layers, &coordinator_layers)) { + die("invalid coordinator layer spec"); + } + + int failures = 0; + if (cfg.suite == PHASE3_SUITE_OFFICIAL) { + FILE *fp = fopen(cfg.vector_file, "rb"); + if (!fp) die_errno("open official vectors"); + official_case vc; + while (read_official_case(fp, &vc)) { + if (!fill_official_case(fp, &vc)) die("parse official vector case"); + if (official_case_disabled(&vc)) continue; + if (cfg.ctx_filter > 0 && vc.ctx != cfg.ctx_filter) continue; + + case_summary sum = {0}; + sum.official_selected_mismatch_step = -1; + for (int i = 0; i < cfg.repeat; i++) { + repeat_result res = {0}; + if (!run_official_repeat(&cfg, coordinator_layers, &vc, &res)) { + print_repeat_result(&cfg, vc.id, vc.ctx, i + 1, &res); + fclose(fp); + return 1; + } + summary_observe_repeat(&sum, &res); + print_repeat_result(&cfg, vc.id, vc.ctx, i + 1, &res); + if (i + 1 < cfg.repeat) sleep(2); + } + print_case_summary(&cfg, vc.id, vc.ctx, &sum); + if (!sum.official_pass || !parity_pass_tolerant(&sum.worst_parity)) failures++; + } + fclose(fp); + } else { + FILE *fp = fopen(cfg.local_golden_file, "rb"); + if (!fp) die_errno("open local golden vectors"); + golden_case tc; + while (read_golden_case(fp, &tc)) { + if (!fill_golden_case(fp, &tc)) die("parse local golden vector case"); + if (cfg.ctx_filter > 0 && tc.ctx != cfg.ctx_filter) continue; + + case_summary sum = {0}; + sum.official_selected_mismatch_step = -1; + for (int i = 0; i < cfg.repeat; i++) { + repeat_result res = {0}; + if (!run_golden_repeat(&cfg, coordinator_layers, &tc, &res)) { + print_repeat_result(&cfg, tc.id, tc.ctx, i + 1, &res); + fclose(fp); + return 1; + } + summary_observe_repeat(&sum, &res); + print_repeat_result(&cfg, tc.id, tc.ctx, i + 1, &res); + if (i + 1 < cfg.repeat) sleep(2); + } + print_case_summary(&cfg, tc.id, tc.ctx, &sum); + if (!sum.golden_pass || !parity_pass_tolerant(&sum.worst_parity)) failures++; + } + fclose(fp); + } + return failures == 0 ? 0 : 1; +} From c05eed4574bf28da846a516f3936768b2256f8e2 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Thu, 4 Jun 2026 22:45:48 +0100 Subject: [PATCH 06/17] refine phase 4 scope --- PLAN.md | 108 ++++++++++++++++----- artifacts/issue-304/decision-log.md | 75 ++++++++++++++ artifacts/issue-304/engine-residency.md | 65 +++++++++++-- artifacts/issue-304/research-notes.md | 5 +- artifacts/issue-304/topology-decoupling.md | 4 +- 5 files changed, 220 insertions(+), 37 deletions(-) diff --git a/PLAN.md b/PLAN.md index 0a3c7a099..df55a92cd 100644 --- a/PLAN.md +++ b/PLAN.md @@ -38,17 +38,19 @@ Source: and its comment thread. ## Remaining unknowns +- To what extent the currently observed route/backend variance would materially hurt realistic benchmarks or user-visible quality once a practical handoff workflow exists. - Whether `CUDA -> Metal` resumed-decode drift is only normal engine/backend implementation variance, or whether it indicates payload/handoff state that would make distributed-prefill-to-local differ from fully local inference on the same decode engine. -- Whether distributed prefill -> merged `DSV4` -> local decode matches the official-vector and local-golden correctness surfaces already used for fully local inference. +- Whether distributed prefill -> merged `DSV4` -> local decode matches the official-vector and local-golden correctness surfaces already used for fully local inference strongly enough to matter in real use, rather than only as a research comparison. - How to let the coordinator participate in distributed prefill while still keeping a full local decode-capable engine resident without exhausting Metal memory budget. - Whether the eventual handoff path should remain a merged `DSV4` checkpoint, move to an in-memory merged payload, or skip the merged payload entirely by streaming worker-owned KV shards back during prefill. ## Implementation direction - Keep the merged `DSV4` handoff path as the current correctness boundary. Phase 2 validated that it can gather distributed shards, stage a payload, load locally, and recover the exact handoff checkpoint. -- Treat mixed-backend resumed-decode drift as a classification problem, not automatically a bug. Isolate it enough to decide whether it is expected engine variance or a handoff-specific defect. -- Require the distributed-prefill-to-local path to match fully local inference on the same decode engine against `tests/test-vectors/official` / `official.vec` and the local golden-vector surface before productizing the workflow. -- Treat coordinator engine residency as a separate productization problem. Phase 2 proved the feature concept by releasing the distributed engine before local decode; the next residency work is about making that handoff practical in one user-visible workflow. +- Treat mixed-backend resumed-decode drift as a risk characterization problem, not automatically a bug and not the current implementation bottleneck. Record it, guard against obvious regressions, and revisit only when practical workflow or benchmark evidence says it matters. +- Use `tests/test-vectors/official` / `official.vec` and the local golden-vector surface as guardrails, not as proofs of end-user equivalence. +- Shift the next implementation focus to practical handoff plumbing: turn the current proof path into a usable workflow that can be benchmarked and exercised realistically. +- Treat coordinator engine residency and practical handoff plumbing as one fused productization problem. Phase 2 proved the feature concept by releasing the distributed engine before local decode; the next work is about making that handoff runnable and benchmarkable in one user-visible workflow. - Defer chunk-by-chunk KV return until after the resumed-decode correctness and residency story are both understood. At this point it is an optimization and UX improvement, not the first proof point. ## Relevant Code Module Map @@ -241,6 +243,20 @@ This change should be run as an iterative research project, not as a straight fe - If a code change adds a new flag, mode, or test, document both the intended command and one known-good invocation in `artifacts/issue-304/runbook.md`. - If a validation result changes the implementation direction, update `artifacts/issue-304/decision-log.md` and the relevant phase notes in this plan. +## Current pivot after Phase 3.5 + +- Phase 3 and Phase 3.5 produced enough evidence to characterize route/backend variance, but not enough to prove product harm. +- Practical next work should therefore focus on making distributed-prefill-to-local-decode usable as an actual workflow that can later be benchmarked on realistic prompts and sessions. +- Deeper variance forensics are deferred unless one of these happens: + - practical handoff plumbing lands and realistic benchmarks show meaningful regressions, + - resumed routes underperform direct generation in user-visible ways, + - CUDA inference changes materially and the route matrix needs to be re-run, + - product design starts depending on resumed routes being treated as equivalent. +- Until then: + - official-vector and local-golden checks remain useful guardrails, + - the existing variance findings remain documented and unresolved, + - but they do not block the next round of handoff/product plumbing work. + ### Phase 0: Baseline and instrumentation Goal: @@ -400,7 +416,7 @@ Work items: - Load the merged `DSV4` payload into that local session. - Decode locally for at least 1-3 tokens. - Compare against continuing distributed decode from the original distributed session and single-node local prefill/decode when feasible. -- Treat this two-session shape as a correctness experiment. Phase 4 owns the decision about whether engine residency can make it practical for user-facing use. +- Treat this two-session shape as a correctness experiment. The fused Phase 4 owns the decision about whether residency plus workflow plumbing can make it practical for user-facing use. Key questions: @@ -412,7 +428,7 @@ Key questions: Exit gate: - The existing payload path can hand off distributed prefill state into a local-only decode session, or a specific blocker is captured with enough detail to choose the next implementation step. -- If the path works only by running two engines or reloading an engine, it must not proceed directly to user-facing implementation; Phase 4 must choose a viable layer-residency design first. +- If the path works only by running two engines or reloading an engine, it must not proceed directly to user-facing implementation; Phase 4 must choose a viable residency-plus-workflow design first. ### Phase 3: Handoff equivalence and drift isolation @@ -462,7 +478,7 @@ Exit gate: - Distributed prefill -> local decode matches fully local inference on the same decode backend for the official-vector prompt set, within the existing official/local-golden acceptance envelope. - Any remaining `CUDA -> Metal` forced-token drift is classified as accepted engine/backend variance, or is localized as a specific handoff defect with a reproduction. -- If official-vector or local-golden checks fail only for distributed handoff, stop before Phase 4 and fix that handoff-specific mismatch. +- If official-vector or local-golden checks fail only for distributed handoff, record that mismatch and carry it forward as an active caveat; Phase 4 may still proceed if the practical workflow questions remain more urgent than deeper variance forensics. ### Phase 3.5: Six-route variance matrix and worst@5 envelope @@ -616,12 +632,13 @@ Exit gate: - Official top-logprob variance and local logit/greedy variance are both available in one consistent result schema. - The evidence can answer, with numbers, whether resumed generation introduces materially more drift than pure `CUDA <-> Metal` variance and whether distributed generation introduces additional drift beyond pure local generation. -### Phase 4: Coordinator residency and workflow viability +### Phase 4: Final-worker residency and workflow viability Goal: -- Why: Phase 2 currently proves the concept by releasing the distributed engine and then opening a full local engine. That is enough for research, but not enough for a practical one-shot coordinator workflow. -- What: choose a viable residency design that lets the coordinator do distributed prefill and then local decode without requiring a research-only two-engine transition. +- Why: Phase 2 currently proves the concept by releasing the distributed engine and then opening a full local engine. That is enough for research, but not enough for a practical one-shot coordinator workflow, and realistic resumed-route benchmarking depends on turning that proof path into a usable workflow. +- What: choose and implement a viable residency-plus-plumbing design that lets the final worker participate in distributed prefill over its later-layer route slice, then continue local decode as the full-resident generation node through a repeatable operator-facing workflow. +- Scope: this phase is not another variance-forensics phase. Phase 3 and Phase 3.5 variance remains an active caveat, but Phase 4 should answer whether a practical, benchmarkable handoff workflow can exist with acceptable residency and operator complexity. Expected artifacts: @@ -631,6 +648,8 @@ Expected artifacts: - Update `artifacts/issue-304/failure-cases.md` with expected failures for missing full-decode layers, invalid layer range transitions, and memory-budget rejection. - Update `artifacts/issue-304/runbook.md` with commands and environment settings used to measure memory. - Update `artifacts/issue-304/research-notes.md` with the residency conclusions and the decision impact on later implementation phases. +- Update `artifacts/issue-304/runbook.md` with the intended developer/operator workflow for the first practical handoff path. +- If a temporary probe flag or harness is added, document it as experimental and keep it out of README until Phase 5 chooses the user-facing API shape. Code touchpoints: @@ -660,33 +679,70 @@ Code touchpoints: Candidate designs to analyze: +- Full-resident final worker with sliced distributed execution: + - Load the full model once on the final worker, but still advertise/execute only the worker-owned later-layer route range for distributed prefill. + - Treat this as the preferred first experiment because it avoids engine unload/reload and avoids two model-weight copies. + - During distributed prefill, call `ds4_session_eval_layer_slice()` only for the worker route slice even though more weights are resident. - Decouple route ownership from weight residency: - - Keep `--layers` as the distributed route slice, but allow the coordinator to map full local decode weights at startup. - - During distributed prefill, call `ds4_session_eval_layer_slice()` only for the coordinator route slice even though more weights are resident. -- Full-resident coordinator with sliced distributed execution: - - Load the full model once on the coordinator, but still advertise/execute only the coordinator-owned distributed layer range for prefill. + - Keep `--layers` as the distributed route slice, but stop forcing final-worker model mapping to that slice when a local-decode residency mode is selected. + - Preserve the coordinator-first route model and coordinator early-layer execution; broader topology flexibility stays deferred. + - Prefer an internal/test-only option or helper path first; defer public CLI naming to Phase 5. +- Dual session over one full-resident engine: + - Use one full-resident final-worker engine with separate distributed-prefill and local-decode sessions. + - This avoids duplicate weights but may duplicate KV/session graph memory; measure it before selecting. + - Keep the distributed session and local decode session distinct unless evidence shows same-session mutation is safer. - Lazy or expandable residency: - Start with route-slice mapping, then expand to full mapping before local decode without closing the engine. - Only keep this path if backend model map spans and cached/preloaded tensors can be expanded safely and fast enough. -- Dual session over one engine: - - Use one full-resident engine with separate distributed-prefill and local-decode sessions. - - This may avoid duplicate weights but still duplicates KV/session graph memory; measure before selecting. - Two engines or reload: - Keep only as a correctness harness or fallback diagnostic, not the final workflow unless the measurements force it. Work items: -- Trace exactly how distributed `--layers` becomes loaded model spans today. -- Measure memory for route-slice engine, full engine, dual-session-over-one-engine, and the current two-engine proof harness where feasible. -- Verify whether a full-resident coordinator can still execute only its distributed slice during prefill by using the existing layer-slice APIs. -- Determine whether session graph allocation assumes only a subset of layers is bound, or whether it can safely hold KV for all layers when the engine has full weights. -- Determine whether output head residency is required on the coordinator for local decode and how `load_output_optional` interacts with that. -- Decide whether the implementation should decouple "route layer range" from "loaded layer range" in `ds4_engine_options` / `ds4_distributed_options`. +1. Re-state the current residency contract in `engine-residency.md`. + - Trace exactly how distributed `--layers` becomes loaded model spans today. + - Record how `load_output_optional`, `N:output`, and `N:42` affect output-head residency. + - Record that merged save/load still requires matching `ctx` and `prefill_cap`. + +2. Build the smallest full-resident-final-worker probe. + - Decouple final-worker route ownership from final-worker loaded spans only for the probe. + - Keep coordinator-first topology and coordinator early-layer execution unchanged. + - Verify the final worker can map full weights and output head while advertising/executing only `N:output` during distributed prefill. + - Verify `ds4_session_eval_layer_slice()` works on a full-resident worker for the route-owned slice. + +3. Measure residency and graph/session memory. + - Compare route-slice final worker, full-resident final worker, dual-session-over-one-engine, and current two-engine proof harness. + - Capture peak process memory, backend allocation behavior, payload bytes, stage/load time, and local decode t/s. + - Record whether dual sessions over one engine duplicate only KV/session graph memory or trigger any unexpected model-weight duplication. + +4. Prototype the first practical workflow with the existing `DSV4` boundary. + - Prefer staged merged `DSV4` first; do not add in-memory or incremental KV return unless the staged path blocks viability. + - Run distributed prefill in the distributed session. + - Transfer or merge the coordinator-owned early-layer KV state into the final worker's full local decode session. + - Prefer the existing merged `DSV4` boundary first if it is the lowest-risk way to prove the workflow. + - Load the handoff state into a local decode session backed by the same full-resident final-worker engine. + - Continue local decode and emit diagnostics for missing full-decode residency, output-head absence, layout mismatch, stale worker state, or memory-budget failure. + +5. Run focused validation, not a new broad variance campaign. + - Re-run the local guardrails that protect payload/session behavior. + - Re-run the Phase 2-style handoff check on the DGX/Mac topology. + - After the implementation is complete, validate both `CUDA -> Metal` and `Metal -> CUDA` routes. + - Re-run a reduced Phase 3.5 sample only if the Phase 4 plumbing changes logits, payload layout, or backend mapping behavior. + - Record any change in official/local behavior as a caveat, but do not require full resumed-route equivalence before proving workflow viability. + +6. Make the Phase 5 decision. + - Choose whether Phase 5 should expose whole-payload handoff, an in-memory payload helper, or an explicit shard merge. + - Record rejected alternatives and the measured reason. + - Do not update README or finalize CLI names until this decision is made. Exit gate: -- A final implementation path exists that does not require loading/unloading the whole engine at handoff time and does not require two full model-weight copies in memory. +- A practical handoff path can run distributed prefill, stage/load the merged payload, and continue local-only decode without closing and reopening the model at handoff time. +- The preferred path uses one full-resident final-worker engine and does not hold two full model-weight copies in memory. +- If the preferred path fails, the smallest acceptable temporary compromise is explicitly recorded with measured memory/runtime costs. - The chosen strategy is captured in `artifacts/issue-304/engine-residency.md` and `artifacts/issue-304/decision-log.md`. +- The runbook contains one known-good Phase 4 command sequence and one memory-measurement procedure. +- Completed implementation validation records both `CUDA -> Metal` and `Metal -> CUDA` route results in the existing issue artifacts. - If no viable strategy is found, stop before advancing and record the smallest code experiment needed to test dynamic or expanded residency. ### Phase 5: Choose API shape and implement the handoff path @@ -1000,6 +1056,6 @@ Work items: - Keep this plan current as decisions are made. - If an unknown unknown changes the direction, add the new fact, the decision it invalidated, and the replacement hypothesis before continuing implementation. -### Initial recommended path +### Current recommended path -Start with Phase 1 and Phase 2 using the existing `DSV4` payload path. This gives the fastest correctness signal with the least new code. Only after that should the work move into API design or pipelined KV return. +Start Phase 4 with the full-resident-final-worker probe and keep the merged `DSV4` payload as the first handoff boundary. Do not move into user-facing API shape, pipelined KV return, or topology decoupling until the final-worker residency workflow is either proven viable or rejected with measured memory/runtime evidence. diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index 6c1d3a872..59d1f1429 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -196,3 +196,78 @@ Why this changes the next steps: - the matching direct-generation backend, - the opposite direct-generation backend, - and the behavior of the stored local-golden fixture itself. + +## 2026-06-04: Pivot next work toward practical handoff plumbing, defer deeper variance forensics + +Decision: + +- Do not spend the next implementation cycle on deeper route/backend variance investigation. +- Move next to practical handoff/product plumbing so the feature can be exercised and later benchmarked in more realistic workflows. +- Keep the existing Phase 3 and Phase 3.5 variance findings as active caveats, not resolved issues. + +Evidence: + +- Phase 3 and Phase 3.5 already produced enough evidence to show that route/backend variance exists and is not reducible to one simple explanation. +- The current workflow is still too research-specific to measure resumed routes convincingly on practical use cases. +- Some of the observed variance may shrink or shift as ongoing CUDA inference work lands, so further forensics now risks chasing a moving target. +- The more actionable next unknown is whether the handoff path can be turned into a usable operator-facing workflow without excessive complexity or unacceptable overhead. + +Why this changes the next steps: + +- Realistic resumed-route benchmarking depends on practical plumbing existing first. +- Official-vector and local-golden checks remain useful guardrails, but they are not enough by themselves to decide product value. +- The next useful deliverable is a runnable handoff workflow that can answer practical engineering questions: + - how awkward the operator flow is, + - where the real latency and memory costs land, + - and whether resumed routes are good enough under actual benchmark workloads. + +Deferred re-entry triggers: + +- Re-open deeper variance investigation when one of these happens: + - practical handoff plumbing lands and realistic benchmarks show meaningful regressions, + - resumed routes underperform direct generation in user-visible ways, + - CUDA inference changes materially and the route matrix should be re-run, + - or product design starts depending on resumed routes being treated as equivalent. + +Operational planning note: + +- The next implementation phase should treat practical handoff plumbing and coordinator residency as one fused problem, not two separate phases. +- In this codebase, a benchmarkable workflow depends directly on how weights stay resident, how `--layers` maps to loaded spans, and whether the coordinator can transition from distributed prefill to local decode without harness-only engine choreography. + +## 2026-06-05: Phase 4 targets final-worker residency, not topology flexibility + +Decision: + +- Keep topology flexibility out of Phase 4. +- Preserve the current coordinator-first route model: + - coordinator prefills earlier layers, + - worker(s) prefill later layers, + - the final worker either owns output/logit generation or sends last-layer hidden state back to the coordinator. +- Focus Phase 4 on the model where the final worker owns output generation and keeps full-model residency, while participating in distributed prefill only for its later-layer route slice. +- Treat the final worker as the local decode owner after distributed prefill. +- Defer the alternative where the final worker sends last-layer output back to the coordinator unless a specific benchmark or deployment need makes it worth the extra transfer. + +Evidence: + +- The current distributed topology requires the coordinator to execute the early prefill slice before worker execution. +- Making the coordinator the full-resident decode node fights that topology and may force wasteful output/head or KV movement. +- The final worker already owns later layers and can own `N:output`; making it full-resident for local decode is a narrower change than decoupling the control-plane coordinator from execution topology. +- The current validated handoff boundary remains merged `DSV4`, but the practical direction should reduce toward sending the coordinator's earlier-layer KV state to the final worker rather than making the coordinator absorb all worker-owned state. + +Why this changes the next steps: + +- Phase 4 should decouple final-worker route ownership from final-worker model residency, not primarily coordinator route ownership from coordinator residency. +- The final worker should be allowed to load all layers and output head, while still advertising/executing only its assigned later-layer route range during distributed prefill. +- The handoff workflow should aim for: + - distributed prefill over the existing route, + - transfer or merge of the coordinator-owned early-layer KV into the final worker's full local decode session, + - local-only decode on the final worker, + - coordinator control/sampling integration only as needed by the chosen Phase 5 API shape. +- This keeps Phase 8 topology decoupling deferred. + +Validation requirement: + +- Once Phase 4/5 implementation work completes, validate both backend directions: + - `CUDA -> Metal` + - `Metal -> CUDA` +- Both directions should record correctness, payload/shard metadata, memory, timing, and failure cases in the existing issue artifacts before the workflow is treated as complete. diff --git a/artifacts/issue-304/engine-residency.md b/artifacts/issue-304/engine-residency.md index fdb7eba97..66a53c101 100644 --- a/artifacts/issue-304/engine-residency.md +++ b/artifacts/issue-304/engine-residency.md @@ -6,8 +6,8 @@ This artifact records the model residency decision for turning the Phase 2 proof - Phase 2 proved distributed prefill can hand off through a merged `DSV4` payload and continue local decode after the distributed engine is released. - That proof path opens a fresh full local engine/session for decode. It is acceptable as a research harness, but not yet a user-facing workflow. -- Phase 3 is now scoped to correctness classification: same-backend distributed handoff parity against fully local inference and the official/local vector gates. -- Phase 4 owns the residency decision. +- Phase 3 and Phase 3.5 completed variance classification well enough to document risk, but not well enough to prove product harm. +- The next phase is a fused residency-plus-practical-workflow phase: the residency decision now exists to support a runnable, benchmarkable handoff workflow rather than as a separate precondition. ## Known Constraints @@ -18,11 +18,62 @@ This artifact records the model residency decision for turning the Phase 2 proof ## Candidate Directions For Phase 4 -- Keep the current two-engine transition for research and measure whether the memory/runtime cost is acceptable only for validation. -- Decouple distributed route ownership from local weight residency so one coordinator engine can own a route slice during prefill but still retain enough state for full local decode. -- Add lazy or staged residency expansion if full upfront residency is too expensive. -- Keep merged `DSV4` as the correctness boundary while improving the user-facing transition mechanics. +- Preferred first experiment: one full-resident final-worker engine with sliced distributed execution. + - `--layers` should still describe each participant's route-owned prefill slice. + - The final worker should map full local-decode weights and output head when the probe mode is enabled. + - Distributed prefill should continue to call `ds4_session_eval_layer_slice()` only for the worker's later-layer route slice. + - Local decode should run from a separate local session over the same full-resident final-worker engine after loading or merging the handoff state. +- Route/residency decoupling: + - Decouple final-worker loaded spans from distributed route ownership only for the Phase 4 probe. + - Keep the coordinator-first topology and coordinator early-layer prefill unchanged. + - Defer public CLI naming until Phase 5 chooses the API shape. +- Dual session over one engine: + - Use the final worker's distributed-prefill session and a local non-distributed session for decode. + - Measure whether this duplicates only KV/session graph memory or creates unexpected model-weight duplication. +- Lazy or staged residency expansion: + - Keep as a fallback if full upfront final-worker residency is too expensive. + - Only pursue it if backend model-map spans, cached tensors, and preloaded expert tables can be expanded safely and cheaply. +- Two engines or engine reload: + - Keep as the Phase 2/3 correctness harness and fallback diagnostic. + - Do not choose it as the practical workflow unless every one-engine option fails and the measured compromise is explicitly accepted. + +## Phase 4 Work Plan + +1. Record the current loading contract. + - Trace `ds4_engine_open()` from `opt->distributed.layers` to `load_layer_start`, `load_layer_end`, `load_output`, and `load_output_optional`. + - Record how `weights_model_map_spans()` and `ds4_gpu_set_model_map_spans()` restrict model mapping. + - Record how output-head ownership differs between `N:output` and `N:42`. + +2. Build a full-resident-final-worker probe. + - Let the final worker keep full local decode residency while advertising/executing only its distributed later-layer route slice. + - Verify `weights_layers_bound()` and `ds4_session_eval_layer_slice()` still accept sliced execution against a full-resident worker engine. + - Keep the first probe internal or harness-only. + +3. Measure memory and timing. + - Compare route-slice final worker, full-resident final worker, dual-session-over-one-engine, and the current two-engine proof harness. + - Capture peak process memory, backend allocation behavior, staged payload bytes, stage/load time, and local decode throughput. + - Keep `ctx` and `prefill_cap` aligned across coordinator and worker before interpreting failures. + +4. Prototype the practical handoff workflow. + - Use staged merged `DSV4` as the first correctness boundary. + - Run distributed prefill in the distributed session. + - Transfer or merge the coordinator-owned early-layer KV state into the final worker's full local decode session. + - Prefer the existing merged `DSV4` boundary first if it is the lowest-risk way to prove the workflow. + - Load the handoff state into the local decode session on the same full-resident final-worker engine. + - Continue local decode and report clear diagnostics for missing full weights, missing output head, layout mismatch, stale worker state, or memory-budget failure. + +5. Decide the Phase 5 API shape. + - If staged `DSV4` is cheap enough and operator flow is acceptable, carry whole-payload handoff forward. + - If temp-file staging is the main cost or workflow problem, consider an in-memory payload helper. + - Defer explicit `DSVL` shard merge and incremental KV return unless measurements show whole-payload handoff is not viable. ## Acceptance Direction -The Phase 4 residency design should not weaken the Phase 3 acceptance envelope: distributed prefill -> local decode must continue to match fully local inference on the same decode backend and pass the official/local vector checks. +The Phase 4 residency design should preserve the existing guardrails without turning them into a false proof of equivalence: + +- do not regress the current official/local vector surfaces, +- keep the known resumed-route variance documented, +- and produce a practical workflow that can later be benchmarked realistically against direct-generation baselines. + +Phase 4 exits successfully when one full-resident final-worker workflow can run distributed prefill and local-only decode without closing/reopening the model at handoff time, or when the measured reason that this is not viable is recorded with the smallest next experiment. +Completed implementation validation must cover both `CUDA -> Metal` and `Metal -> CUDA` routes before the workflow is treated as complete. diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index 97a6af4c0..4ed8b6284 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -11,7 +11,8 @@ This file tracks phase-wise findings for the staged investigation in `PLAN.md`. | Phase 2 | Complete | Distributed prefill -> merged `DSV4` -> fresh local Metal load now validates end-to-end on the DGX/Mac route. Handoff logits and 16-token greedy continuation matched, but forced-token logits still diverged at the first post-load eval step. | | Phase 3 | Complete | Same-backend Phase 3 parity was measured and rejected. The official-vector gate kept passing, but distributed-prefill-to-local decode did not match a fresh fully local Metal baseline closely enough, and the long local-golden continuation failed outright on same-backend parity. | | Phase 3.5 | Complete | The six-route worst@5 matrix is now measured. Official top-logprob variance is route-dependent on short prompts, resumed payload routes remain the weakest parity cells, and the stored local-golden fixture is not anchored purely to the local Metal route. | -| Later phases | Deferred | Engine residency, user-facing workflow, and pipelined KV return stay deferred until the same-backend resumed-decode mismatch is fixed or localized. | +| Phase 4 | Next | The next phase is a fused residency-plus-practical-workflow phase: make the handoff path usable enough to benchmark and operate realistically, while keeping the existing variance findings as active caveats. | +| Later phases | Deferred | Pipelined KV return, topology decoupling, and broader optimization work stay deferred until the practical handoff workflow exists and can be benchmarked realistically. | ## Phase 0: Establish distributed baseline @@ -289,7 +290,7 @@ Phase 2 is no longer blocked on distributed gather, payload staging, or initial ### Implication -Phase 3 did its job: the remaining drift is not just a CUDA-vs-Metal variance story. The handoff path itself differs from a same-backend fresh local Metal decode path after resumed evaluation begins. Later productization phases should stay blocked until that resumed-decode mismatch is localized or fixed. +Phase 3 did its job: the remaining drift is not just a CUDA-vs-Metal variance story. The handoff path itself differs from a same-backend fresh local Metal decode path after resumed evaluation begins. That remains an active caveat, but it no longer blocks the next engineering phase by itself; the next step is to build a practical fused residency-plus-workflow path and then judge the variance again under realistic use and benchmarks. ## Pointers diff --git a/artifacts/issue-304/topology-decoupling.md b/artifacts/issue-304/topology-decoupling.md index bb5db9487..57196446d 100644 --- a/artifacts/issue-304/topology-decoupling.md +++ b/artifacts/issue-304/topology-decoupling.md @@ -4,8 +4,8 @@ This artifact records follow-on topology work after the first correct local-gene ## Current Status -- Topology decoupling is deferred until after the Phase 3 correctness classification and Phase 4 residency decision. -- The current coordinator-first route model remains acceptable for proving the first local-generation handoff unless Phase 4 shows it blocks a viable residency design. +- Topology decoupling is deferred until after the fused Phase 4 residency-plus-practical-workflow work. +- The current coordinator-first route model remains acceptable for the first practical handoff path unless Phase 4 shows it blocks a viable runnable workflow or benchmarkable design. ## Current Constraints From 2ad3829836a6158012fa1d705552077a6bf036a4 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 12:13:52 +0100 Subject: [PATCH 07/17] phase 4 closure --- Makefile | 22 +- artifacts/issue-304/decision-log.md | 70 +++ artifacts/issue-304/engine-residency.md | 50 ++ artifacts/issue-304/failure-cases.md | 32 + artifacts/issue-304/perf-breakdown.md | 42 ++ artifacts/issue-304/research-notes.md | 2 +- artifacts/issue-304/runbook.md | 41 ++ ds4.c | 179 +++++- ds4.h | 21 + ds4_cuda.cu | 14 + ds4_distributed.c | 775 +++++++++++++++++++++++- ds4_distributed.h | 23 + ds4_gpu.h | 2 + ds4_metal.m | 78 +++ tests/issue304_phase4_diagnose.c | 729 ++++++++++++++++++++++ tests/issue304_phase4_handoff.c | 433 +++++++++++++ 16 files changed, 2479 insertions(+), 34 deletions(-) create mode 100644 tests/issue304_phase4_diagnose.c create mode 100644 tests/issue304_phase4_handoff.c diff --git a/Makefile b/Makefile index 95ba33b33..e975ed43a 100644 --- a/Makefile +++ b/Makefile @@ -250,6 +250,26 @@ else $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase35_vectors.o $(CORE_OBJS) $(CUDA_LDLIBS) endif +tests/issue304_phase4_handoff.o: tests/issue304_phase4_handoff.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase4_handoff.c + +tests/issue304_phase4_handoff: tests/issue304_phase4_handoff.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase4_handoff.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase4_handoff.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + +tests/issue304_phase4_diagnose.o: tests/issue304_phase4_diagnose.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase4_diagnose.c + +tests/issue304_phase4_diagnose: tests/issue304_phase4_diagnose.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase4_diagnose.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase4_diagnose.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + issue304-phase0-local: ds4 tests/issue304_phase0_local ./tests/issue304_phase0_local @@ -269,4 +289,4 @@ q4k-dot-test: tests/test_q4k_dot.c ./tests/test_q4k_dot clean: - rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o tests/issue304_phase2_handoff tests/issue304_phase2_handoff.o tests/issue304_phase3_vectors tests/issue304_phase3_vectors.o tests/issue304_phase35_vectors tests/issue304_phase35_vectors.o + rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o tests/issue304_phase2_handoff tests/issue304_phase2_handoff.o tests/issue304_phase3_vectors tests/issue304_phase3_vectors.o tests/issue304_phase35_vectors tests/issue304_phase35_vectors.o tests/issue304_phase4_handoff tests/issue304_phase4_handoff.o diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index 59d1f1429..8a1e8bc4a 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -271,3 +271,73 @@ Validation requirement: - `CUDA -> Metal` - `Metal -> CUDA` - Both directions should record correctness, payload/shard metadata, memory, timing, and failure cases in the existing issue artifacts before the workflow is treated as complete. + +## 2026-06-05: Phase 4 workflow is viable; lifecycle stability remains in scope + +Decision: + +- Treat the core Phase 4 workflow question as answered: the full-resident final-worker handoff design works in both backend directions. +- Keep worker lifecycle stabilization inside Phase 4 scope before calling the workflow complete. +- Keep the startup memory guard enabled by default. + +Evidence: + +- `Metal -> CUDA` produced a passing final-worker handoff run with matching generated tokens. +- `CUDA -> Metal` also produced a passing run with matching generated tokens. +- DGX startup now rejects an unsafe second CUDA residency request before model mapping, preventing the earlier memory-exhaustion freeze class. +- Reused long-lived Metal workers produced inconsistent `CUDA -> Metal` outcomes until the Metal worker process was restarted. + +Implications: + +- The remaining question is no longer whether final-worker handoff can work. +- The remaining question is whether a reused worker process can survive coordinator reconnects and repeated handoff runs without stale state leaking into a later session. +- If the lifecycle bug is not fixed in Phase 4, the runbook must explicitly require fresh worker startup for authoritative `CUDA -> Metal` validation. + +## 2026-06-05: Lifecycle hardening helped, but did not close repeated `CUDA -> Metal` instability + +Decision: + +- Keep the lifecycle fixes landed so far. +- Do not mark Phase 4 lifecycle stabilization complete yet. +- Continue treating repeated `CUDA -> Metal` validation as an open technical risk, not just an operator-runbook problem. + +Evidence: + +- Added hardening: + - unique coordinator session ids, + - epoch-gated stale worker data connections, + - GPU synchronize before session free, + - Metal runtime scratch reset when worker sessions are cleared. +- Those changes removed the simplest stale-session explanation, but repeated `CUDA -> Metal` validation still failed in two ways: + - a fresh-worker run later diverged at generated step `12`, + - the immediate next run on the same worker again diverged from the first generated token. + +Implications: + +- The remaining instability is no longer well described as session-id reuse alone. +- The next investigation should focus on Metal runtime state reuse across worker reconnects and on any remaining distributed/local decode variance that only appears after prior worker activity. + +## 2026-06-05: Close Phase 4 with a fresh-Metal-worker validation rule + +Decision: + +- Mark Phase 4 complete. +- Treat the reused-Metal-worker `CUDA -> Metal` rerun mismatch as a Phase 3.5-class variance caveat, not a Phase 4 workflow blocker. +- Keep the startup memory guard and lifecycle hardening changes. +- Use a fresh Metal worker process for strict `CUDA -> Metal` parity validation in later phases unless and until reuse determinism becomes a specific goal. + +Evidence: + +- `Metal -> CUDA` passed three back-to-back sessions on one reused CUDA worker with identical generated tokens. +- `CUDA -> Metal` also continued to reproduce on a reused Metal worker, but the new diagnostic harness showed two important properties: + - the divergent token streams were coherent text, not gibberish, + - the first mismatch in both sampled reruns was a near-top1 logit flip with full `top5`/`top10` overlap. +- Example shapes: + - mismatch at step `0`: handoff `#`, reference `This` + - mismatch at step `11`: handoff ` (\``, reference ` (` + +Implications: + +- Phase 4 answered its actual question: the final-worker residency and in-process handoff workflow is viable and benchmarkable. +- The remaining reused-Metal-worker drift should not block Phase 5+ work unless those phases require strict repeated token parity on a long-lived Metal worker. +- Research documentation should now describe Phase 4 as complete with an operational validation caveat, not as an open residency/workflow question. diff --git a/artifacts/issue-304/engine-residency.md b/artifacts/issue-304/engine-residency.md index 66a53c101..2ac172031 100644 --- a/artifacts/issue-304/engine-residency.md +++ b/artifacts/issue-304/engine-residency.md @@ -8,6 +8,23 @@ This artifact records the model residency decision for turning the Phase 2 proof - That proof path opens a fresh full local engine/session for decode. It is acceptable as a research harness, but not yet a user-facing workflow. - Phase 3 and Phase 3.5 completed variance classification well enough to document risk, but not well enough to prove product harm. - The next phase is a fused residency-plus-practical-workflow phase: the residency decision now exists to support a runnable, benchmarkable handoff workflow rather than as a separate precondition. +- 2026-06-05 Phase 4 implementation proved a one-worker final-resident handoff path: + - coordinator keeps `0:21`, + - final worker keeps route `22:output`, + - coordinator early-layer KV loads into the existing worker session, + - worker continues local greedy decode in-process. +- Both backend directions have now produced at least one passing run: + - `Metal -> CUDA`: pass on a reused CUDA worker process. + - `CUDA -> Metal`: pass on a fresh Metal worker process. +- Additional repeated validation now refines the remaining risk: + - `Metal -> CUDA` passed three back-to-back sessions on one reused CUDA worker with identical generated tokens. + - `CUDA -> Metal` still produces non-deterministic mismatches on a reused long-lived Metal worker. + - Those `CUDA -> Metal` mismatches are coherent text variations with near-matching logits, not obvious stale-state gibberish or broken handoff state. +- Phase 4 is complete as a workflow/research phase: + - the final-worker handoff design is viable, + - the authoritative validation rule is now “fresh Metal worker for strict `CUDA -> Metal` parity checks,” + - and the reused-Metal-worker drift is carried forward as a Phase 3.5-class variance caveat rather than a Phase 4 blocker. +- A startup memory guard was added for accelerator-backed startup so DGX now rejects a second large residency request before model mapping can exhaust device memory. ## Known Constraints @@ -77,3 +94,36 @@ The Phase 4 residency design should preserve the existing guardrails without tur Phase 4 exits successfully when one full-resident final-worker workflow can run distributed prefill and local-only decode without closing/reopening the model at handoff time, or when the measured reason that this is not viable is recorded with the smallest next experiment. Completed implementation validation must cover both `CUDA -> Metal` and `Metal -> CUDA` routes before the workflow is treated as complete. + +## 2026-06-05 Implementation Notes + +Observed passing runs: + +| Route | Result | Notes | +| --- | --- | --- | +| `Metal -> CUDA` | Pass | Reused CUDA worker remained stable across the handoff and reference passes. | +| `CUDA -> Metal` | Pass | Clean worker restart required for the authoritative passing run. | + +Observed instability: + +| Route | Result | Notes | +| --- | --- | --- | +| `CUDA -> Metal` with reused Metal worker | Unstable | One run diverged at generated step `11`; another diverged from the first generated token. | +| `CUDA -> Metal` after lifecycle hardening | Still unstable | Fresh-worker run later diverged at generated step `12`; a second run on the same worker diverged from the first generated token again. | + +Phase 4 interpretation: + +- The full-resident final-worker design is viable. +- The first handoff implementation is benchmarkable. +- `Metal -> CUDA` reuse looks stable enough for repeated validation. +- `CUDA -> Metal` reused-worker drift remains real, but current evidence places it in the same practical class as the Phase 3.5 near-top1 backend variance caveat: + - coherent token stream, + - top5/top10 sets still match at the first divergent step, + - no evidence of corrupted KV or nonsensical decode output. +- Phase 4 therefore exits as complete with an operational validation rule, not as blocked on strict reused-Metal-worker parity. +- Current hardening in code: + - unique coordinator session ids, + - epoch-gated stale worker data channels, + - GPU synchronize before session free, + - Metal runtime scratch reset when worker sessions are cleared. +- Those changes improved containment, but they are not yet enough to call reused Metal-worker parity stable. diff --git a/artifacts/issue-304/failure-cases.md b/artifacts/issue-304/failure-cases.md index ca19aac27..642bd1cf3 100644 --- a/artifacts/issue-304/failure-cases.md +++ b/artifacts/issue-304/failure-cases.md @@ -7,6 +7,9 @@ This artifact records mismatches that should remain rejected during distributed- - Phase 3 recorded a real same-backend rejection case. - Phase 2 observed `CUDA -> Metal` forced-token logit drift after resumed eval, but that is no longer the main blocker. - The stronger rejection is: distributed-prefill -> merged `DSV4` -> local Metal decode does not stay close enough to a fresh local Metal baseline after resumed evaluation begins. +- Phase 4 added two new failure classes that must stay rejected: + - unsafe second-process accelerator startup when free memory is already below the residency budget, + - reused-worker lifecycle contamination where a later rerun can inherit stale state from an earlier coordinator connection. ## Recorded Rejection Cases @@ -43,6 +46,33 @@ This artifact records mismatches that should remain rejected during distributed- - Golden overlap: `top5=3/5`, `top20=16/20`, `top64=46/64`, `top20_max_abs=5.2168293`. - Why rejected: the stored local-golden vector is not a reliable “pure local Metal canonical” surface for Phase 3.5 route attribution. +- `phase4 DGX startup / second CUDA residency request while stale worker is still live` + - Observed guard rejection: + - free `18.94 GiB` + - request `42.03 GiB` + - reserve `10.14 GiB` + - total `121.69 GiB` + - Why rejected: without an explicit guard this class previously exhausted DGX memory badly enough to freeze the box. + +- `phase4 CUDA -> Metal / reused Metal worker rerun` + - First unstable rerun: first mismatch at generated step `11`. + - Second unstable rerun: first mismatch at generated step `0`; `handoff_first_token=5`, reference `2337`. + - Why rejected: repeated handoff validation on the same long-lived Metal worker process is not trustworthy until reconnect/session cleanup is fixed. + +- `phase4 CUDA -> Metal / lifecycle-hardening follow-up` + - Fresh-worker rerun after session-id, stale-channel, and session-free fixes: first mismatch at generated step `12`. + - Immediate next rerun on the same worker: first mismatch at generated step `0`; `handoff_first_token=5`, reference `2337`. + - Why rejected: the lifecycle fixes improved the original stale-worker symptom, but they did not make repeated reused-worker parity reliable enough to use as a strict acceptance surface. + +## Phase 4 closeout classification + +- The two Phase 4 `CUDA -> Metal` reused-worker rerun failures remain recorded here because they fail strict token-parity expectations. +- They do not block Phase 4 closeout because the diagnostic traces now show: + - coherent decoded text rather than gibberish, + - near-matching logits with full `top5`/`top10` overlap at the first divergent step, + - and no evidence that the final-worker handoff workflow itself is invalid. +- Treat them as the same practical class of backend-sensitive near-top1 variance already documented in Phase 3.5 unless a later phase proves a concrete stale-state or payload-integrity defect. + ## Phase 3 Rejection Criteria A drift case should be recorded here as rejected if it: @@ -71,4 +101,6 @@ Cross-engine forced-logit differences alone are not a rejection case if same-bac - Missing output head when logits are requested. - Worker reconnect before shard fetch. - Stale worker session after route rebuild. +- Stale data-connection thread surviving a coordinator reconnect. +- Metal runtime scratch or command-state reuse across worker reconnects. - Incomplete or stale incremental KV return chunks. diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md index 644486cb9..49c9b428e 100644 --- a/artifacts/issue-304/perf-breakdown.md +++ b/artifacts/issue-304/perf-breakdown.md @@ -1,5 +1,47 @@ # Issue 304 Performance Breakdown +## Phase 4 final-worker handoff timings + +Tool: + +```sh +make tests/issue304_phase4_handoff +``` + +Authoritative 2026-06-05 passing runs: + +| Route | Prefill handoff sec | Prefill ref sec | Shard load sec | Local decode sec | Local tok/s | Distributed decode sec | Distributed tok/s | Result | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- | +| `Metal -> CUDA` | 37.998446 | 38.547497 | 0.431831 | 1.226027 | 13.05 | 0.977782 | 16.36 | Pass | +| `CUDA -> Metal` | 36.136962 | 35.978407 | 0.263383 | 0.522352 | 30.63 | 0.950070 | 16.84 | Pass | + +Additional 2026-06-05 instability notes: + +| Route | Result | Notes | +| --- | --- | --- | +| `CUDA -> Metal` reused Metal worker, run A | Fail | First mismatch at generated step `11`. | +| `CUDA -> Metal` reused Metal worker, run B | Fail | Diverged from the first generated token; `handoff_first_token=5`, reference `2337`. | +| `Metal -> CUDA` reused CUDA worker, repeat set of 3 | Pass | All three runs matched with identical generated tokens. | + +Interpretation: + +- The in-process final-worker handoff is viable in both backend directions. +- The local worker decode can be materially faster than continued distributed decode on the same prompt frontier. +- The remaining performance caveat is operational: strict `CUDA -> Metal` parity checks should restart the Metal worker first. + +`CUDA -> Metal` divergence characterization from `tests/issue304_phase4_diagnose`: + +| Reused-worker run | First mismatch | Sequence character | Top-5 overlap | Top-10 overlap | Notes | +| --- | ---: | --- | ---: | ---: | --- | +| A | `0` | Coherent alternate continuation | `5/5` | `10/10` | Handoff chose `#`; reference chose `This`. | +| B | `11` | Coherent punctuation / formatting variant | `5/5` | `10/10` | Handoff chose ` (\``; reference chose ` (`. | + +Diagnostic interpretation: + +- The observed reused-Metal-worker divergence is not gibberish. +- The first divergent token remains inside the opposite side's top-5/top-10 candidate set. +- This matches the practical shape already seen in Phase 3.5: near-top1 ranking flips on a backend-sensitive frontier. + ## Phase 0 baseline ### Historical local loopback topology diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index 4ed8b6284..b529bd3e7 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -11,7 +11,7 @@ This file tracks phase-wise findings for the staged investigation in `PLAN.md`. | Phase 2 | Complete | Distributed prefill -> merged `DSV4` -> fresh local Metal load now validates end-to-end on the DGX/Mac route. Handoff logits and 16-token greedy continuation matched, but forced-token logits still diverged at the first post-load eval step. | | Phase 3 | Complete | Same-backend Phase 3 parity was measured and rejected. The official-vector gate kept passing, but distributed-prefill-to-local decode did not match a fresh fully local Metal baseline closely enough, and the long local-golden continuation failed outright on same-backend parity. | | Phase 3.5 | Complete | The six-route worst@5 matrix is now measured. Official top-logprob variance is route-dependent on short prompts, resumed payload routes remain the weakest parity cells, and the stored local-golden fixture is not anchored purely to the local Metal route. | -| Phase 4 | Next | The next phase is a fused residency-plus-practical-workflow phase: make the handoff path usable enough to benchmark and operate realistically, while keeping the existing variance findings as active caveats. | +| Phase 4 | Complete | Final-worker full-resident handoff is now proven end to end. Both backend directions work; `Metal -> CUDA` is stable across repeated reused-worker sessions, and `CUDA -> Metal` reused-worker drift is currently classified as a Phase 3.5-style near-top1 variance caveat rather than a workflow blocker. | | Later phases | Deferred | Pipelined KV return, topology decoupling, and broader optimization work stay deferred until the practical handoff workflow exists and can be benchmarked realistically. | ## Phase 0: Establish distributed baseline diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md index 35bc17fa4..35d8bcee5 100644 --- a/artifacts/issue-304/runbook.md +++ b/artifacts/issue-304/runbook.md @@ -1,5 +1,46 @@ # Issue 304 Runbook +## Phase 4 closeout rules + +Phase 4 is complete. Use these rules for ongoing validation and follow-on work: + +- run only one DGX `ds4` worker at a time, +- clear stale DGX workers before starting the opposite route direction, +- treat a fresh Metal worker process as the authoritative `CUDA -> Metal` validation path, +- do not rely on repeated `CUDA -> Metal` reruns against the same long-lived Metal worker process, +- do not treat one successful fresh-worker `CUDA -> Metal` pass as proof that immediate reruns will also match, +- and do treat repeated `Metal -> CUDA` runs on a reused CUDA worker as acceptable coverage, since three back-to-back sessions matched. + +Current startup guard behavior: + +- CUDA startup now rejects a large accelerator residency request before model mapping if free memory is too low. +- Override only for explicit debugging with: + +```sh +DS4_DISABLE_STARTUP_MEMORY_GUARD=1 +``` + +Observed DGX rejection example: + +```text +ds4: cuda startup memory guard rejected model residency request +free 18.94 GiB, request 42.03 GiB, reserve 10.14 GiB, total 121.69 GiB +``` + +Safe Phase 4 route order: + +1. start exactly one worker for the target route +2. run `tests/issue304_phase4_handoff` for pass/fail validation or `tests/issue304_phase4_diagnose` for mismatch characterization +3. stop that worker +4. verify no stale DGX `ds4` remains before starting the next route + +Recommended cleanup checks: + +```sh +ssh dgx-direct 'ps -ef | grep "[d]s4" || true' +ssh dgx-direct 'nvidia-smi --query-compute-apps=pid,process_name,used_gpu_memory --format=csv,noheader,nounits' +``` + ## Phase 0 baseline ### Historical localhost preparation diff --git a/ds4.c b/ds4.c index 7221203e0..13256af51 100644 --- a/ds4.c +++ b/ds4.c @@ -17639,6 +17639,77 @@ const char *ds4_backend_name(ds4_backend backend) { return "unknown"; } +static double ds4_bytes_gib(uint64_t bytes) { + return (double)bytes / 1073741824.0; +} + +static bool ds4_startup_memory_guard_enabled(void) { + const char *env = getenv("DS4_DISABLE_STARTUP_MEMORY_GUARD"); + return !(env && env[0] && strcmp(env, "0") != 0); +} + +static uint64_t ds4_startup_memory_guard_reserve_bytes(ds4_backend backend, + uint64_t total_bytes, + uint64_t request_bytes) { + if (backend == DS4_BACKEND_CUDA) { + uint64_t reserve = total_bytes / 12u; + const uint64_t min_reserve = 8ull * 1073741824ull; + const uint64_t max_reserve = 16ull * 1073741824ull; + if (reserve < min_reserve) reserve = min_reserve; + if (reserve > max_reserve) reserve = max_reserve; + if (request_bytes >= 80ull * 1073741824ull && reserve < 12ull * 1073741824ull) { + reserve = 12ull * 1073741824ull; + } + return reserve; + } + (void)request_bytes; + (void)total_bytes; + return 0; +} + +static bool ds4_startup_memory_guard_check(ds4_backend backend, + const char *what, + uint64_t request_bytes) { +#ifdef DS4_NO_GPU + (void)backend; + (void)what; + (void)request_bytes; + return true; +#else + if (!ds4_startup_memory_guard_enabled() || + request_bytes == 0 || + backend == DS4_BACKEND_CPU) { + return true; + } + + uint64_t free_bytes = 0; + uint64_t total_bytes = 0; + if (ds4_gpu_query_memory(&free_bytes, &total_bytes) == 0 || total_bytes == 0) { + return true; + } + + const uint64_t reserve_bytes = + ds4_startup_memory_guard_reserve_bytes(backend, total_bytes, request_bytes); + if (request_bytes > free_bytes || + free_bytes - request_bytes < reserve_bytes) { + fprintf(stderr, + "ds4: %s startup memory guard rejected %s " + "(free %.2f GiB, request %.2f GiB, reserve %.2f GiB, total %.2f GiB)\n", + ds4_backend_name(backend), + what ? what : "accelerator residency request", + ds4_bytes_gib(free_bytes), + ds4_bytes_gib(request_bytes), + ds4_bytes_gib(reserve_bytes), + ds4_bytes_gib(total_bytes)); + fprintf(stderr, + "ds4: free accelerator memory or reduce the layer slice before starting this process. " + "Set DS4_DISABLE_STARTUP_MEMORY_GUARD=1 to bypass.\n"); + return false; + } + return true; +#endif +} + bool ds4_think_mode_enabled(ds4_think_mode mode) { return mode == DS4_THINK_HIGH || mode == DS4_THINK_MAX; } @@ -19944,8 +20015,13 @@ int ds4_engine_open(ds4_engine **out, const ds4_engine_options *opt) { uint32_t load_layer_end = opt->load_layer_end; bool load_output = opt->load_output; bool load_output_optional = false; + const bool full_resident_worker = + opt->distributed.role == DS4_DISTRIBUTED_WORKER && + getenv("DS4_DIST_WORKER_FULL_RESIDENT") != NULL && + strcmp(getenv("DS4_DIST_WORKER_FULL_RESIDENT"), "0") != 0; if (opt->distributed.role != DS4_DISTRIBUTED_NONE && - opt->distributed.layers.set) + opt->distributed.layers.set && + !full_resident_worker) { load_slice = true; load_layer_start = opt->distributed.layers.start; @@ -20018,6 +20094,8 @@ int ds4_engine_open(ds4_engine **out, const ds4_engine_options *opt) { uint64_t *load_offsets = NULL; uint64_t *load_sizes = NULL; uint32_t load_span_count = 0; + uint64_t startup_model_bytes = 0; + uint64_t load_max_tensor_bytes = e->model.max_tensor_bytes; if (load_slice) { const bool map_output = load_output || (load_output_optional && @@ -20053,9 +20131,11 @@ int ds4_engine_open(ds4_engine **out, const ds4_engine_options *opt) { sizes[i] = spans.v[i].end - spans.v[i].off; span_bytes += sizes[i]; } + startup_model_bytes = span_bytes; load_offsets = offsets; load_sizes = sizes; load_span_count = spans.len; + load_max_tensor_bytes = spans.max_tensor_bytes; fprintf(stderr, "ds4: restricting %s model map to layers %u:%s (%u spans, %.2f GiB tensor span)\n", ds4_backend_name(e->backend), @@ -20063,13 +20143,33 @@ int ds4_engine_open(ds4_engine **out, const ds4_engine_options *opt) { load_end, spans.len, (double)span_bytes / 1073741824.0); - model_map_ok = ds4_gpu_set_model_map_spans(e->model.map, - e->model.size, - load_offsets, - load_sizes, - load_span_count, - spans.max_tensor_bytes); free(spans.v); + } else { + startup_model_bytes = e->model.size > e->model.tensor_data_pos ? + e->model.size - e->model.tensor_data_pos : 0; + } + if (e->mtp_ready) { + const uint64_t mtp_bytes = e->mtp_model.size > e->mtp_model.tensor_data_pos ? + e->mtp_model.size - e->mtp_model.tensor_data_pos : 0; + if (mtp_bytes <= UINT64_MAX - startup_model_bytes) startup_model_bytes += mtp_bytes; + else startup_model_bytes = UINT64_MAX; + } + if (!ds4_startup_memory_guard_check(e->backend, + "model residency request", + startup_model_bytes)) { + free(load_offsets); + free(load_sizes); + ds4_engine_close(e); + *out = NULL; + return 1; + } + if (load_slice) { + model_map_ok = ds4_gpu_set_model_map_spans(e->model.map, + e->model.size, + load_offsets, + load_sizes, + load_span_count, + load_max_tensor_bytes); } else { model_map_ok = ds4_gpu_set_model_map_range(e->model.map, e->model.size, @@ -20302,6 +20402,9 @@ void ds4_session_free(ds4_session *s) { } #ifndef DS4_NO_GPU else { + if (ds4_gpu_synchronize() == 0) { + fprintf(stderr, "ds4: synchronize before session free failed\n"); + } metal_graph_free(&s->graph); } #endif @@ -20340,6 +20443,68 @@ int ds4_session_distributed_route_summary( errlen); } +int ds4_session_distributed_handoff_argmax( + ds4_session *s, + int n_predict, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen) { + if (!s || !s->distributed) { + if (errlen) snprintf(err, errlen, "session is not a distributed coordinator"); + return -1; + } + if (!s->checkpoint_valid) { + if (errlen) snprintf(err, errlen, "distributed handoff requires a valid checkpoint"); + return -1; + } + return ds4_dist_session_handoff_argmax(s->distributed, + s, + n_predict, + tokens_out, + token_cap, + shard_load_sec_out, + decode_sec_out, + err, + errlen); +} + +int ds4_session_distributed_handoff_argmax_trace( + ds4_session *s, + int n_predict, + int *tokens_out, + int token_cap, + float *logits_trace_out, + int logits_trace_cap, + int *logits_trace_steps_out, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen) { + if (!s || !s->distributed) { + if (errlen) snprintf(err, errlen, "session is not a distributed coordinator"); + return -1; + } + if (!s->checkpoint_valid) { + if (errlen) snprintf(err, errlen, "distributed handoff requires a valid checkpoint"); + return -1; + } + return ds4_dist_session_handoff_argmax_trace(s->distributed, + s, + n_predict, + tokens_out, + token_cap, + logits_trace_out, + logits_trace_cap, + logits_trace_steps_out, + shard_load_sec_out, + decode_sec_out, + err, + errlen); +} + int ds4_session_power(ds4_session *s) { if (!s || !s->engine) return 100; return s->engine->power_percent; diff --git a/ds4.h b/ds4.h index 56a487d10..9f94b368c 100644 --- a/ds4.h +++ b/ds4.h @@ -221,6 +221,27 @@ int ds4_session_distributed_route_summary( bool *output_on_coordinator, char *err, size_t errlen); +int ds4_session_distributed_handoff_argmax( + ds4_session *s, + int n_predict, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen); +int ds4_session_distributed_handoff_argmax_trace( + ds4_session *s, + int n_predict, + int *tokens_out, + int token_cap, + float *logits_trace_out, + int logits_trace_cap, + int *logits_trace_steps_out, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen); typedef enum { DS4_SESSION_REWRITE_ERROR = -1, diff --git a/ds4_cuda.cu b/ds4_cuda.cu index 9ac36795d..39254e943 100644 --- a/ds4_cuda.cu +++ b/ds4_cuda.cu @@ -1534,6 +1534,8 @@ extern "C" int ds4_gpu_commit_and_wait_selected_readback(uint64_t event_value, c } extern "C" int ds4_gpu_end_commands(void) { return cuda_ok(cudaDeviceSynchronize(), "end commands"); } extern "C" int ds4_gpu_synchronize(void) { return cuda_ok(cudaDeviceSynchronize(), "synchronize"); } +extern "C" void ds4_gpu_reset_runtime_scratch(void) { +} static int cuda_model_set_host_map(const void *model_map, uint64_t model_size) { if (!model_map || model_size == 0) return 0; @@ -1760,6 +1762,18 @@ extern "C" void ds4_gpu_print_memory_report(const char *label) { label ? label : "", (double)free_b / 1048576.0, (double)total_b / 1048576.0); } +extern "C" int ds4_gpu_query_memory(uint64_t *free_bytes, uint64_t *total_bytes) { + size_t free_b = 0, total_b = 0; + cudaError_t err = cudaMemGetInfo(&free_b, &total_b); + if (err != cudaSuccess) { + (void)cudaGetLastError(); + return 0; + } + if (free_bytes) *free_bytes = (uint64_t)free_b; + if (total_bytes) *total_bytes = (uint64_t)total_b; + return 1; +} + extern "C" void ds4_gpu_set_quality(bool quality) { g_quality_mode = quality ? 1 : 0; if (g_cublas_ready) { diff --git a/ds4_distributed.c b/ds4_distributed.c index f6cceac19..c6c98ebfe 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -14,6 +14,7 @@ */ #include "ds4_distributed.h" +#include "ds4_gpu.h" #include #include @@ -51,6 +52,8 @@ #define DS4_DIST_MSG_SNAPSHOT_CHUNK 7u #define DS4_DIST_MSG_SNAPSHOT_DONE 8u #define DS4_DIST_MSG_SNAPSHOT_LOAD_BEGIN 9u +#define DS4_DIST_MSG_LOCAL_GENERATE_REQ 10u +#define DS4_DIST_MSG_LOCAL_GENERATE_RES 11u #define DS4_DIST_MAX_MODEL_NAME 127u #define DS4_DIST_WORK_F_INPUT_HC 0x00000001u #define DS4_DIST_WORK_F_OUTPUT_LOGITS 0x00000002u @@ -195,6 +198,34 @@ typedef struct { uint32_t message_bytes; } ds4_dist_snapshot_done_fixed; +typedef struct { + uint32_t model_id; + uint32_t session_hi; + uint32_t session_lo; + uint32_t request_hi; + uint32_t request_lo; + uint32_t token_hash_hi; + uint32_t token_hash_lo; + uint32_t n_predict; + uint32_t logits_bytes; +} ds4_dist_local_generate_req_fixed; + +typedef struct { + uint32_t model_id; + uint32_t session_hi; + uint32_t session_lo; + uint32_t request_hi; + uint32_t request_lo; + uint32_t token_hash_hi; + uint32_t token_hash_lo; + uint32_t generated_count; + uint32_t decode_usec; + uint32_t status; + uint32_t token_bytes; + uint32_t logits_bytes; + uint32_t message_bytes; +} ds4_dist_local_generate_res_fixed; + /* ========================================================================= * Runtime State * ========================================================================= @@ -273,6 +304,8 @@ typedef struct { int listen_fd; pthread_mutex_t mu; ds4_dist_worker_session *sessions; + uint64_t connection_epoch; + bool control_connected; } ds4_dist_worker_state; typedef struct ds4_dist_worker_upstream ds4_dist_worker_upstream; @@ -305,6 +338,7 @@ typedef struct ds4_dist_worker_forwarder { struct ds4_dist_worker_upstream { ds4_dist_worker_state *state; int fd; + uint64_t epoch; pthread_mutex_t write_mu; pthread_mutex_t forward_mu; ds4_dist_worker_forwarder *forwarders; @@ -334,6 +368,7 @@ typedef struct { typedef struct { ds4_dist_worker_state *state; int fd; + uint64_t epoch; char peer_host[NI_MAXHOST]; char peer_port[NI_MAXSERV]; } ds4_dist_data_client_ctx; @@ -504,10 +539,15 @@ static int dist_worker_handle_snapshot_load( ds4_dist_worker_state *state, ds4_dist_worker_upstream *upstream, uint32_t bytes); +static int dist_worker_handle_local_generate( + ds4_dist_worker_state *state, + ds4_dist_worker_upstream *upstream, + uint32_t bytes); static void dist_worker_upstream_init( ds4_dist_worker_upstream *upstream, ds4_dist_worker_state *state, - int fd); + int fd, + uint64_t epoch); static void dist_worker_upstream_destroy(ds4_dist_worker_upstream *upstream); static int dist_worker_upstream_send_work_error( ds4_dist_worker_upstream *upstream, @@ -539,6 +579,11 @@ static const char *dist_role_name(ds4_distributed_role role) { return "unknown"; } +static bool dist_worker_full_resident_enabled(void) { + const char *env = getenv("DS4_DIST_WORKER_FULL_RESIDENT"); + return env && env[0] && strcmp(env, "0") != 0; +} + static void dist_sleep_reconnect(void) { sleep(1); } @@ -1706,6 +1751,62 @@ static void dist_snapshot_done_from_wire(ds4_dist_snapshot_done_fixed *s) { s->message_bytes = ntohl(s->message_bytes); } +static void dist_local_generate_req_to_wire(ds4_dist_local_generate_req_fixed *r) { + r->model_id = htonl(r->model_id); + r->session_hi = htonl(r->session_hi); + r->session_lo = htonl(r->session_lo); + r->request_hi = htonl(r->request_hi); + r->request_lo = htonl(r->request_lo); + r->token_hash_hi = htonl(r->token_hash_hi); + r->token_hash_lo = htonl(r->token_hash_lo); + r->n_predict = htonl(r->n_predict); + r->logits_bytes = htonl(r->logits_bytes); +} + +static void dist_local_generate_req_from_wire(ds4_dist_local_generate_req_fixed *r) { + r->model_id = ntohl(r->model_id); + r->session_hi = ntohl(r->session_hi); + r->session_lo = ntohl(r->session_lo); + r->request_hi = ntohl(r->request_hi); + r->request_lo = ntohl(r->request_lo); + r->token_hash_hi = ntohl(r->token_hash_hi); + r->token_hash_lo = ntohl(r->token_hash_lo); + r->n_predict = ntohl(r->n_predict); + r->logits_bytes = ntohl(r->logits_bytes); +} + +static void dist_local_generate_res_to_wire(ds4_dist_local_generate_res_fixed *r) { + r->model_id = htonl(r->model_id); + r->session_hi = htonl(r->session_hi); + r->session_lo = htonl(r->session_lo); + r->request_hi = htonl(r->request_hi); + r->request_lo = htonl(r->request_lo); + r->token_hash_hi = htonl(r->token_hash_hi); + r->token_hash_lo = htonl(r->token_hash_lo); + r->generated_count = htonl(r->generated_count); + r->decode_usec = htonl(r->decode_usec); + r->status = htonl(r->status); + r->token_bytes = htonl(r->token_bytes); + r->logits_bytes = htonl(r->logits_bytes); + r->message_bytes = htonl(r->message_bytes); +} + +static void dist_local_generate_res_from_wire(ds4_dist_local_generate_res_fixed *r) { + r->model_id = ntohl(r->model_id); + r->session_hi = ntohl(r->session_hi); + r->session_lo = ntohl(r->session_lo); + r->request_hi = ntohl(r->request_hi); + r->request_lo = ntohl(r->request_lo); + r->token_hash_hi = ntohl(r->token_hash_hi); + r->token_hash_lo = ntohl(r->token_hash_lo); + r->generated_count = ntohl(r->generated_count); + r->decode_usec = ntohl(r->decode_usec); + r->status = ntohl(r->status); + r->token_bytes = ntohl(r->token_bytes); + r->logits_bytes = ntohl(r->logits_bytes); + r->message_bytes = ntohl(r->message_bytes); +} + static void dist_telemetry_to_wire(ds4_dist_telemetry_fixed *t) { t->layer_start = htonl(t->layer_start); t->layer_end = htonl(t->layer_end); @@ -4362,10 +4463,21 @@ static void *dist_coordinator_accept_main(void *arg) { } static uint64_t dist_make_session_id(const void *ptr) { - uint64_t id = ((uint64_t)(uint32_t)time(NULL) << 32) ^ (uint64_t)getpid(); - id ^= ((uint64_t)(uintptr_t)ptr << 17) ^ (uint64_t)(uintptr_t)ptr; - id ^= (uint64_t)clock(); - return id ? id : 1u; + static pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; + static uint64_t next_id = 0; + + pthread_mutex_lock(&mu); + if (next_id == 0) { + uint64_t seed = ((uint64_t)(uint32_t)time(NULL) << 32) ^ + (uint64_t)(uint32_t)getpid(); + seed ^= ((uint64_t)(uintptr_t)ptr << 17) ^ (uint64_t)(uintptr_t)ptr; + seed ^= (uint64_t)clock(); + next_id = seed ? seed : 1u; + } + uint64_t id = next_id++; + if (next_id == 0) next_id = 1u; + pthread_mutex_unlock(&mu); + return id; } static int dist_session_ensure_route(ds4_dist_session *d, char *err, size_t errlen) { @@ -4558,6 +4670,174 @@ static int dist_read_snapshot_done_frame( return 0; } +static int dist_local_generate_remote( + ds4_dist_session *d, + const ds4_dist_route_entry *entry, + uint64_t token_hash, + const float *logits, + int n_predict, + int *tokens_out, + int token_cap, + float *logits_trace_out, + int logits_trace_cap, + int *logits_trace_steps_out, + double *decode_sec_out, + char *err, + size_t errlen) { + if (decode_sec_out) *decode_sec_out = 0.0; + if (logits_trace_steps_out) *logits_trace_steps_out = 0; + if (!d || !entry || !logits || n_predict < 0 || token_cap < n_predict) { + if (errlen) snprintf(err, errlen, "invalid distributed local generate request"); + return -1; + } + + const uint32_t vocab = (uint32_t)ds4_engine_vocab_size(d->state.engine); + const uint32_t logits_bytes = (uint32_t)((uint64_t)vocab * sizeof(float)); + const uint64_t frame_bytes64 = + sizeof(ds4_dist_local_generate_req_fixed) + (uint64_t)logits_bytes; + if (frame_bytes64 > UINT32_MAX) { + if (errlen) snprintf(err, errlen, "distributed local generate frame is too large"); + return -1; + } + + int fd = dist_connect_endpoint(entry->host, (int)entry->port, err, errlen); + if (fd < 0) return -1; + + uint64_t request_id = d->request_id++; + ds4_dist_local_generate_req_fixed req; + memset(&req, 0, sizeof(req)); + req.model_id = d->state.model_id; + dist_u64_to_halves(d->session_id, &req.session_hi, &req.session_lo); + dist_u64_to_halves(request_id, &req.request_hi, &req.request_lo); + dist_u64_to_halves(token_hash, &req.token_hash_hi, &req.token_hash_lo); + req.n_predict = (uint32_t)n_predict; + req.logits_bytes = logits_bytes; + ds4_dist_local_generate_req_fixed wire = req; + dist_local_generate_req_to_wire(&wire); + + int rc = -1; + if (dist_write_frame_header(fd, DS4_DIST_MSG_LOCAL_GENERATE_REQ, + (uint32_t)frame_bytes64) != 0 || + dist_write_full(fd, &wire, sizeof(wire)) != 0 || + dist_write_full(fd, logits, logits_bytes) != 0) { + if (errlen) snprintf(err, errlen, "failed to send distributed local generate request"); + goto cleanup; + } + + uint32_t type = 0, bytes = 0; + if (dist_read_frame_header(fd, &type, &bytes, err, errlen) <= 0) { + if (errlen && !err[0]) snprintf(err, errlen, "worker closed before local generate response"); + goto cleanup; + } + if (type != DS4_DIST_MSG_LOCAL_GENERATE_RES || + bytes < sizeof(ds4_dist_local_generate_res_fixed)) { + dist_discard_bytes(fd, bytes); + if (errlen) snprintf(err, errlen, "worker returned invalid local generate frame"); + goto cleanup; + } + + ds4_dist_local_generate_res_fixed res; + if (dist_read_full(fd, &res, sizeof(res)) <= 0) { + if (errlen) snprintf(err, errlen, "failed to read local generate response"); + goto cleanup; + } + dist_local_generate_res_from_wire(&res); + uint32_t body = bytes - (uint32_t)sizeof(res); + if (res.model_id != d->state.model_id || + dist_u64_from_halves(res.session_hi, res.session_lo) != d->session_id || + dist_u64_from_halves(res.request_hi, res.request_lo) != request_id || + res.token_bytes > body || + res.logits_bytes > body - res.token_bytes || + res.message_bytes > body - res.token_bytes - res.logits_bytes) { + dist_discard_bytes(fd, body); + if (errlen) snprintf(err, errlen, "invalid distributed local generate response"); + goto cleanup; + } + + if (res.status != 0) { + char msg[256] = {0}; + if (res.token_bytes != 0) { + dist_discard_bytes(fd, res.token_bytes); + body -= res.token_bytes; + } + if (res.logits_bytes != 0) { + if (dist_discard_bytes(fd, res.logits_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to discard local generate logits"); + goto cleanup; + } + body -= res.logits_bytes; + } + if (res.message_bytes != 0) { + uint32_t copy = res.message_bytes < sizeof(msg) ? + res.message_bytes : (uint32_t)sizeof(msg) - 1u; + if (copy != 0 && dist_read_full(fd, msg, copy) <= 0) { + if (errlen) snprintf(err, errlen, "failed to read local generate error"); + goto cleanup; + } + msg[copy] = '\0'; + if (res.message_bytes > copy && + dist_discard_bytes(fd, res.message_bytes - copy) <= 0) { + if (errlen) snprintf(err, errlen, "failed to discard local generate error"); + goto cleanup; + } + body -= res.message_bytes; + } + if (body != 0) dist_discard_bytes(fd, body); + if (errlen) snprintf(err, errlen, "%s", + msg[0] ? msg : "distributed local generate failed"); + goto cleanup; + } + + if (res.generated_count > (uint32_t)n_predict || + res.generated_count > (uint32_t)token_cap || + res.token_bytes != res.generated_count * sizeof(uint32_t) || + res.message_bytes != 0) { + dist_discard_bytes(fd, body); + if (errlen) snprintf(err, errlen, "distributed local generate returned invalid token payload"); + goto cleanup; + } + const uint32_t expect_logits_bytes = + (uint32_t)((uint64_t)res.generated_count * (uint64_t)vocab * sizeof(float)); + if (res.logits_bytes != expect_logits_bytes) { + dist_discard_bytes(fd, body); + if (errlen) snprintf(err, errlen, "distributed local generate returned invalid logits payload"); + goto cleanup; + } + for (uint32_t i = 0; i < res.generated_count; i++) { + uint32_t wire_token = 0; + if (dist_read_full(fd, &wire_token, sizeof(wire_token)) <= 0) { + if (errlen) snprintf(err, errlen, "failed to read generated token"); + goto cleanup; + } + tokens_out[i] = (int)ntohl(wire_token); + } + body -= res.token_bytes; + if (res.logits_bytes != 0) { + const int logits_trace_values = (int)((uint64_t)res.generated_count * (uint64_t)vocab); + if (!logits_trace_out || logits_trace_cap < logits_trace_values) { + if (dist_discard_bytes(fd, res.logits_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to discard local generate logits"); + goto cleanup; + } + } else if (dist_read_full(fd, logits_trace_out, res.logits_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to read local generate logits"); + goto cleanup; + } + body -= res.logits_bytes; + if (logits_trace_steps_out) *logits_trace_steps_out = (int)res.generated_count; + } + if (body != 0 && dist_discard_bytes(fd, body) <= 0) { + if (errlen) snprintf(err, errlen, "failed to discard trailing local generate bytes"); + goto cleanup; + } + if (decode_sec_out) *decode_sec_out = (double)res.decode_usec / 1000000.0; + rc = (int)res.generated_count; + +cleanup: + close(fd); + return rc; +} + static int dist_receive_snapshot_chunks_to_file( int fd, uint64_t request_id, @@ -5143,6 +5423,8 @@ static int dist_prepare_shard_from_session_payload( static int dist_load_remote_shard_from_payload( ds4_dist_session *d, const ds4_dist_route_entry *entry, + uint32_t layer_start, + uint32_t layer_end, const int *tokens, uint32_t token_count, uint64_t token_hash, @@ -5161,8 +5443,8 @@ static int dist_load_remote_shard_from_payload( dist_u64_to_halves(request_id, &begin.request_hi, &begin.request_lo); dist_u64_to_halves(token_hash, &begin.token_hash_hi, &begin.token_hash_lo); begin.token_count = token_count; - begin.layer_start = entry->layer_start; - begin.layer_end = entry->layer_end; + begin.layer_start = layer_start; + begin.layer_end = layer_end; dist_u64_to_halves(payload_bytes, &begin.payload_hi, &begin.payload_lo); begin.token_bytes = token_count * sizeof(uint32_t); @@ -5461,6 +5743,7 @@ int ds4_dist_session_load_payload( } } else { if (dist_load_remote_shard_from_payload(d, entry, + layer_start, layer_end, tokens_arg, layout.token_count, token_hash, tmp, shard_bytes, @@ -5489,6 +5772,163 @@ int ds4_dist_session_load_payload( return rc; } +static int dist_session_handoff_argmax_trace( + ds4_dist_session *d, + ds4_session *owner, + int n_predict, + int *tokens_out, + int token_cap, + float *logits_trace_out, + int logits_trace_cap, + int *logits_trace_steps_out, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen) { + if (shard_load_sec_out) *shard_load_sec_out = 0.0; + if (decode_sec_out) *decode_sec_out = 0.0; + if (!d || !owner || n_predict < 0 || token_cap < n_predict) { + if (errlen) snprintf(err, errlen, "invalid distributed handoff request"); + return -1; + } + if (dist_session_ensure_route(d, err, errlen) != 0) return -1; + if (dist_kv_route_validate(d, err, errlen) != 0) return -1; + if (d->plan.count != 1) { + if (errlen) snprintf(err, errlen, "distributed handoff currently requires exactly one worker"); + return -1; + } + const ds4_dist_route_entry *entry = &d->plan.entry[d->plan.count - 1u]; + if ((entry->flags & DS4_DIST_ROUTE_F_OUTPUT_LOGITS) == 0u) { + if (errlen) snprintf(err, errlen, "distributed handoff requires worker-owned output head"); + return -1; + } + + const ds4_tokens *timeline = ds4_session_tokens(owner); + if (!timeline || timeline->len < 0 || (uint64_t)timeline->len > UINT32_MAX) { + if (errlen) snprintf(err, errlen, "distributed handoff requires a valid token timeline"); + return -1; + } + const uint64_t token_hash = dist_token_hash_prefix(timeline->v, (uint32_t)timeline->len); + + FILE *tmp = dist_tmpfile_or_err("dist-handoff-local", err, errlen); + if (!tmp) return -1; + int rc = -1; + uint64_t shard_bytes = 0; + if (ds4_session_save_layer_payload(owner, + tmp, + d->state.local_start, + d->state.local_end, + err, + errlen) != 0) { + fclose(tmp); + return -1; + } + if (dist_measure_file(tmp, &shard_bytes, "distributed handoff shard", err, errlen) != 0 || + dist_rewind_file(tmp, "distributed handoff shard", err, errlen) != 0) { + fclose(tmp); + return -1; + } + + const double load_t0 = dist_now_sec(); + if (dist_load_remote_shard_from_payload(d, + entry, + d->state.local_start, + d->state.local_end, + timeline->v, + (uint32_t)timeline->len, + token_hash, + tmp, + shard_bytes, + err, + errlen) != 0) { + fclose(tmp); + return -1; + } + const double load_t1 = dist_now_sec(); + fclose(tmp); + + const int vocab = ds4_engine_vocab_size(d->state.engine); + float *logits = malloc((size_t)vocab * sizeof(logits[0])); + if (!logits) { + if (errlen) snprintf(err, errlen, "out of memory copying handoff logits"); + return -1; + } + if (ds4_session_copy_logits(owner, logits, vocab) != vocab) { + free(logits); + if (errlen) snprintf(err, errlen, "failed to copy handoff logits"); + return -1; + } + rc = dist_local_generate_remote(d, + entry, + token_hash, + logits, + n_predict, + tokens_out, + token_cap, + logits_trace_out, + logits_trace_cap, + logits_trace_steps_out, + decode_sec_out, + err, + errlen); + free(logits); + if (rc >= 0 && shard_load_sec_out) { + *shard_load_sec_out = load_t1 - load_t0; + } + return rc; +} + +int ds4_dist_session_handoff_argmax( + ds4_dist_session *d, + ds4_session *owner, + int n_predict, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen) { + return dist_session_handoff_argmax_trace(d, + owner, + n_predict, + tokens_out, + token_cap, + NULL, + 0, + NULL, + shard_load_sec_out, + decode_sec_out, + err, + errlen); +} + +int ds4_dist_session_handoff_argmax_trace( + ds4_dist_session *d, + ds4_session *owner, + int n_predict, + int *tokens_out, + int token_cap, + float *logits_trace_out, + int logits_trace_cap, + int *logits_trace_steps_out, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen) { + return dist_session_handoff_argmax_trace(d, + owner, + n_predict, + tokens_out, + token_cap, + logits_trace_out, + logits_trace_cap, + logits_trace_steps_out, + shard_load_sec_out, + decode_sec_out, + err, + errlen); +} + /* ========================================================================= * Coordinator Session API * ========================================================================= @@ -5896,9 +6336,9 @@ static int dist_run_coordinator(ds4_engine *engine, const ds4_dist_options *opt, * Worker Control Loop And Result Frames * ========================================================================= */ -static int dist_worker_read_loop(ds4_dist_worker_state *state, int fd) { +static int dist_worker_read_loop(ds4_dist_worker_state *state, int fd, uint64_t epoch) { ds4_dist_worker_upstream upstream; - dist_worker_upstream_init(&upstream, state, fd); + dist_worker_upstream_init(&upstream, state, fd, epoch); int loop_rc = 0; for (;;) { @@ -5949,6 +6389,14 @@ static int dist_worker_read_loop(ds4_dist_worker_state *state, int fd) { } continue; } + if (type == DS4_DIST_MSG_LOCAL_GENERATE_REQ) { + rc = dist_worker_handle_local_generate(state, &upstream, bytes); + if (rc <= 0) { + loop_rc = rc == 0 ? 0 : 1; + break; + } + continue; + } rc = dist_discard_bytes(fd, bytes); if (rc <= 0) { loop_rc = rc == 0 ? 0 : 1; @@ -6104,6 +6552,67 @@ static int dist_send_snapshot_done(int fd, uint64_t request_id, uint32_t status, return 1; } +static int dist_send_local_generate_response( + int fd, + uint64_t session_id, + uint64_t request_id, + uint32_t model_id, + uint64_t token_hash, + const int *tokens, + uint32_t generated_count, + const float *logits_trace, + uint32_t logits_bytes, + uint32_t decode_usec, + uint32_t status, + const char *msg) { + if (!msg) msg = ""; + size_t len = strlen(msg); + if (len > UINT32_MAX) len = UINT32_MAX; + uint64_t token_bytes64 = (uint64_t)generated_count * sizeof(uint32_t); + if (token_bytes64 > UINT32_MAX) return -1; + uint32_t token_bytes = status == 0 ? (uint32_t)token_bytes64 : 0u; + if (status != 0) { + generated_count = 0; + logits_bytes = 0; + } + + ds4_dist_local_generate_res_fixed res; + memset(&res, 0, sizeof(res)); + res.model_id = model_id; + dist_u64_to_halves(session_id, &res.session_hi, &res.session_lo); + dist_u64_to_halves(request_id, &res.request_hi, &res.request_lo); + dist_u64_to_halves(token_hash, &res.token_hash_hi, &res.token_hash_lo); + res.generated_count = generated_count; + res.decode_usec = decode_usec; + res.status = status; + res.token_bytes = token_bytes; + res.logits_bytes = logits_bytes; + res.message_bytes = status == 0 ? 0u : (uint32_t)len; + + uint64_t frame_bytes64 = sizeof(res) + token_bytes + logits_bytes + res.message_bytes; + if (frame_bytes64 > UINT32_MAX) return -1; + ds4_dist_local_generate_res_fixed wire = res; + dist_local_generate_res_to_wire(&wire); + if (dist_write_frame_header(fd, DS4_DIST_MSG_LOCAL_GENERATE_RES, + (uint32_t)frame_bytes64) != 0 || + dist_write_full(fd, &wire, sizeof(wire)) != 0) { + return -1; + } + if (status == 0) { + for (uint32_t i = 0; i < generated_count; i++) { + uint32_t t = htonl((uint32_t)tokens[i]); + if (dist_write_full(fd, &t, sizeof(t)) != 0) return -1; + } + if (logits_bytes != 0 && + dist_write_full(fd, logits_trace, logits_bytes) != 0) { + return -1; + } + } else if (len != 0 && dist_write_full(fd, msg, len) != 0) { + return -1; + } + return 1; +} + static int dist_send_snapshot_file_chunks(int fd, uint64_t request_id, FILE *fp, uint64_t bytes) { uint8_t *buf = malloc(DS4_DIST_SNAPSHOT_CHUNK_BYTES); if (!buf) return -1; @@ -6437,14 +6946,43 @@ static int dist_worker_upstream_send_work_error( static void dist_worker_upstream_init( ds4_dist_worker_upstream *upstream, ds4_dist_worker_state *state, - int fd) { + int fd, + uint64_t epoch) { memset(upstream, 0, sizeof(*upstream)); upstream->state = state; upstream->fd = fd; + upstream->epoch = epoch; pthread_mutex_init(&upstream->write_mu, NULL); pthread_mutex_init(&upstream->forward_mu, NULL); } +static uint64_t dist_worker_control_connect(ds4_dist_worker_state *state) { + pthread_mutex_lock(&state->mu); + state->connection_epoch++; + if (state->connection_epoch == 0) state->connection_epoch = 1u; + state->control_connected = true; + const uint64_t epoch = state->connection_epoch; + pthread_mutex_unlock(&state->mu); + return epoch; +} + +static void dist_worker_control_disconnect(ds4_dist_worker_state *state, uint64_t epoch) { + pthread_mutex_lock(&state->mu); + if (state->control_connected && state->connection_epoch == epoch) { + state->control_connected = false; + state->connection_epoch++; + if (state->connection_epoch == 0) state->connection_epoch = 1u; + } + pthread_mutex_unlock(&state->mu); +} + +static bool dist_worker_epoch_is_current(ds4_dist_worker_state *state, uint64_t epoch) { + pthread_mutex_lock(&state->mu); + const bool ok = state->control_connected && state->connection_epoch == epoch; + pthread_mutex_unlock(&state->mu); + return ok; +} + static bool dist_worker_forwarder_enqueue_request( ds4_dist_worker_forwarder *forwarder, uint64_t request_id, @@ -6972,6 +7510,7 @@ static uint32_t dist_worker_clear_sessions(ds4_dist_worker_state *state) { it = next; n++; } + if (n != 0) ds4_gpu_reset_runtime_scratch(); return n; } @@ -7008,6 +7547,13 @@ static int dist_worker_handle_snapshot_save( ds4_dist_worker_state *state, ds4_dist_worker_upstream *upstream, uint32_t bytes) { + if (!dist_worker_epoch_is_current(state, upstream->epoch)) { + DIST_DEBUG("worker ignoring stale snapshot-save fd=%d epoch=%llu", + upstream->fd, + (unsigned long long)upstream->epoch); + dist_discard_bytes(upstream->fd, bytes); + return -1; + } ds4_dist_snapshot_req_fixed req; uint64_t request_id = 0; uint64_t session_id = 0; @@ -7114,6 +7660,13 @@ static int dist_worker_handle_snapshot_load( ds4_dist_worker_state *state, ds4_dist_worker_upstream *upstream, uint32_t bytes) { + if (!dist_worker_epoch_is_current(state, upstream->epoch)) { + DIST_DEBUG("worker ignoring stale snapshot-load fd=%d epoch=%llu", + upstream->fd, + (unsigned long long)upstream->epoch); + dist_discard_bytes(upstream->fd, bytes); + return -1; + } ds4_dist_snapshot_begin_fixed begin; uint64_t request_id = 0; uint64_t session_id = 0; @@ -7169,11 +7722,13 @@ static int dist_worker_handle_snapshot_load( dist_token_hash_prefix(tokens, begin.token_count) != token_hash) { snprintf(err, sizeof(err), "snapshot load token hash mismatch"); } + const bool full_resident_worker = dist_worker_full_resident_enabled(); if (!err[0] && (begin.model_id != state->model_id || - begin.layer_start != state->layer_start || - begin.layer_end != state->layer_end || - begin.token_count > (uint32_t)state->ctx_size)) { + begin.token_count > (uint32_t)state->ctx_size || + (!full_resident_worker && + (begin.layer_start != state->layer_start || + begin.layer_end != state->layer_end)))) { snprintf(err, sizeof(err), "snapshot load request does not match worker state"); } @@ -7257,8 +7812,8 @@ static int dist_worker_handle_snapshot_load( payload_bytes, tokens, begin.token_count, - state->layer_start, - state->layer_end, + begin.layer_start, + begin.layer_end, err, sizeof(err)) == 0) { session->token_hash = token_hash; @@ -7282,6 +7837,137 @@ static int dist_worker_handle_snapshot_load( return rc; } +static int dist_worker_handle_local_generate( + ds4_dist_worker_state *state, + ds4_dist_worker_upstream *upstream, + uint32_t bytes) { + if (!dist_worker_epoch_is_current(state, upstream->epoch)) { + DIST_DEBUG("worker ignoring stale local-generate fd=%d epoch=%llu", + upstream->fd, + (unsigned long long)upstream->epoch); + dist_discard_bytes(upstream->fd, bytes); + return -1; + } + ds4_dist_local_generate_req_fixed req; + char err[256] = {0}; + uint64_t request_id = 0; + uint64_t session_id = 0; + const uint32_t vocab = (uint32_t)ds4_engine_vocab_size(state->engine); + const uint32_t logits_bytes = (uint32_t)((uint64_t)vocab * sizeof(float)); + + if (bytes != sizeof(req) + logits_bytes) { + dist_discard_bytes(upstream->fd, bytes); + return -1; + } + int rc = dist_read_full(upstream->fd, &req, sizeof(req)); + if (rc <= 0) return rc == 0 ? 0 : -1; + dist_local_generate_req_from_wire(&req); + request_id = dist_u64_from_halves(req.request_hi, req.request_lo); + session_id = dist_u64_from_halves(req.session_hi, req.session_lo); + const uint64_t token_hash = dist_u64_from_halves(req.token_hash_hi, + req.token_hash_lo); + if (req.model_id != state->model_id || req.logits_bytes != logits_bytes) { + dist_discard_bytes(upstream->fd, bytes - (uint32_t)sizeof(req)); + snprintf(err, sizeof(err), "local generate request does not match worker state"); + } + + float *logits = NULL; + if (!err[0]) { + logits = malloc(logits_bytes); + if (!logits) { + dist_discard_bytes(upstream->fd, logits_bytes); + snprintf(err, sizeof(err), "out of memory reading local generate logits"); + } + } + if (!err[0] && dist_read_full(upstream->fd, logits, logits_bytes) <= 0) { + free(logits); + return -1; + } + + int *tokens = NULL; + float *logits_trace = NULL; + uint32_t generated = 0; + uint64_t final_hash = token_hash; + uint32_t decode_usec = 0; + if (!err[0] && req.n_predict != 0) { + tokens = malloc((size_t)req.n_predict * sizeof(tokens[0])); + if (!tokens) snprintf(err, sizeof(err), "out of memory allocating generated tokens"); + if (!err[0]) { + const uint64_t trace_values64 = (uint64_t)req.n_predict * (uint64_t)vocab; + if (trace_values64 > SIZE_MAX / sizeof(float)) { + snprintf(err, sizeof(err), "local generate logits trace is too large"); + } else { + logits_trace = malloc((size_t)trace_values64 * sizeof(float)); + if (!logits_trace) { + snprintf(err, sizeof(err), "out of memory allocating generated logits trace"); + } + } + } + } + + if (!err[0]) { + pthread_mutex_lock(&state->mu); + ds4_dist_worker_session *session = dist_worker_find_session_locked(state, session_id); + if (!session) { + snprintf(err, sizeof(err), "worker has no session for local generate"); + } else if (!session->token_hash_valid || session->token_hash != token_hash) { + snprintf(err, sizeof(err), "worker local generate token hash mismatch"); + } else if (ds4_session_set_logits(session->session, logits, (int)vocab) != 0) { + snprintf(err, sizeof(err), "failed to seed local generate logits"); + } else { + const double t0 = dist_now_sec(); + for (uint32_t i = 0; i < req.n_predict; i++) { + const int tok = ds4_session_argmax(session->session); + tokens[i] = tok; + if (ds4_session_eval(session->session, tok, err, sizeof(err)) != 0) { + session->token_hash_valid = false; + generated = i; + break; + } + if (logits_trace) { + if (ds4_session_copy_logits(session->session, + logits_trace + (size_t)i * (size_t)vocab, + (int)vocab) != (int)vocab) { + snprintf(err, sizeof(err), "failed to copy local generate logits trace"); + session->token_hash_valid = false; + generated = i; + break; + } + } + final_hash = dist_token_hash_update(final_hash, tok); + generated = i + 1u; + } + const double t1 = dist_now_sec(); + decode_usec = dist_usec_since(t0, t1); + if (!err[0]) { + session->token_hash = final_hash; + session->token_hash_valid = true; + } + } + pthread_mutex_unlock(&state->mu); + } + + pthread_mutex_lock(&upstream->write_mu); + rc = dist_send_local_generate_response(upstream->fd, + session_id, + request_id, + state->model_id, + err[0] ? token_hash : final_hash, + tokens, + generated, + logits_trace, + (uint32_t)((uint64_t)generated * (uint64_t)vocab * + sizeof(float)), + decode_usec, + err[0] ? 1u : 0u, + err); + pthread_mutex_unlock(&upstream->write_mu); + free(tokens); + free(logits_trace); + free(logits); + return rc; +} + /* ========================================================================= * Worker Layer Execution * ========================================================================= */ @@ -7291,6 +7977,12 @@ static int dist_worker_process_work_payload( ds4_dist_worker_upstream *upstream, const void *payload, uint32_t bytes) { + if (!dist_worker_epoch_is_current(state, upstream->epoch)) { + DIST_DEBUG("worker ignoring stale data payload fd=%d epoch=%llu", + upstream->fd, + (unsigned long long)upstream->epoch); + return -1; + } uint64_t request_id = 0; char err[256]; if (bytes < sizeof(ds4_dist_work_fixed)) { @@ -7872,9 +8564,9 @@ static void *dist_worker_prefetch_eval_main(void *arg) { return NULL; } -static int dist_worker_read_loop_prefetch(ds4_dist_worker_state *state, int fd) { +static int dist_worker_read_loop_prefetch(ds4_dist_worker_state *state, int fd, uint64_t epoch) { ds4_dist_worker_upstream upstream; - dist_worker_upstream_init(&upstream, state, fd); + dist_worker_upstream_init(&upstream, state, fd, epoch); ds4_dist_worker_job_queue queue; dist_worker_job_queue_init(&queue, state, &upstream); @@ -7961,6 +8653,14 @@ static int dist_worker_read_loop_prefetch(ds4_dist_worker_state *state, int fd) } continue; } + if (type == DS4_DIST_MSG_LOCAL_GENERATE_REQ) { + rc = dist_worker_handle_local_generate(state, &upstream, bytes); + if (rc <= 0) { + loop_rc = rc == 0 ? 0 : 1; + break; + } + continue; + } rc = dist_discard_bytes(fd, bytes); if (rc <= 0) { loop_rc = rc == 0 ? 0 : 1; @@ -7987,15 +8687,21 @@ static void *dist_worker_data_client_main(void *arg) { ds4_dist_data_client_ctx *ctx = arg; ds4_dist_worker_state *state = ctx->state; int fd = ctx->fd; + const uint64_t epoch = ctx->epoch; char peer_host[NI_MAXHOST]; char peer_port[NI_MAXSERV]; snprintf(peer_host, sizeof(peer_host), "%s", ctx->peer_host); snprintf(peer_port, sizeof(peer_port), "%s", ctx->peer_port); free(ctx); + if (!dist_worker_epoch_is_current(state, epoch)) { + close(fd); + return NULL; + } + int rc = getenv("DS4_DIST_DISABLE_WORKER_PREFETCH") - ? dist_worker_read_loop(state, fd) - : dist_worker_read_loop_prefetch(state, fd); + ? dist_worker_read_loop(state, fd, epoch) + : dist_worker_read_loop_prefetch(state, fd, epoch); if (rc != 0) { fprintf(stderr, "ds4: distributed worker: data connection %s:%s closed after error\n", @@ -8027,8 +8733,20 @@ static void *dist_worker_data_listener_main(void *arg) { close(fd); continue; } + uint64_t epoch = 0; + bool connected = false; + pthread_mutex_lock(&state->mu); + epoch = state->connection_epoch; + connected = state->control_connected; + pthread_mutex_unlock(&state->mu); + if (!connected || epoch == 0) { + close(fd); + free(ctx); + continue; + } ctx->state = state; ctx->fd = fd; + ctx->epoch = epoch; if (getnameinfo((struct sockaddr *)&ss, slen, ctx->peer_host, sizeof(ctx->peer_host), ctx->peer_port, sizeof(ctx->peer_port), @@ -8121,11 +8839,13 @@ static int dist_run_worker(ds4_engine *engine, const ds4_dist_options *opt, int dist_sleep_reconnect(); continue; } + const uint64_t control_epoch = dist_worker_control_connect(&state); int rc = getenv("DS4_DIST_DISABLE_WORKER_PREFETCH") - ? dist_worker_read_loop(&state, fd) - : dist_worker_read_loop_prefetch(&state, fd); + ? dist_worker_read_loop(&state, fd, control_epoch) + : dist_worker_read_loop_prefetch(&state, fd, control_epoch); close(fd); + dist_worker_control_disconnect(&state, control_epoch); uint32_t dropped_sessions = dist_worker_clear_sessions(&state); if (dropped_sessions) { fprintf(stderr, @@ -8497,10 +9217,15 @@ int ds4_dist_prepare_engine_options( if (engine && opt) { engine->distributed = *opt; if (ds4_dist_enabled(opt)) { - engine->load_slice = true; - engine->load_layer_start = opt->layers.start; - engine->load_layer_end = opt->layers.has_output ? UINT32_MAX : opt->layers.end; - engine->load_output = opt->layers.has_output; + const bool full_resident_worker = + opt->role == DS4_DISTRIBUTED_WORKER && + dist_worker_full_resident_enabled(); + if (!full_resident_worker) { + engine->load_slice = true; + engine->load_layer_start = opt->layers.start; + engine->load_layer_end = opt->layers.has_output ? UINT32_MAX : opt->layers.end; + engine->load_output = opt->layers.has_output; + } } } return 0; diff --git a/ds4_distributed.h b/ds4_distributed.h index a207a9232..f37483591 100644 --- a/ds4_distributed.h +++ b/ds4_distributed.h @@ -87,6 +87,29 @@ int ds4_dist_session_describe_route( bool *output_on_coordinator, char *err, size_t errlen); +int ds4_dist_session_handoff_argmax( + ds4_dist_session *d, + ds4_session *owner, + int n_predict, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen); +int ds4_dist_session_handoff_argmax_trace( + ds4_dist_session *d, + ds4_session *owner, + int n_predict, + int *tokens_out, + int token_cap, + float *logits_trace_out, + int logits_trace_cap, + int *logits_trace_steps_out, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen); /* Synchronize the distributed KV state to the requested prompt timeline. */ int ds4_dist_session_sync( diff --git a/ds4_gpu.h b/ds4_gpu.h index dbcd4b9e0..d4e3e8be8 100644 --- a/ds4_gpu.h +++ b/ds4_gpu.h @@ -40,6 +40,7 @@ int ds4_gpu_signal_selected_readback_ready(uint64_t *event_value); int ds4_gpu_commit_and_wait_selected_readback(uint64_t event_value, const char *label); int ds4_gpu_end_commands(void); int ds4_gpu_synchronize(void); +void ds4_gpu_reset_runtime_scratch(void); int ds4_gpu_set_model_map(const void *model_map, uint64_t model_size); int ds4_gpu_set_model_fd(int fd); @@ -55,6 +56,7 @@ int ds4_gpu_preload_q4_expert_tables(const void *model_map, uint64_t model_size, int ds4_gpu_should_use_managed_kv_cache(uint64_t kv_cache_bytes, uint64_t context_bytes); void ds4_gpu_set_quality(bool quality); void ds4_gpu_print_memory_report(const char *label); +int ds4_gpu_query_memory(uint64_t *free_bytes, uint64_t *total_bytes); /* ========================================================================= * Embeddings and Indexer Helpers. diff --git a/ds4_metal.m b/ds4_metal.m index 32e365504..0f77cd7ab 100644 --- a/ds4_metal.m +++ b/ds4_metal.m @@ -1843,6 +1843,12 @@ void ds4_gpu_print_memory_report(const char *label) { ds4_gpu_mib((uint64_t)g_raw_store_round_bytes)); } +int ds4_gpu_query_memory(uint64_t *free_bytes, uint64_t *total_bytes) { + (void)free_bytes; + (void)total_bytes; + return 0; +} + void ds4_gpu_set_quality(bool quality) { g_quality_mode = quality ? 1 : 0; } @@ -5325,6 +5331,78 @@ int ds4_gpu_synchronize(void) { return ds4_gpu_finish_command_buffer(cb, 1, "synchronize"); } +void ds4_gpu_reset_runtime_scratch(void) { + if (!g_initialized) return; + + @autoreleasepool { + if (ds4_gpu_synchronize() == 0) { + fprintf(stderr, "ds4: Metal synchronize before scratch reset failed\n"); + } + + g_selected_readback_event = nil; + g_selected_readback_event_value = 0; + [g_transient_buffers removeAllObjects]; + + g_flash_attn_mask_buffer = nil; + g_flash_attn_pad_buffer = nil; + g_flash_attn_tmp_buffer = nil; + g_flash_attn_blk_buffer = nil; + g_flash_attn_ring_buffer = nil; + g_flash_attn_kv_buffer = nil; + g_compressor_pool_kv_buffer = nil; + g_compressor_pool_score_buffer = nil; + g_compressor_pool_score_cont_buffer = nil; + g_compressor_pool_softmax_buffer = nil; + g_compressor_pool_product_buffer = nil; + g_compressor_store_ape_buffer = nil; + g_compressor_store_score_buffer = nil; + g_embed_rows_buffer = nil; + g_router_selection_buffer = nil; + g_router_weight_sum_buffer = nil; + g_indexer_head_scores_buffer = nil; + g_indexer_topk_buffer = nil; + g_indexed_topk_buffer = nil; + g_f16_round_scratch_buffer = nil; + g_raw_store_round_buffer = nil; + g_moe_gate_scratch_buffer = nil; + g_moe_down_scratch_buffer = nil; + g_moe_id_map_buffer = nil; + g_moe_q4_gate_slots_buffer = nil; + g_moe_q4_up_slots_buffer = nil; + g_moe_q4_down_slots_buffer = nil; + g_attn_out_group_ids_buffer = nil; + + g_flash_attn_mask_bytes = 0; + g_flash_attn_pad_bytes = 0; + g_flash_attn_tmp_bytes = 0; + g_flash_attn_blk_bytes = 0; + g_flash_attn_ring_bytes = 0; + g_flash_attn_kv_bytes = 0; + g_compressor_pool_kv_bytes = 0; + g_compressor_pool_score_bytes = 0; + g_compressor_pool_score_cont_bytes = 0; + g_compressor_pool_softmax_bytes = 0; + g_compressor_pool_product_bytes = 0; + g_compressor_store_ape_bytes = 0; + g_compressor_store_score_bytes = 0; + g_embed_rows_bytes = 0; + g_router_selection_bytes = 0; + g_router_weight_sum_bytes = 0; + g_indexer_head_scores_bytes = 0; + g_indexer_topk_bytes = 0; + g_indexed_topk_bytes = 0; + g_f16_round_scratch_bytes = 0; + g_raw_store_round_bytes = 0; + g_moe_gate_scratch_bytes = 0; + g_moe_down_scratch_bytes = 0; + g_moe_id_map_bytes = 0; + g_moe_q4_gate_slots_bytes = 0; + g_moe_q4_up_slots_bytes = 0; + g_moe_q4_down_slots_bytes = 0; + g_attn_out_group_ids_bytes = 0; + } +} + void ds4_gpu_cleanup(void) { if (!g_initialized) return; diff --git a/tests/issue304_phase4_diagnose.c b/tests/issue304_phase4_diagnose.c new file mode 100644 index 000000000..4c7806f1b --- /dev/null +++ b/tests/issue304_phase4_diagnose.c @@ -0,0 +1,729 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + const char *model_path; + const char *prompt_file; + const char *system_prompt; + const char *listen_host; + const char *coordinator_layers; + const char *worker_layers; + int listen_port; + int ctx_size; + int gen_tokens; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + bool debug; +} diag_cfg; + +typedef struct { + int *tokens; + int token_count; + float *trace; + int trace_steps; + double elapsed_sec; +} token_trace_run; + +typedef struct { + int top1_ref; + int top1_cand; + int top5_overlap; + int top10_overlap; + int top20_overlap; + int nonfinite; + float rms; + float max_abs; + float top20_max_abs; +} parity_metrics; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die_usage(const char *argv0) { + fprintf(stderr, + "usage: %s --model FILE --listen-host IPV4 --listen-port N " + "[--prompt-file FILE] [--system TEXT] [--ctx N] [--gen-tokens N] " + "[--prefill-chunk N] [--prefill-window N] [--activation-bits N] " + "[--coordinator-layers A:B|A:output] [--worker-layers A:B|A:output] [--no-debug]\n", + argv0); + exit(2); +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase4-diagnose: %s\n", msg); + exit(1); +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (len != 0 && fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static bool parse_layer_spec(const char *spec, ds4_distributed_layers *out) { + if (!spec || !out) return false; + const char *colon = strchr(spec, ':'); + if (!colon || colon == spec || colon[1] == '\0') return false; + + errno = 0; + char *end = NULL; + unsigned long start = strtoul(spec, &end, 10); + if (errno != 0 || end != colon || start > UINT32_MAX) return false; + + ds4_distributed_layers layers = {0}; + layers.start = (uint32_t)start; + layers.set = true; + if (strcmp(colon + 1, "output") == 0) { + layers.has_output = true; + layers.end = 0; + } else { + errno = 0; + unsigned long layer_end = strtoul(colon + 1, &end, 10); + if (errno != 0 || *end != '\0' || layer_end > UINT32_MAX) return false; + layers.end = (uint32_t)layer_end; + } + *out = layers; + return true; +} + +static bool set_process_lock_file(const char *path, char *err, size_t errlen) { + if (!path || !path[0]) { + snprintf(err, errlen, "invalid lock file path"); + return false; + } + if (setenv("DS4_LOCK_FILE", path, 1) != 0) { + snprintf(err, errlen, "failed to set DS4_LOCK_FILE: %s", strerror(errno)); + return false; + } + return true; +} + +static int wait_route(ds4_session *session, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase4-diagnose: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase4-diagnose: timed out waiting for route\n"); + return 0; +} + +static void free_token_trace_run(token_trace_run *run) { + free(run->tokens); + free(run->trace); + memset(run, 0, sizeof(*run)); +} + +static void parse_args(diag_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--prompt-file") && i + 1 < argc) { + cfg->prompt_file = argv[++i]; + } else if (!strcmp(argv[i], "--system") && i + 1 < argc) { + cfg->system_prompt = argv[++i]; + } else if (!strcmp(argv[i], "--listen-host") && i + 1 < argc) { + cfg->listen_host = argv[++i]; + } else if (!strcmp(argv[i], "--listen-port") && i + 1 < argc) { + cfg->listen_port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx") && i + 1 < argc) { + cfg->ctx_size = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--gen-tokens") && i + 1 < argc) { + cfg->gen_tokens = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { + cfg->coordinator_layers = argv[++i]; + } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { + cfg->worker_layers = argv[++i]; + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + die_usage(argv[0]); + } + } + + if (!cfg->model_path || !cfg->listen_host || cfg->listen_port <= 0) { + die_usage(argv[0]); + } +} + +static bool open_distributed_session(const diag_cfg *cfg, + ds4_engine *engine, + ds4_session **session_out, + char *route_summary, + size_t route_summary_len, + uint32_t *route_hops, + bool *output_on_coordinator) { + *session_out = NULL; + if (ds4_session_create(session_out, engine, cfg->ctx_size) != 0 || !*session_out) { + fprintf(stderr, "issue304-phase4-diagnose: failed to create distributed session\n"); + return false; + } + if (wait_route(*session_out, 60.0) != 1) return false; + + char err[256] = {0}; + if (ds4_session_distributed_route_summary(*session_out, + route_summary, + route_summary_len, + route_hops, + output_on_coordinator, + err, + sizeof(err)) != 1) { + fprintf(stderr, "issue304-phase4-diagnose: route summary failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + return true; +} + +static void logits_topk(const float *logits, int n, int *out, int k) { + for (int i = 0; i < k; i++) out[i] = -1; + for (int i = 0; i < n; i++) { + const float v = logits[i]; + for (int j = 0; j < k; j++) { + if (out[j] < 0 || v > logits[out[j]]) { + for (int t = k - 1; t > j; t--) out[t] = out[t - 1]; + out[j] = i; + break; + } + } + } +} + +static bool topk_contains(const int *top, int k, int id) { + for (int i = 0; i < k; i++) { + if (top[i] == id) return true; + } + return false; +} + +static parity_metrics compare_logits(const float *ref, const float *cand, int vocab) { + int ref_top[64]; + int cand_top[64]; + logits_topk(ref, vocab, ref_top, 64); + logits_topk(cand, vocab, cand_top, 64); + + int top5_overlap = 0; + int top10_overlap = 0; + int top20_overlap = 0; + for (int i = 0; i < 20; i++) { + if (ref_top[i] < 0) continue; + if (i < 5 && topk_contains(cand_top, 5, ref_top[i])) top5_overlap++; + if (i < 10 && topk_contains(cand_top, 10, ref_top[i])) top10_overlap++; + if (topk_contains(cand_top, 20, ref_top[i])) top20_overlap++; + } + + int nonfinite = 0; + double sumsq = 0.0; + float max_abs = 0.0f; + float top20_max_abs = 0.0f; + for (int i = 0; i < vocab; i++) { + if (!isfinite(ref[i]) || !isfinite(cand[i])) { + nonfinite++; + continue; + } + const float delta = cand[i] - ref[i]; + const float abs_delta = fabsf(delta); + if (abs_delta > max_abs) max_abs = abs_delta; + sumsq += (double)delta * (double)delta; + } + for (int i = 0; i < 20; i++) { + const int id = ref_top[i]; + if (id < 0) continue; + const float abs_delta = fabsf(cand[id] - ref[id]); + if (abs_delta > top20_max_abs) top20_max_abs = abs_delta; + } + + parity_metrics out = { + .top1_ref = ref_top[0], + .top1_cand = cand_top[0], + .top5_overlap = top5_overlap, + .top10_overlap = top10_overlap, + .top20_overlap = top20_overlap, + .nonfinite = nonfinite, + .rms = (float)sqrt(sumsq / (double)vocab), + .max_abs = max_abs, + .top20_max_abs = top20_max_abs, + }; + return out; +} + +static char *token_piece_text(ds4_engine *engine, int token) { + size_t len = 0; + char *piece = ds4_token_text(engine, token, &len); + if (!piece) return strdup(""); + char *out = malloc(len + 1u); + if (!out) { + free(piece); + return NULL; + } + memcpy(out, piece, len); + out[len] = '\0'; + free(piece); + return out; +} + +static char *tokens_render_text(ds4_engine *engine, const int *tokens, int n) { + size_t cap = 128; + size_t len = 0; + char *buf = malloc(cap); + if (!buf) return NULL; + buf[0] = '\0'; + for (int i = 0; i < n; i++) { + size_t piece_len = 0; + char *piece = ds4_token_text(engine, tokens[i], &piece_len); + if (!piece) continue; + if (len + piece_len + 1u > cap) { + size_t need = len + piece_len + 1u; + size_t next = cap; + while (next < need) next *= 2u; + char *grown = realloc(buf, next); + if (!grown) { + free(piece); + free(buf); + return NULL; + } + buf = grown; + cap = next; + } + memcpy(buf + len, piece, piece_len); + len += piece_len; + buf[len] = '\0'; + free(piece); + } + return buf; +} + +static void print_json_string(const char *s) { + putchar('"'); + for (const unsigned char *p = (const unsigned char *)s; *p; p++) { + unsigned char c = *p; + switch (c) { + case '\\': fputs("\\\\", stdout); break; + case '"': fputs("\\\"", stdout); break; + case '\b': fputs("\\b", stdout); break; + case '\f': fputs("\\f", stdout); break; + case '\n': fputs("\\n", stdout); break; + case '\r': fputs("\\r", stdout); break; + case '\t': fputs("\\t", stdout); break; + default: + if (c < 0x20u) { + printf("\\u%04x", c); + } else { + putchar((char)c); + } + break; + } + } + putchar('"'); +} + +static void print_token_array(const int *tokens, int n) { + putchar('['); + for (int i = 0; i < n; i++) { + if (i != 0) putchar(','); + printf("%d", tokens[i]); + } + putchar(']'); +} + +static void print_topk_json(ds4_engine *engine, const float *logits, int vocab, int k) { + int top[16]; + if (k > (int)(sizeof(top) / sizeof(top[0]))) k = (int)(sizeof(top) / sizeof(top[0])); + logits_topk(logits, vocab, top, k); + putchar('['); + for (int i = 0; i < k; i++) { + char *piece = token_piece_text(engine, top[i]); + if (i != 0) putchar(','); + printf("{\"id\":%d,\"logit\":%.6f,\"text\":", top[i], logits[top[i]]); + print_json_string(piece ? piece : ""); + printf("}"); + free(piece); + } + putchar(']'); +} + +static bool capture_reference_trace(ds4_session *session, + int vocab, + int steps, + token_trace_run *out) { + memset(out, 0, sizeof(*out)); + out->tokens = malloc((size_t)steps * sizeof(out->tokens[0])); + out->trace = malloc((size_t)steps * (size_t)vocab * sizeof(out->trace[0])); + if (!out->tokens || !out->trace) return false; + + char err[160] = {0}; + double t0 = now_sec(); + for (int i = 0; i < steps; i++) { + const int token = ds4_session_argmax(session); + out->tokens[i] = token; + out->token_count++; + if (ds4_session_eval(session, token, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase4-diagnose: distributed eval failed at step %d: %s\n", + i, err[0] ? err : "unknown error"); + return false; + } + if (ds4_session_copy_logits(session, + out->trace + (size_t)i * (size_t)vocab, + vocab) != vocab) { + fprintf(stderr, "issue304-phase4-diagnose: failed to copy distributed logits at step %d\n", + i); + return false; + } + out->trace_steps = i + 1; + } + out->elapsed_sec = now_sec() - t0; + return true; +} + +int main(int argc, char **argv) { + diag_cfg cfg = { + .system_prompt = "You are a concise assistant.", + .ctx_size = 16384, + .gen_tokens = 16, + .prefill_chunk = 0, + .prefill_window = 0, + .activation_bits = 0, + .debug = true, + .coordinator_layers = "0:21", + .worker_layers = "22:output", + }; + parse_args(&cfg, argc, argv); + + char *prompt_text = cfg.prompt_file ? read_file(cfg.prompt_file) : strdup("Summarize this test."); + if (!prompt_text) die("failed to read prompt"); + + ds4_distributed_layers coordinator_layers = {0}; + ds4_distributed_layers worker_layers = {0}; + if (!parse_layer_spec(cfg.coordinator_layers, &coordinator_layers) || + !parse_layer_spec(cfg.worker_layers, &worker_layers)) { + die("failed to parse coordinator or worker layer range"); + } + + char err[256] = {0}; + if (!set_process_lock_file("/tmp/ds4-phase4-diagnose.lock", err, sizeof(err))) { + die(err); + } + + ds4_engine *dist_engine = NULL; + ds4_session *handoff_session = NULL; + ds4_session *reference_session = NULL; + ds4_tokens prompt = {0}; + token_trace_run handoff_run = {0}; + token_trace_run reference_run = {0}; + float *seed_logits_handoff = NULL; + float *seed_logits_ref = NULL; + int local_first_token = -1; + int ref_first_token = -1; + int mismatch_step = -1; + bool token_match = false; + double prefill_handoff_sec = 0.0; + double prefill_ref_sec = 0.0; + double shard_load_sec = 0.0; + double local_decode_sec = 0.0; + uint32_t route_hops = 0; + bool output_on_coordinator = false; + char route_summary[1024] = {0}; + + ds4_engine_options dist_opt = { + .model_path = cfg.model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = coordinator_layers, + .listen_host = cfg.listen_host, + .listen_port = cfg.listen_port, + .prefill_chunk = cfg.prefill_chunk, + .prefill_window = cfg.prefill_window, + .activation_bits = cfg.activation_bits, + .debug = cfg.debug, + }, + }; + if (ds4_dist_prepare_engine_options(&dist_opt.distributed, &dist_opt, err, sizeof(err)) != 0) { + die(err[0] ? err : "distributed options failed"); + } + if (ds4_engine_open(&dist_engine, &dist_opt) != 0 || !dist_engine) { + die("failed to open distributed coordinator engine"); + } + + const int vocab = ds4_engine_vocab_size(dist_engine); + if (vocab <= 0) die("invalid vocab size"); + + if (!open_distributed_session(&cfg, + dist_engine, + &handoff_session, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator)) { + die("failed to open handoff session"); + } + if (output_on_coordinator) die("phase4 diagnose requires worker-owned output head"); + + ds4_encode_chat_prompt(dist_engine, cfg.system_prompt, prompt_text, DS4_THINK_NONE, &prompt); + if (prompt.len <= 0) die("prompt tokenization failed"); + if (prompt.len >= cfg.ctx_size) die("prompt exceeds ctx"); + + double t0 = now_sec(); + if (ds4_session_sync(handoff_session, &prompt, err, sizeof(err)) != 0) { + die(err[0] ? err : "distributed prefill failed"); + } + prefill_handoff_sec = now_sec() - t0; + + seed_logits_handoff = malloc((size_t)vocab * sizeof(seed_logits_handoff[0])); + handoff_run.tokens = malloc((size_t)cfg.gen_tokens * sizeof(handoff_run.tokens[0])); + handoff_run.trace = malloc((size_t)cfg.gen_tokens * (size_t)vocab * sizeof(handoff_run.trace[0])); + if (!seed_logits_handoff || !handoff_run.tokens || !handoff_run.trace) { + die("out of memory allocating handoff trace buffers"); + } + if (ds4_session_copy_logits(handoff_session, seed_logits_handoff, vocab) != vocab) { + die("failed to copy handoff seed logits"); + } + local_first_token = ds4_session_argmax(handoff_session); + handoff_run.token_count = ds4_session_distributed_handoff_argmax_trace( + handoff_session, + cfg.gen_tokens, + handoff_run.tokens, + cfg.gen_tokens, + handoff_run.trace, + cfg.gen_tokens * vocab, + &handoff_run.trace_steps, + &shard_load_sec, + &local_decode_sec, + err, + sizeof(err)); + handoff_run.elapsed_sec = local_decode_sec; + if (handoff_run.token_count < 0) { + die(err[0] ? err : "distributed handoff trace failed"); + } + + ds4_session_free(handoff_session); + handoff_session = NULL; + + if (!open_distributed_session(&cfg, + dist_engine, + &reference_session, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator)) { + die("failed to open reference session"); + } + t0 = now_sec(); + if (ds4_session_sync(reference_session, &prompt, err, sizeof(err)) != 0) { + die(err[0] ? err : "distributed reference prefill failed"); + } + prefill_ref_sec = now_sec() - t0; + + seed_logits_ref = malloc((size_t)vocab * sizeof(seed_logits_ref[0])); + if (!seed_logits_ref) die("out of memory allocating reference seed logits"); + if (ds4_session_copy_logits(reference_session, seed_logits_ref, vocab) != vocab) { + die("failed to copy reference seed logits"); + } + ref_first_token = ds4_session_argmax(reference_session); + if (!capture_reference_trace(reference_session, vocab, cfg.gen_tokens, &reference_run)) { + die("failed to capture distributed reference trace"); + } + + token_match = handoff_run.token_count == reference_run.token_count; + if (token_match) { + for (int i = 0; i < handoff_run.token_count; i++) { + if (handoff_run.tokens[i] != reference_run.tokens[i]) { + token_match = false; + mismatch_step = i; + break; + } + } + } + + const float *ref_cmp = NULL; + const float *cand_cmp = NULL; + int local_mismatch_token = -1; + int ref_mismatch_token = -1; + char *local_piece = NULL; + char *ref_piece = NULL; + if (!token_match) { + if (mismatch_step == 0) { + ref_cmp = seed_logits_ref; + cand_cmp = seed_logits_handoff; + } else if (mismatch_step > 0 && + mismatch_step - 1 < reference_run.trace_steps && + mismatch_step - 1 < handoff_run.trace_steps) { + ref_cmp = reference_run.trace + (size_t)(mismatch_step - 1) * (size_t)vocab; + cand_cmp = handoff_run.trace + (size_t)(mismatch_step - 1) * (size_t)vocab; + } + if (mismatch_step >= 0 && mismatch_step < handoff_run.token_count) { + local_mismatch_token = handoff_run.tokens[mismatch_step]; + local_piece = token_piece_text(dist_engine, local_mismatch_token); + } + if (mismatch_step >= 0 && mismatch_step < reference_run.token_count) { + ref_mismatch_token = reference_run.tokens[mismatch_step]; + ref_piece = token_piece_text(dist_engine, ref_mismatch_token); + } + } + + const char *local_text = ""; + const char *reference_text = ""; + char *local_text_owned = tokens_render_text(dist_engine, handoff_run.tokens, handoff_run.token_count); + char *reference_text_owned = tokens_render_text(dist_engine, reference_run.tokens, reference_run.token_count); + if (local_text_owned) local_text = local_text_owned; + if (reference_text_owned) reference_text = reference_text_owned; + + printf("{\n"); + printf(" \"tool\":\"issue304_phase4_diagnose\",\n"); + printf(" \"model_path\":"); + print_json_string(cfg.model_path); + printf(",\n"); + printf(" \"prompt_file\":"); + print_json_string(cfg.prompt_file ? cfg.prompt_file : ""); + printf(",\n"); + printf(" \"ctx\":%d,\n", cfg.ctx_size); + printf(" \"prompt_tokens\":%d,\n", prompt.len); + printf(" \"gen_tokens\":%d,\n", cfg.gen_tokens); + printf(" \"prefill_chunk\":%u,\n", cfg.prefill_chunk); + printf(" \"prefill_window\":%u,\n", cfg.prefill_window); + printf(" \"activation_bits\":%u,\n", cfg.activation_bits); + printf(" \"route_hops\":%u,\n", route_hops); + printf(" \"route_summary\":"); + print_json_string(route_summary); + printf(",\n"); + printf(" \"prefill_handoff_sec\":%.6f,\n", prefill_handoff_sec); + printf(" \"prefill_ref_sec\":%.6f,\n", prefill_ref_sec); + printf(" \"shard_load_sec\":%.6f,\n", shard_load_sec); + printf(" \"local_decode_sec\":%.6f,\n", local_decode_sec); + printf(" \"reference_decode_sec\":%.6f,\n", reference_run.elapsed_sec); + printf(" \"handoff_first_token\":%d,\n", local_first_token); + printf(" \"reference_first_token\":%d,\n", ref_first_token); + printf(" \"generated\":{\n"); + printf(" \"match\":%s,\n", token_match ? "true" : "false"); + printf(" \"mismatch_step\":%d,\n", mismatch_step); + printf(" \"handoff_tokens\":"); + print_token_array(handoff_run.tokens, handoff_run.token_count); + printf(",\n"); + printf(" \"reference_tokens\":"); + print_token_array(reference_run.tokens, reference_run.token_count); + printf(",\n"); + printf(" \"handoff_text\":"); + print_json_string(local_text); + printf(",\n"); + printf(" \"reference_text\":"); + print_json_string(reference_text); + printf("\n"); + printf(" }"); + + if (!token_match && ref_cmp && cand_cmp) { + parity_metrics cmp = compare_logits(ref_cmp, cand_cmp, vocab); + int ref_top10[10]; + int cand_top10[10]; + logits_topk(ref_cmp, vocab, ref_top10, 10); + logits_topk(cand_cmp, vocab, cand_top10, 10); + printf(",\n \"mismatch\":{\n"); + printf(" \"step\":%d,\n", mismatch_step); + printf(" \"handoff_token\":%d,\n", local_mismatch_token); + printf(" \"reference_token\":%d,\n", ref_mismatch_token); + printf(" \"handoff_token_text\":"); + print_json_string(local_piece ? local_piece : ""); + printf(",\n"); + printf(" \"reference_token_text\":"); + print_json_string(ref_piece ? ref_piece : ""); + printf(",\n"); + printf(" \"handoff_in_reference_top5\":%s,\n", + topk_contains(ref_top10, 5, local_mismatch_token) ? "true" : "false"); + printf(" \"handoff_in_reference_top10\":%s,\n", + topk_contains(ref_top10, 10, local_mismatch_token) ? "true" : "false"); + printf(" \"reference_in_handoff_top5\":%s,\n", + topk_contains(cand_top10, 5, ref_mismatch_token) ? "true" : "false"); + printf(" \"reference_in_handoff_top10\":%s,\n", + topk_contains(cand_top10, 10, ref_mismatch_token) ? "true" : "false"); + printf(" \"logits\":{\n"); + printf(" \"top1_ref\":%d,\n", cmp.top1_ref); + printf(" \"top1_handoff\":%d,\n", cmp.top1_cand); + printf(" \"top5_overlap\":%d,\n", cmp.top5_overlap); + printf(" \"top10_overlap\":%d,\n", cmp.top10_overlap); + printf(" \"top20_overlap\":%d,\n", cmp.top20_overlap); + printf(" \"nonfinite\":%d,\n", cmp.nonfinite); + printf(" \"rms\":%.8f,\n", cmp.rms); + printf(" \"max_abs\":%.8f,\n", cmp.max_abs); + printf(" \"top20_max_abs\":%.8f,\n", cmp.top20_max_abs); + printf(" \"reference_top10\":"); + print_topk_json(dist_engine, ref_cmp, vocab, 10); + printf(",\n"); + printf(" \"handoff_top10\":"); + print_topk_json(dist_engine, cand_cmp, vocab, 10); + printf("\n"); + printf(" }\n"); + printf(" }\n"); + } else { + printf("\n"); + } + printf("}\n"); + + free(local_piece); + free(ref_piece); + free(local_text_owned); + free(reference_text_owned); + free(seed_logits_handoff); + free(seed_logits_ref); + free(prompt_text); + ds4_tokens_free(&prompt); + free_token_trace_run(&handoff_run); + free_token_trace_run(&reference_run); + ds4_session_free(handoff_session); + ds4_session_free(reference_session); + ds4_engine_close(dist_engine); + return 0; +} diff --git a/tests/issue304_phase4_handoff.c b/tests/issue304_phase4_handoff.c new file mode 100644 index 000000000..fa60ca810 --- /dev/null +++ b/tests/issue304_phase4_handoff.c @@ -0,0 +1,433 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + const char *model_path; + const char *prompt_file; + const char *system_prompt; + const char *listen_host; + const char *coordinator_layers; + const char *worker_layers; + int listen_port; + int ctx_size; + int gen_tokens; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + bool debug; +} phase4_cfg; + +typedef struct { + int *tokens; + int token_count; + double elapsed_sec; +} token_run; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die_usage(const char *argv0) { + fprintf(stderr, + "usage: %s --model FILE --listen-host IPV4 --listen-port N " + "[--prompt-file FILE] [--system TEXT] [--ctx N] [--gen-tokens N] " + "[--prefill-chunk N] [--prefill-window N] [--activation-bits N] " + "[--coordinator-layers A:B|A:output] [--worker-layers A:B|A:output] [--no-debug]\n", + argv0); + exit(2); +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase4-handoff: %s\n", msg); + exit(1); +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (len != 0 && fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static bool parse_layer_spec(const char *spec, ds4_distributed_layers *out) { + if (!spec || !out) return false; + const char *colon = strchr(spec, ':'); + if (!colon || colon == spec || colon[1] == '\0') return false; + + errno = 0; + char *end = NULL; + unsigned long start = strtoul(spec, &end, 10); + if (errno != 0 || end != colon || start > UINT32_MAX) return false; + + ds4_distributed_layers layers = {0}; + layers.start = (uint32_t)start; + layers.set = true; + if (strcmp(colon + 1, "output") == 0) { + layers.has_output = true; + layers.end = 0; + } else { + errno = 0; + unsigned long layer_end = strtoul(colon + 1, &end, 10); + if (errno != 0 || *end != '\0' || layer_end > UINT32_MAX) return false; + layers.end = (uint32_t)layer_end; + } + *out = layers; + return true; +} + +static bool set_process_lock_file(const char *path, char *err, size_t errlen) { + if (!path || !path[0]) { + snprintf(err, errlen, "invalid lock file path"); + return false; + } + if (setenv("DS4_LOCK_FILE", path, 1) != 0) { + snprintf(err, errlen, "failed to set DS4_LOCK_FILE: %s", strerror(errno)); + return false; + } + return true; +} + +static int wait_route(ds4_session *session, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase4-handoff: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase4-handoff: timed out waiting for route\n"); + return 0; +} + +static bool capture_greedy_trace(ds4_session *session, int steps, token_run *out) { + memset(out, 0, sizeof(*out)); + out->tokens = malloc((size_t)steps * sizeof(out->tokens[0])); + if (!out->tokens) return false; + + char err[160]; + double t0 = now_sec(); + for (int i = 0; i < steps; i++) { + const int token = ds4_session_argmax(session); + out->tokens[i] = token; + out->token_count++; + if (ds4_session_eval(session, token, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase4-handoff: distributed eval failed at step %d: %s\n", + i, err[0] ? err : "unknown error"); + return false; + } + } + out->elapsed_sec = now_sec() - t0; + return true; +} + +static void free_token_run(token_run *run) { + free(run->tokens); + memset(run, 0, sizeof(*run)); +} + +static void parse_args(phase4_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--prompt-file") && i + 1 < argc) { + cfg->prompt_file = argv[++i]; + } else if (!strcmp(argv[i], "--system") && i + 1 < argc) { + cfg->system_prompt = argv[++i]; + } else if (!strcmp(argv[i], "--listen-host") && i + 1 < argc) { + cfg->listen_host = argv[++i]; + } else if (!strcmp(argv[i], "--listen-port") && i + 1 < argc) { + cfg->listen_port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx") && i + 1 < argc) { + cfg->ctx_size = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--gen-tokens") && i + 1 < argc) { + cfg->gen_tokens = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { + cfg->coordinator_layers = argv[++i]; + } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { + cfg->worker_layers = argv[++i]; + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + die_usage(argv[0]); + } + } + + if (!cfg->model_path || !cfg->listen_host || cfg->listen_port <= 0) { + die_usage(argv[0]); + } +} + +static bool open_distributed_session(const phase4_cfg *cfg, + ds4_engine *engine, + ds4_session **session_out, + char *route_summary, + size_t route_summary_len, + uint32_t *route_hops, + bool *output_on_coordinator) { + *session_out = NULL; + if (ds4_session_create(session_out, engine, cfg->ctx_size) != 0 || !*session_out) { + fprintf(stderr, "issue304-phase4-handoff: failed to create distributed session\n"); + return false; + } + if (wait_route(*session_out, 60.0) != 1) return false; + + char err[256] = {0}; + if (ds4_session_distributed_route_summary(*session_out, + route_summary, + route_summary_len, + route_hops, + output_on_coordinator, + err, + sizeof(err)) != 1) { + fprintf(stderr, "issue304-phase4-handoff: route summary failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + return true; +} + +static void print_token_array(const int *tokens, int n) { + putchar('['); + for (int i = 0; i < n; i++) { + if (i != 0) printf(","); + printf("%d", tokens[i]); + } + putchar(']'); +} + +int main(int argc, char **argv) { + phase4_cfg cfg = { + .system_prompt = "You are a concise assistant.", + .ctx_size = 16384, + .gen_tokens = 16, + .prefill_chunk = 0, + .prefill_window = 0, + .activation_bits = 0, + .debug = true, + .coordinator_layers = "0:21", + .worker_layers = "22:output", + }; + parse_args(&cfg, argc, argv); + + char *prompt_text = cfg.prompt_file ? read_file(cfg.prompt_file) : strdup("Summarize this test."); + if (!prompt_text) die("failed to read prompt"); + + ds4_distributed_layers coordinator_layers = {0}; + ds4_distributed_layers worker_layers = {0}; + if (!parse_layer_spec(cfg.coordinator_layers, &coordinator_layers) || + !parse_layer_spec(cfg.worker_layers, &worker_layers)) { + die("failed to parse coordinator or worker layer range"); + } + + char err[256] = {0}; + if (!set_process_lock_file("/tmp/ds4-phase4-dist.lock", err, sizeof(err))) { + die(err); + } + + ds4_engine *dist_engine = NULL; + ds4_session *handoff_session = NULL; + ds4_session *reference_session = NULL; + ds4_tokens prompt = {0}; + token_run dist_run = {0}; + int *local_tokens = NULL; + int local_generated = -1; + int local_first_token = -1; + int dist_first_token = -1; + bool token_match = false; + int mismatch_step = -1; + double prefill_handoff_sec = 0.0; + double prefill_ref_sec = 0.0; + double shard_load_sec = 0.0; + double local_decode_sec = 0.0; + uint32_t route_hops = 0; + bool output_on_coordinator = false; + char route_summary[1024] = {0}; + + ds4_engine_options dist_opt = { + .model_path = cfg.model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = coordinator_layers, + .listen_host = cfg.listen_host, + .listen_port = cfg.listen_port, + .prefill_chunk = cfg.prefill_chunk, + .prefill_window = cfg.prefill_window, + .activation_bits = cfg.activation_bits, + .debug = cfg.debug, + }, + }; + if (ds4_dist_prepare_engine_options(&dist_opt.distributed, &dist_opt, err, sizeof(err)) != 0) { + die(err[0] ? err : "distributed options failed"); + } + if (ds4_engine_open(&dist_engine, &dist_opt) != 0 || !dist_engine) { + die("failed to open distributed coordinator engine"); + } + + if (!open_distributed_session(&cfg, + dist_engine, + &handoff_session, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator)) { + die("failed to open handoff session"); + } + if (output_on_coordinator) { + die("phase4 handoff requires worker-owned output head"); + } + + ds4_encode_chat_prompt(dist_engine, cfg.system_prompt, prompt_text, DS4_THINK_NONE, &prompt); + if (prompt.len <= 0) die("prompt tokenization failed"); + if (prompt.len >= cfg.ctx_size) die("prompt exceeds ctx"); + + double t0 = now_sec(); + if (ds4_session_sync(handoff_session, &prompt, err, sizeof(err)) != 0) { + die(err[0] ? err : "distributed prefill failed"); + } + prefill_handoff_sec = now_sec() - t0; + local_first_token = ds4_session_argmax(handoff_session); + + local_tokens = malloc((size_t)cfg.gen_tokens * sizeof(local_tokens[0])); + if (!local_tokens) die("out of memory allocating local token buffer"); + local_generated = ds4_session_distributed_handoff_argmax(handoff_session, + cfg.gen_tokens, + local_tokens, + cfg.gen_tokens, + &shard_load_sec, + &local_decode_sec, + err, + sizeof(err)); + if (local_generated < 0) { + die(err[0] ? err : "distributed local handoff failed"); + } + + ds4_session_free(handoff_session); + handoff_session = NULL; + + if (!open_distributed_session(&cfg, + dist_engine, + &reference_session, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator)) { + die("failed to open reference session"); + } + t0 = now_sec(); + if (ds4_session_sync(reference_session, &prompt, err, sizeof(err)) != 0) { + die(err[0] ? err : "distributed reference prefill failed"); + } + prefill_ref_sec = now_sec() - t0; + dist_first_token = ds4_session_argmax(reference_session); + if (!capture_greedy_trace(reference_session, cfg.gen_tokens, &dist_run)) { + die("failed to capture distributed reference trace"); + } + + token_match = local_generated == dist_run.token_count; + if (token_match) { + for (int i = 0; i < local_generated; i++) { + if (local_tokens[i] != dist_run.tokens[i]) { + token_match = false; + mismatch_step = i; + break; + } + } + } + + printf("{\n"); + printf(" \"tool\":\"issue304_phase4_handoff\",\n"); + printf(" \"model_path\":\"%s\",\n", cfg.model_path); + printf(" \"prompt_file\":\"%s\",\n", cfg.prompt_file ? cfg.prompt_file : ""); + printf(" \"ctx\":%d,\n", cfg.ctx_size); + printf(" \"prompt_tokens\":%d,\n", prompt.len); + printf(" \"gen_tokens\":%d,\n", cfg.gen_tokens); + printf(" \"prefill_chunk\":%u,\n", cfg.prefill_chunk); + printf(" \"prefill_window\":%u,\n", cfg.prefill_window); + printf(" \"activation_bits\":%u,\n", cfg.activation_bits); + printf(" \"coordinator_layers\":\"%s\",\n", cfg.coordinator_layers); + printf(" \"worker_layers\":\"%s\",\n", cfg.worker_layers); + printf(" \"route_hops\":%u,\n", route_hops); + printf(" \"route_summary\":\"%s\",\n", route_summary); + printf(" \"output_owner\":\"%s\",\n", output_on_coordinator ? "coordinator" : "worker"); + printf(" \"prefill_handoff_sec\":%.6f,\n", prefill_handoff_sec); + printf(" \"prefill_ref_sec\":%.6f,\n", prefill_ref_sec); + printf(" \"shard_load_sec\":%.6f,\n", shard_load_sec); + printf(" \"local_decode_sec\":%.6f,\n", local_decode_sec); + printf(" \"local_decode_tok_per_sec\":%.2f,\n", + local_decode_sec > 0.0 ? (double)local_generated / local_decode_sec : 0.0); + printf(" \"distributed_decode_sec\":%.6f,\n", dist_run.elapsed_sec); + printf(" \"distributed_decode_tok_per_sec\":%.2f,\n", + dist_run.elapsed_sec > 0.0 ? (double)dist_run.token_count / dist_run.elapsed_sec : 0.0); + printf(" \"handoff_first_token\":%d,\n", local_first_token); + printf(" \"reference_first_token\":%d,\n", dist_first_token); + printf(" \"generated\":{\n"); + printf(" \"count\":%d,\n", local_generated); + printf(" \"match\":%s,\n", token_match ? "true" : "false"); + printf(" \"mismatch_step\":%d,\n", mismatch_step); + printf(" \"local_tokens\":"); + print_token_array(local_tokens, local_generated); + printf(",\n"); + printf(" \"distributed_tokens\":"); + print_token_array(dist_run.tokens, dist_run.token_count); + printf("\n"); + printf(" }\n"); + printf("}\n"); + + free(local_tokens); + free_token_run(&dist_run); + ds4_tokens_free(&prompt); + ds4_session_free(reference_session); + ds4_session_free(handoff_session); + ds4_engine_close(dist_engine); + free(prompt_text); + return 0; +} From e9e5a480c39013d4337da796d52b7ae823b936b1 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 12:14:05 +0100 Subject: [PATCH 08/17] phases 5+ scope refinement --- PLAN.md | 163 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 95 insertions(+), 68 deletions(-) diff --git a/PLAN.md b/PLAN.md index df55a92cd..830a29204 100644 --- a/PLAN.md +++ b/PLAN.md @@ -640,6 +640,12 @@ Goal: - What: choose and implement a viable residency-plus-plumbing design that lets the final worker participate in distributed prefill over its later-layer route slice, then continue local decode as the full-resident generation node through a repeatable operator-facing workflow. - Scope: this phase is not another variance-forensics phase. Phase 3 and Phase 3.5 variance remains an active caveat, but Phase 4 should answer whether a practical, benchmarkable handoff workflow can exist with acceptable residency and operator complexity. +Closeout note: + +- Phase 4 is now complete. +- The practical answer is yes: a final-worker full-resident handoff workflow exists, works in both backend directions, and is benchmarkable. +- Ongoing caveat: strict `CUDA -> Metal` parity checks should use a fresh Metal worker process because reused-worker reruns can still produce Phase-3.5-class near-top1 variance. + Expected artifacts: - Update `artifacts/issue-304/engine-residency.md` with the current layer-loading model, observed memory behavior, and candidate designs. @@ -780,14 +786,19 @@ Code touchpoints: Likely options: +- Same-session final-worker handoff: + - keep the final worker's later-layer KV resident in its existing distributed worker session, + - transfer only the coordinator-owned earlier-layer shard into that same worker session, + - and continue local decode in-process on the final worker. + - This is now the preferred Phase 5 implementation direction because Phase 4 proved it viable. - Whole-payload handoff: - - expose a helper that saves/stages a distributed session payload and loads it into a provided local session. + - keep merged `DSV4` staging as a correctness harness, debug surface, and fallback diagnostic. + - Do not treat it as the preferred user-facing implementation unless the same-session path proves too brittle. - In-memory payload handoff: - - extend distributed sessions so `ds4_session_save_snapshot()` or a new memory-backed payload helper can gather remote shards. - - This avoids temp files, but requires solving the current distributed snapshot restriction. + - only pursue if the same logical whole-payload path is still needed after Phase 5 and temp-file staging is the only material problem. - Explicit shard merge: - - expose a multi-`DSVL` merge path that reconstructs a local session from layer shards. - - This is more invasive and should only be chosen if whole `DSV4` handoff proves too slow or too rigid. + - treat this as the practical optimization path around the coordinator-owned missing shard, not as a requirement to reconstruct the full session from scratch. + - Prefer it only in the narrow form already validated by Phase 4: worker keeps its own later-layer KV in place while loading the coordinator's earlier-layer shard. Decision criteria: @@ -797,16 +808,17 @@ Decision criteria: - Ability to support cross-backend handoff. - Measured handoff overhead relative to prefill speedup. - Amount of new protocol surface in `ds4_distributed.c`. +- Fit with the validated same-session final-worker continuation shape. Work items: -- Decide whether the first implementation should be whole-payload, in-memory payload, or explicit shard merge. +- Decide the smallest API shape for the already-chosen same-session final-worker continuation path. - Record that decision and evidence before adding user-facing wiring. - Add the minimal session-level handoff mechanism selected from that decision. -- Keep the distributed prefill session and local decode session distinct unless evidence shows same-session mutation is safer. -- Ensure the local session receives full token timeline, logits, raw SWA KV rows in logical order, compressed KV rows, compressor frontier state, and indexer state. +- Prefer same-session worker continuation; keep whole-payload `DSV4` as a debug/fallback path rather than the primary implementation. +- Ensure the final worker session receives full token timeline, logits, raw SWA KV rows in logical order, compressed KV rows, compressor frontier state, and indexer state. - Add CLI/server wiring only after the core session path works. -- Document the operator requirement for full local decode weights if the coordinator's distributed `--layers` setting does not load them. +- Document the operator requirement for full decode weights on the final worker and the current validation rule for strict `CUDA -> Metal` parity checks: restart the Metal worker first. Exit gate: @@ -817,7 +829,7 @@ Exit gate: Goal: - Why: once correctness is established, the remaining risk is that post-prefill shard fetch/merge/load latency erases the practical benefit of faster distributed prefill. -- What: measure handoff overhead, then add incremental or pipelined KV return only if it materially reduces latency while preserving token/hash ordering, backend synchronization, and resume equivalence. +- What: measure the residual cost of returning the coordinator-owned missing KV shard to the final worker, then add incremental or pipelined KV return only if it materially reduces latency while preserving token/hash ordering, backend synchronization, and resume equivalence. Expected artifacts: @@ -857,12 +869,17 @@ Other entry points: Work items: - Extend `ds4_distributed.c` only after Phase 5 shows payload save/load overhead is material. -- Investigate returning worker-owned KV alongside prefill chunk boundaries. +- Investigate returning only the coordinator-owned missing KV alongside prefill chunk boundaries. - Define when a chunk's KV is safe to export relative to in-flight kernels and worker forwarding. - Preserve ratio-4 compressor/indexer frontier state; do not return only completed compressed rows. - Reuse existing snapshot chunk framing where possible: `DS4_DIST_MSG_SNAPSHOT_SAVE_REQ`, `DS4_DIST_MSG_SNAPSHOT_BEGIN`, `DS4_DIST_MSG_SNAPSHOT_CHUNK`, and `DS4_DIST_MSG_SNAPSHOT_DONE`. - Add new protocol messages only if existing request/response snapshot framing cannot express incremental return cleanly. +Scope note: + +- Phase 6 is no longer about optimizing a whole-session `DSV4` handoff first. +- It is specifically about shrinking or hiding the cost of moving the coordinator-owned earlier-layer KV into the already-full-resident final worker session. + Exit gate: - Incremental KV return reduces measured handoff latency without changing resumed logits/tokens beyond the Phase 3 official/local acceptance envelope. @@ -914,22 +931,69 @@ Exit gate: - Known stale/missing/mismatched shard cases fail closed with useful diagnostics. -### Phase 8: Topology decoupling follow-on +### Phase 8: Documentation and durable learnings + +Goal: + +- Why: this change crosses distributed transport, backend serialization, model residency, KV persistence, and user workflow; undocumented learnings will be expensive to rediscover. +- What: update user docs, runbooks, decision logs, performance notes, failure cases, and this plan so the final implementation state and remaining deferred work are clear to the next engineer. + +Expected artifacts: + +- Update `README.md` with the final user-visible workflow, constraints, and expected performance behavior. +- Update `artifacts/issue-304/runbook.md` with final known-good commands. +- Update `artifacts/issue-304/decision-log.md` with final architecture and remaining deferred work. +- Update `artifacts/issue-304/perf-breakdown.md` with final benchmark numbers. +- Update `artifacts/issue-304/topology-decoupling.md` if topology flexibility is deferred or partially implemented. +- Update `artifacts/issue-304/research-notes.md` with a final phase-by-phase summary of what was learned and what remains deferred. +- Keep this `PLAN.md` accurate if parts of the staged plan were skipped or invalidated. + +Code/documentation touchpoints: + +- `README.md` + - Distributed inference documentation. + - Any new CLI/server workflow. +- `ds4_cli.c` + - Help text and flag descriptions if CLI flags were added. +- `ds4_server.c` + - API/session documentation if server behavior changed. +- Tests added in prior phases. + +Other entry points: + +- GitHub issue #304 follow-up comment or PR description. +- Any local scripts/harnesses created for validation. +- Artifact files under `artifacts/issue-304/`. + +Work items: + +- Update `README.md` once the user-visible workflow exists. +- Keep issue-specific research notes in `artifacts/issue-304/`. +- Keep this plan current as decisions are made. +- If an unknown unknown changes the direction, add the new fact, the decision it invalidated, and the replacement hypothesis before continuing implementation. + +### Phase 9: Topology decoupling follow-on Goal: -- Why: practical deployments may want GPU-rich machines to do prefill and memory-rich machines to do generation, so control-plane role, prefill layer ownership, output-head/logit ownership, KV return destination, and decode owner should not remain permanently coupled. -- What: document the current coordinator-first topology constraints, determine whether topology decoupling is required for the first production implementation or can be deferred, and outline a route/protocol direction if it must be solved. +- Why: practical deployments may want the best GPU machine to own early prefill while a different machine owns later layers and generation, so control-plane role, prefill layer ownership, output-head/logit ownership, KV return destination, and decode owner should not remain permanently coupled. +- What: document the current coordinator-first topology constraints, then design a route/protocol direction that allows any role to own generation effectively, including cases where a worker prefills early layers while the coordinator owns later layers and generation. + +This is intentionally after Phase 8 so the first production handoff path and its caveats are documented before route structure is reopened. Do not let this phase block the first correct local-generation handoff unless later product requirements prove the current topology insufficient. + +Phase 4 conclusion for this phase: -This is intentionally after Phase 7 because the immediate feature can be proven with the current route model. Do not let this phase block the first correct local-generation handoff unless the chosen Phase 4 residency design makes topology decoupling unavoidable. +- Topology decoupling is still deferred for the first implementation. +- The current coordinator-first topology is acceptable for the first production implementation as long as the final worker owns `N:output`, keeps full decode residency, and becomes the local decode owner after prefill. +- Phase 9 should therefore start from a documented working baseline and then ask what protocol/API changes are needed to let generation ownership move independently of today's coordinator/worker split. Expected artifacts: - Update `artifacts/issue-304/topology-decoupling.md` with the current topology constraints, desired future topologies, and candidate protocol/API changes. -- Update `artifacts/issue-304/decision-log.md` with whether topology decoupling is deferred, partially required, or required for the first production implementation. +- Update `artifacts/issue-304/decision-log.md` with whether topology decoupling remains deferred, becomes partially required, or becomes required for the next implementation stage. - Update `artifacts/issue-304/perf-breakdown.md` with measurements that motivate topology changes, especially GPU-prefill throughput versus memory-bandwidth-local decode throughput. - Update `artifacts/issue-304/runbook.md` with any topology experiments and command lines. -- Update `artifacts/issue-304/research-notes.md` with topology-related findings and whether they affect the first implementation scope. +- Update `artifacts/issue-304/research-notes.md` with topology-related findings and whether they affect the implementation scope after the first production path. Current constraints to capture: @@ -943,11 +1007,13 @@ Current constraints to capture: Desired future topology properties: - Control-plane coordinator should be separable from prefill execution role. +- Any role should be able to own generation if it has the required later layers, output head, and full KV state. +- Early prefill ownership should be assignable to a worker while the coordinator owns later layers and generation. - The machine that performs local decode should be separable from the machine that runs the earliest prefill layers. - Prefill pipeline stages should be assignable to the machines with the best GPU throughput, not necessarily to the decode/sampling machine. - Decode/sampling should be placeable on the machine with the best memory bandwidth and enough resident full-model/KV state. - Output-head/logit production should be an explicit route property rather than an implicit consequence of `N:output` versus `N:42`. -- KV ownership and KV return destination should be explicit enough to support "GPU prefill workers -> memory-rich local decoder" without forcing awkward layer ownership. +- KV ownership and KV return destination should be explicit enough to support "GPU-prefill workers -> memory-rich decoder" without forcing awkward layer ownership. Code touchpoints: @@ -979,7 +1045,8 @@ Other entry points: - `--role worker --layers N:42` - Future topology experiments: - control coordinator with no prefill layers - - GPU-prefill node owns early layers while decode node owns full local generation state + - worker owns early layers while coordinator owns later layers and generation + - GPU-prefill node owns early layers while a different decode node owns full local generation state - final prefill worker returns hidden state or KV to a separate decode destination - output head computed on a non-final/non-prefill participant @@ -989,72 +1056,32 @@ Candidate directions to analyze: - coordinator owns prompt/session/control plane but may not execute layer `0`. - execution participants advertise layer ranges and capabilities independently. - Make the route graph explicit: - - represent ordered prefill stages, output/logit stage, return target, and KV return target separately. + - represent ordered prefill stages, output/logit stage, generation owner, return target, and KV return target separately. - keep contiguous layer coverage initially, but do not hard-code coordinator-first. -- Add an explicit decode owner: +- Add an explicit generation owner / decode owner: - define which participant will receive merged KV and run local decode. - - this may be the coordinator, but should not be required forever. + - allow that participant to be a worker or the coordinator. - Add explicit output-head ownership: - replace `N:output`/`N:42` as the only mechanism with a capability/route field. - preserve the current flags as shorthand for the simple topology. - Keep current topology for Phases 5 and 6: - - use this option if local-generation handoff works and topology flexibility can be deferred without compromising correctness. + - use this option if local-generation handoff works and topology flexibility can stay deferred without compromising the first implementation. Work items: - Document exactly where the current route requires the coordinator to own layer `0`. - Document how output logits are requested and validated today. - Identify which protocol fields would need to change to support a route whose first execution stage is remote. +- Identify which protocol fields would need to change to let generation ownership live on a different role than the final prefill worker. - Identify whether hidden-state return, logits return, and KV return need separate destinations. -- Determine whether topology changes are necessary for the first production implementation or should be split into a later issue. +- Determine whether topology changes are necessary for the next implementation stage or should remain a later issue. - Preserve compatibility with existing `--layers 0:M` / `N:output` workflows as shorthand if new topology controls are added. Exit gate: -- The follow-on topology problem is documented with a concrete design direction or explicitly deferred. -- If deferred, the plan records why the current coordinator-first topology is acceptable for the first local-generation implementation. -- If required, Phases 4 and 5 must be revisited before user-facing implementation. - -### Phase 9: Documentation and durable learnings - -Goal: - -- Why: this change crosses distributed transport, backend serialization, model residency, KV persistence, and user workflow; undocumented learnings will be expensive to rediscover. -- What: update user docs, runbooks, decision logs, performance notes, failure cases, and this plan so the final implementation state and remaining deferred work are clear to the next engineer. - -Expected artifacts: - -- Update `README.md` with the final user-visible workflow, constraints, and expected performance behavior. -- Update `artifacts/issue-304/runbook.md` with final known-good commands. -- Update `artifacts/issue-304/decision-log.md` with final architecture and remaining deferred work. -- Update `artifacts/issue-304/perf-breakdown.md` with final benchmark numbers. -- Update `artifacts/issue-304/topology-decoupling.md` if topology flexibility is deferred or partially implemented. -- Update `artifacts/issue-304/research-notes.md` with a final phase-by-phase summary of what was learned and what remains deferred. -- Keep this `PLAN.md` accurate if parts of the staged plan were skipped or invalidated. - -Code/documentation touchpoints: - -- `README.md` - - Distributed inference documentation. - - Any new CLI/server workflow. -- `ds4_cli.c` - - Help text and flag descriptions if CLI flags were added. -- `ds4_server.c` - - API/session documentation if server behavior changed. -- Tests added in prior phases. - -Other entry points: - -- GitHub issue #304 follow-up comment or PR description. -- Any local scripts/harnesses created for validation. -- Artifact files under `artifacts/issue-304/`. - -Work items: - -- Update `README.md` once the user-visible workflow exists. -- Keep issue-specific research notes in `artifacts/issue-304/`. -- Keep this plan current as decisions are made. -- If an unknown unknown changes the direction, add the new fact, the decision it invalidated, and the replacement hypothesis before continuing implementation. +- The follow-on topology problem is documented with a concrete design direction or explicitly deferred again. +- If deferred, the plan records why the current coordinator-first topology is still acceptable after the first implementation lands. +- If required, the plan identifies exactly which earlier assumptions in Phases 5-7 would need to be revisited. ### Current recommended path From 5c621a0110cbd9d6e1a2bcb221ddaeeae691483f Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 12:41:47 +0100 Subject: [PATCH 09/17] remove compiled binaries --- tests/issue304_phase1_matrix | Bin 944072 -> 0 bytes tests/issue304_phase2_handoff | Bin 959976 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100755 tests/issue304_phase1_matrix delete mode 100755 tests/issue304_phase2_handoff diff --git a/tests/issue304_phase1_matrix b/tests/issue304_phase1_matrix deleted file mode 100755 index 0aef66c996d84262f77807e61bcd5dd39cb66c9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 944072 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

slkvqV@MaEm{cvw%4tu&^=&ls;zt3)RS356c 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 H?|u0{KiU6P diff --git a/tests/issue304_phase2_handoff b/tests/issue304_phase2_handoff deleted file mode 100755 index 85778f335b1cedbf747d2952b2460af01a0c8840..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 959976 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%0AE){*Pp_ABTdt8#{jmh;OP!<#{WSf! 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 z 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

e=^b1zi`Pvs271Bc;;!Cc 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�im-9u>s{!&YIwO;5PGTw;f;VG{IH8V zm8;>+T0z>pT9Eb*2*Q86u-&T5h!-3{JkZQJ3^F=qQ}r--1D#h*eb)$5-z9>T#G~t~ z#}Y3%-qC^86C52_J&Aa9UG)^=1+RB>VD(f-2YR}y9$F*m=q!~X!PY8W@gQQQiwWfd@Lw#sor;RxAQeXI|LU`(@m>^sgxRJu~pJIY=Gr$cKj(RI52)7vA zSA`?5VmH5a;4To3`Ya|W-A-^N!cn)y1mT*%6$?i_7ZZe&&N@#x>b#gBoOD*6aMXV> zLAWY#nZlKUBM3JGTumtul&i@~J{HwYX-xOL!CgrlvB3Bv6JX9-8U6%&MO0(Szr z8$%lw6NF1f2OJZw5*$IezTiF)ZY(&0a8=+w5N%hG$+!SyG;dX+1OStR75rk_3w^z8S;0VGcv)1L$;39r_7Cjla19KeRc`dk$jqa5H z-x)jh<(ut%qwmeWj;`oba4&&t1?S+=q3P&V@Xss%o{2ipnJ>7A`jZaSzOC2*i}g;d zAJAMuPwYDSoRoMICNPxI&CcW+oh~q@jLcgrN)!#;JXpu zope1&-xFQOn9|R95?{Z@ld|75AD5`-P9ICYNWE=$>DUH5KFp%6^6i%lF57<5z#RJp z19R=?4a~DQ0a-gZaWDE{6JZ76Zo;*MxIWCaCa=U^o67ic7SC~g$a7pD<~TN5jcg;v zizPtWW)Y3?7%$cXYoM`4?~IvB^iKOm*t4tgVm+`XgLu6&UM$f&{1o9F1dSEz1(7Y| z7astW?bQz`zjzT)wwKb&_9EXX`$eR?w3k`-)=_N5*aAm?-A|dldFjE1Cp8z`F;cRVeGWw%g=@b6n7u@^8CH%h%+&RH#m9Zr*D!1&+Hoi8e@A*# zhuAocv`rJZm*Y5Oy#PNw`ekbzhrL8w_67HR9EZJxj;;dt8*uw+b7!2#94R)D+E4mG zs;B}jd|W!^LGHx10N|6*W1`r%6CeFAd-b>#mF^uXolhw;qU zf3fl1fua=Vle=(VDEfhM%l<(Yd#9W``L@6#TjAXosXN`Zw~01+0bYE;{5#8j9(c^? zh-|(uw4XKjLVF|7o3G!%v*%m4O+52|1~UI=AoG6)=GadF6=L z$GDUC?}Qf#s|a@yTA?rC`lnuF?mghn&(GpH)t#SD=Q+(C53cXQU4SE)V@K}SlW#Nf zz8*O=bMf$mnTv;a%v?OYrn&g_=z(Ux6-)1AK0b=xFmv+g3+ab{&3AOe4=9J`=w;hn zV0cjd6@8EETkhrI_@}2A99!4z>!|Z8>Y@-2@B_K$hbuoCxoCapuNd~e_*1!z=-<&b2KKt{=7~;$Q_;U@P z^6bpJYuu5F45lHA>BwX^WV1VcaSzs>`-55=(^SA6nasN%Wi8f;MBgrT7p5My9;U(2 zfGuEPmi>-_=mG$UD6Ttyg4$RiwQ-4=bLng5>E zoqpDpm2{qGy0WsKwOig=mhn8VmrO`TXm_)2r2vQ@!mLxlwqFllNk(RUmTX|-OE$_} z*?0yTJ=yq9oX0$+=X!*azLH$1Xl)bKjlm0?_Yy6{Eb{hi@O^Bj?y2*`8$XH0e!ijzM-*F{X?Ps zcf&`8_HC5&i}Lpe?l)6SI~LmC1dfCz@weJjHrO>LF3-N&z+8K>fjRa>1GDWb4a~B? zZeXT;xq%t>Wd`aV;IG4rSHP2(!<*yb(aY#3#<5SqwIg@qFxxIOFvl(hs!W66$t=P#`0{Ur7nwI$$y&k~d=)M#4-eJiZ@NoxHG6J*vETT{I~{$SPo8Ei23X!Xj}UfR!*{7F7%c#5y@oafLGBM*nKbM1}jD~%z<57O_+*cfYF9i~2^ z5gVW{H2g;#2d_hS6}TmF9K7!G_2M`VUUzl=Ja92&Q{}R{2fp60Xwk^y$Yz6o;mG}r zT^dQv+Q3Rm}x(4V1{iQ zcxL{K7FXXI=RyBx`)v-=&mM#K+Km28Mt?eYoO|n8UqDW`P>)Mp8vesT&N($O+kU{n z9J|)QT>HmB*9QQ^xa5o};YG z4xvM$v_lBJqBWiJ*+${xQgmb~Hm=T{4lv&l;673LcEv+YKXiDg270s?OFU9!+MF{_ zunj%C;hZ=QeTgkA9_k*)X^iZQC0b4U>08HUoO1l_CvFy z2lI`6{9XQ0(sh0~Dm}=USv(gRVD#X|&d1I9_6j5K`St~r>0TdlseLG&tY4iP_Z{Zj zw)@SwrhW450^r5`OL|c4B$>=MaXEITf!X#s24>l38JKDJFfhaJW}xij&lx}O&>HF# z^kEnDVpsHI06m#XpN+q8QBv>(eRhk>bFz`8?_vr4w(Q{}?wt0&49v1WHZa@%r-3>4 z2L|Tahkz=_9BkLggdqgY`$(3wo*+W}HQZA(jF7GSYS51!AJ$>JdVE->XK((M{<{R; z)0(wg^^6|PXU*Cl$!n^=%fLqXS7TY7^&uWC$?2H)ywv5pKakery9IHc=-|6M3@*#a zkLdhQ((i{)8{lvCO&UXq7q3$~>O=GS!W;gBC);?gB7R~#Z|N~-4fYjr96Sh};!8*W z^h|u6 zXulqDzqy%j#Lp%0^9-Inp1zT1t+UYCp7P^=)4(kIdIK}rx+-nz6>562d`Gc zvt!}iOXkrqiEgvo!iJrDD$C-obkcmB{KV1$Eljna&4vJi! z*-Tl!D4%`R{pLx&@#NqMo;^8OZR#b*{)K_r_9_Fj>_-jEv{x9&IavmNF*$gMv|p6I zG?%{n`NorjdwDi;@Hw`L_S!I*r+-K>zScJSiPnUELUT&D7`ij<8UwTJ?-A=p6?D!7P)ORHM4!`Yw^A_Le+c$w1 zQ@#$HD97Go;Vi?+yF{w$T3pkN?K~_cI1&*&7VZw$~e&V~2p^ z@j;xK$YI2rj-JChSi%;9$Kz$^bny6V?7Q)J{6;;yJg)sX9*;kc9EitjkQ4EEi6CtW z?;0Mj7o_cK1mTeqLG1L1WB|X5WaIOA{={5|=jW*$F3%4YpO9Z7&zFKbo#$n%p3d_< zg@Z=p+b0k4y!6lMJf9-mX*_QU$2a16{a^fk0zQeaR{+-p?wD|tZ#uz~4e__^)6bI) z@%;NP?-@G|TC2eAi{l*Gm;vq`aHq@0RA~I~$VQ#ffdzJN>R0>SzKCr6(*5Ra!&?P* zPvGgYk!Iqu?SO$?8yKZ)M{+;{=UOPuKs421$l9ZG1*R<IE^(F?g zMiwaF$Q;%YOePE=WD{C?b;yR+5)`8US4;o%?8(OCtRL`XW4xX{{ePY_r&iCpff{6^ zMv%5F5tROCy+958RWAtN)CeLQC4%rxgmnWo#l#EtBVMqKc)nEvArwYSa1a4G{^RqaO1%dgqs0wuW%E<5rkU|?$5$a0!I*T9k|~MHw7F) zxSim33U@s?f^bdXwh1>C93igTnDY;V_jKD5cYg8oeqZYdo*`Xgzpr%!98$-bd+waA z)?)R9cJS+zX9hgV*wI-_#n_lJuf{K(=(wew`$Y2WiALAt*^#eW%kS|S9k;tPpUCLA zPbAO&w)@Rne4}~7H-V@6;^_ZP9R0t6^#2CZ{~JjEZ=if||2tnu;(l^Z$0hD3f7bo) zMg#E$8klWA4b-`jhv|3!LfB0BIU(ZiT}j7YZDa3>beiVqBJSRm3O#G@iuTqrj;rz0 z2H2-Yj|rxuCj@Dy2tGTb#{}V#8eqNfuKgNeUx;VF2JUtG@&}=d4ORF8GVMyk4|zPZ zH_e@=8wxJ2FR1&zl%cn9UEw=|+M^0wp>WV*^aZ#X;J93}LtlVf4DKA^;3K0iz^wz< zT{!49`U2ceZ~<_g^RVc1*1|NA?%ytNc>QxSavKA;pK?2Ps>7%EDZehVQ%~`6IDGmk z9|!ZZra#KFzefFhQ9j-3e)AR6=6Uw{z~Rs+J5_BjzeYb3$DK+BX4=IDX4t(A%==uw z2L6rD^wnv8?YKKP(bk!-j(SOT|J~KVEIY+O_RSfXWBUxuwYfvwtnXU}AKgK?iZGOr zLuh55p~Ra@!}nX_`W?~}{KJo@b@+$J^BngF)Bf@YYfKeoo}yE~uzXthg}-%=!>9Y9 z#anCgsA+SJVLJSC55{qh54bP&eODZZ57_m;eLs$qf5GY3ZjIycFTm4_`L+h!e&|aa z>okLte;`U7M!ygr71-H^CkpJRq2IOXI@NcH&{L6`EG}QCX%1gbL5w*w&lOlUAjjvnSQK|yoQ;&m40D<3VkFV za_m!2=Q!)b_mP(S8~bDT#Tt4z^G+}Lb6X?iY5D%c%ss93C+$)GKR2?3F5v%PRF8z* zZwmQFdE^_IVdnzH2iKraR7aV-tNy&Y(OJ8#{g}JE*%!KdUSL&8veh$EXPvC&n@Ho? zp(r%R@QW7COI_7=_?*!35xy`N=Y=`@`edXrGt_oCD|CDoxZA*O1@}=-=q}Q>yq6o& z`F$3543;lQ*-*Y9c>`mU-M(*f&O7p}x@@ApzT;1>6J0v1=>S3Z#N5aE{L?rahq;AP z)|ff8+?E__;j9+c>y<`^@t^5kLv3>cyq{AVnZWyPX~d_qKg0QFgTL#B27i|g_`SnL z-L2Vc*{>eqf0DzT?%W-XoaUxld&1Dvd#X#*4*9A@3;Tf3yQ0UOd(Hb4Xu?N6xFxBe zF1IUZL;bsb@~QHbW&id<)qSSD)xZopY+!+n90X6!y%gEF1R1G9Rw|);48G@zP_+2f z@9I38=CT)VjTZZmrzGP1q+z|oloY-}mgaIc%?{*gN5-B2bIAw)X2srrPiqpnFA$qD z@;YDS-3V)c|gvKMI1 zMj11lHXnBU_1sX?u=7F($_hjKyB39xcJ;AN#usaub1v(gbgq%sDsj#Sd!)A84J z;|zqenB(bbUoxeA#Ygo2A5(W9P*=_9&8SJMZ}e@U-7@E!q2sS#6Z)|3Tm0jO(7vBe z0 z!@BcAAFO3f81<++ZRQ^NeLpP6Gx$8;r9y}0eaC$)vboK7oFA<3qMW}K-HVJ;=h|l& zd)pVTppMPIKNuQ(l014*$L9UPVZq1UJgGm27VfB`4xBtWd)muWXY9AvaWCL9^eoS! zBg(VM=faDEKP8`d8Fyb4taI~?mytV<;$`H_XfI!t(d0$mCa*h&2k+zC2Cu$yFAm<# zdm8_n=FzyB^V8SjyY%Sfd}rl%h_dTk38hv1A?YjXLFc;$?$29=eQRXFN~z$?ao(S? zVlPt{527p87mfCJnSCR5#rcT;A93#c9BO2TM3n6 zJ!M$Rcv#Ba1lIgE!7KP*XG6fLkE;9wS_Kml3L^!SGodZKj&?}!@ITPstWduA)PGg} ze>&}Qn09GSo=QVwBuX2qt108L&cR&raQm;yit8WD=38;y{;Tr;r>Xy{{5za<<@Y{H zqf0KcCa+7p*7(*9cZ2?@kN@Pjt>HPeIeyvHp8Cc&+iJ;j4>})quGJgaw{*(mojgJJ z60N1Jna_B5H+A5?^-AtMF>Qe@%3<~@^ZeEt^F6m!@BrUS8Hv`R`tvE%|fg2bE3PzDu)3V0EYs94a~P9Vd$+Ad&h8mhnH&S(HF@7TIjA)_egvU zY)#l!pxF~HwwXcvBk#TUO=G&Z#RL--?pivJtl_2YjxrXMNAuQ7cjUxe~^yN-Hf zA&0aN*a5us8Mkk?94dzwH9B$Hx^Ys8gC9B*2Onx%bZ30caVL)7jnjfSl08a?b+;`? z>xn~|l~*HS%F73o-x9@%8-7sXOWbf^O}!Jo z+YPT*_$oIXsC~g2H|#ToJr6E_bSP4RzDU__Mj!0Klf!cqAN#d0(-(rP3L|$3KF_!j zTmYOleQWJhE7F_$2g)eZ7SdH3qQS_0Rz&*a27CynPJ5+7_wkzeQxre7LhY%4-irB0 z@r&^fp>|Z*U(N`dfKNahe2p*Bewi@kqjtj|-xmElf$@0Pbjoy(Qzo@#A@N@zt_g?# zR3DkXRc$2v?_KH9xB8uXsk3P}BP(f(M@{>321#&9 zVPv)-Z8l2~SwGXj9J|cG6nna0MPcM2^POhj0nF!KR_PUo#5ngXe)ATk`-Co z*ekTwmwqf<&Y0%DsCASxmwSwAfCg89Pa)o)V61iL5s$jTeHR~3=3PANNGbNCMb7`* z;WPT*;JU&mXp@D+>CGd)I?8=lxYAHPjgLUeP+9Bf`!`Z%%@;N2Uhd+CgPX|x+u}Vn zV~u~tQPMTYYjqdW5WV#G#7$mCeg%BDChce&%l~5S@?qSoYlW!K=8l(S1}oS@R^EH# ztrUmW{3Gk;;mZ%Zrus?Pg^rD@uA~3!#>G`nIXr#q!S3G3Uh>#GDXw}Cw6^D-xau$A zJzq|Vt8Tn6uDZ6rHzK}LTMUG+)DBYoxa#mC(y0J0iK~7@bgP1xrcu{dn1QNQpVAIBOlNideo5D4$2gjliRU7sG*!S z&lOhRNB`B_$Gdc`fmy-3WeY=}^&oxGLzyds?*yNVd`1pcr!-rF>jv^CP5EfhIJ6Q5 zJZSP;FgGiN?Cg!)shxvAM)8X082iXB!#^lXfBA2Sr|p_sJ^tPNlxzx+M;o?8?SmHftzw)oZfjrm>28$$R_~&dHQPNW>llM| zyF8J)-JZx^`greFU$xq<=0nEQKJK;|>8sv1nz1tvnt#z_bky)FAhZ^K*%PUG)#J>E z*OJBto_F}?KJwW_SOw#6iLd%g#_pHPN%uL*P;OmT`=KXtXe#T(UTg9Y+F&p?z+Hhu zQXgIX*N%T(Jan2>@snvSE51DFt=@OkTm2xGiX#mTCF9PR~elq3yHF+-ZMCunY z_A9_$MV|e^Z=!s~!@>=I_$G@`43Ny|t@t+^%0T(Jw_~S?LrRdnq16Rm?r}8jk9!d1)<8{2TUioRZz6l{05Ll+M!&v;Ly zEWuh6ulqDlYTtHSd-7rcEl0= zUQaniQ!DbdKIg_W{g-AZxN!!lF7vF&isG0!>O01c<;Ll!ILv$0o(E}*?${`qagN*lnw&ob7zdm3=FaaooeyW1J89rS|9UDcYykM07mkR~bH( z%710>Ny$ptZq7j$q@OoivvPu!-JJf5_N`>bLHM5uU(qJGl<=Bej0fWT2ec2?0t;HU z57te=jtaZkF7T1V;MN?;38E)(zc;+J-Q2|{-uIKuc>~1>f5@B!etNLpQ(cPR5y_&_ z_cbmWcn{@gp7$&0p%AG0&U5RF?=j~t5z4(=@9cXG;hzN7zYan((yOF9>aNC2&yvOc z^$yhBy+1sCDLPE!cFGQa$VHzV5S0l7S_BhjSiw5*_oYkrYgLhIWI8k27uk$l?^W8)IfB|F8P^zL4tR$NoTdc#E>gC)8Wy{nrxi ziaFWXBZYo$g#ODqT0JC-k!#hWd)Awg9S(0ua{GS@X^J;24L7c71gcDa%7o6oCEQ4z z;Z>SzJ@4kD`4V%2E#c#C7;pt)ng=TkKeJoH%;C&`z~2!TJ3lq;s5EKECkfNJ82y*Q ze>LwEMuOlp#&i#M&2H{3eI9<#eolB5azJ;Y-$}pep1cWdIn(41)-E3!I*i?4*hjsf z;T_1L&)~s zx$%TebnnV!96NVqGFFC=);Q>%_8ZlWv?g&Ux(o6UwDJV9q#6CTb3-foqGiyu|5Ris zef3rx{YZQJtyA}qUO;=7b+vk2_HFHbZF|$+*U{dE@aprmcNgtv#|rR)W9Gitwq`sWrLPa?V+(7>1N&trefC-ADShrLA)jdn zoG~H3auBTf{a8NX=kE8@X!JT{(*MsidKmhwEU*@ChbC(}IQ036tM3k^+#1)a z=M}uKLe5KOi9Vy_j&Wq#ZK~UD;x$eE@A9^L2@_uZRYSk*jM6gt>$&=7_Bm*K5FDgf}pe@xy-$n;=^}^cxVFgDu@0SkdNl#4k zBqVCjfV!?0Ok>|*t}i)}@1F8?U$1uXrkgcHt!qku@zb8tU#8NZqL1$qX94%{R34o@ zVq?|se`a|)cd$CXXbt+;s_zv=^xt6Sc}IYnAO6Ip7ro!byL7)spH=N|v$UQ5 zcld0wy%WBz{q@f{SMkMebPse>4|@t}(8khEj((TivB>NNjCRxPO?kHFqhFGjnM(q% zcgw0U+T}D|>l*hz(Wc>JF}hX}VX=Hb`cz+VM~bY_Szp61U!S6!rk{D`IKR^J{_4W8h{7Dn^zwOYA#yO*fccEdzg3CK{}c0sXVL!9XqJ4n$jM3 zZdzEN_DQjN)RAW$^Ot(^t!Ms{hdoG5Yj@3wIn16ZtU)t}d1P8rMJ@A~+FaIyiitnS zTV2!HbCNy2$exSAcjxIv*c8I3v*tS% zmGym;HT^o;rjE9$r)~Dcw9VdcYnwZqwvi5aggR>6PjcHpV``$?R>I%GyY@|lzsx=?J%8 za$+BR@u0<=&sw9t(>%cFQ3qKMldK^vL+^aoBEK{iZtTqcsmQsxoEuO3w?i)*W!E8k zA&%x6$)xiqANu=pXCFo5#>gY!hi)9nBgwb9$RveNMD8e!_XroiDxo@1d(S76JVO~(I zGN~-a&;NkP3vOAvoTDtyenVNFjwy>N1M?D<;aGHTvK<~dM?8YL3FR<0V3gx~hZ`4N zKwjeWv~^_X2JW91&t7zT{N3=F_7I4Dm#5w3JeWN* zKlcT*E-=49cR8Ou9yiCX3k)It5aP2gQ01-*RGqml@L!I{`LXK)LoTuw&R`7Iu=Xi^ zZu*_hc>Dsqc)0rHBi`ZV2WrsgH2#h-9;55aab4WIo}vFod7H$fMZpv|>~k$%v{Y5jrD){_3H!LLR8Z|e`;_e_6WL4UY>@|^t< zKBGURW22K_-VbGQo7e=lY zWIPTO#J;)+cw{s_R<{lf9fe1%;(qAd^W4qMe#(4ne|%8#*u3B552_yK{h@el5}o^u ze{VZ<+=H}rS8>)w#DUjj0KYNq9to$?ek$Qq+UsO@>ZJW^H|_Rr+CDdJ4^a0ZHk{`! z#AB|{m?P)}vHm-nnReg~Gy_v@(t+P`Rs}n*4|vw_Y#id8LFtA~*T#VJz6oCSA!kz> zk#UoF5C5>T!i!Ec19{c4ta;E!TTO^dH2XA1n5PzUKEFY>E%fz7)-tpovj;kp9Me9| za`X$?qZqq>*Jsd^;6y79-Z}RnyX-RXzaby*CgwUiuR_}n1pgrTC{8y2w}bmRxQ(3s zcy~xywSQVcg_rZt(SME*me<;k?;vZXd}3Wf+e_WJ=emFJ)ZK&s{rM01JC(1N z*fW@qx_QnuFx8%IApXqVyk`QnMz@N&)Iy%0^W4bOi{~loJ(u?0hz{b{nR{#zba$A4 zr1M_S+O!`#W#Q-PeVFsk8uO@xc;|kMP4K=)NoUCW%zZAbtQeQzuU|$Q%2Vw$&MnUm z48;G3f%yM05dR+re)~BYJBjq6#c(&)D51B%xqA`U^S|uoL~rr*z3em1+2t0_Ie-S! zZ&7=H$4AxYO}JC%NNT{%G_>cOFA|-79D~!@l3C!kHT}zZlX&(qz`gI{yw)suVA+-% zD2G43tlHWz@I(T(6dg~l>zmhRX)E*YS>M+hxT7TMmlyr9%6b<+z42vz&72c`!}z)? z7OiI551KKYX}6)CI&W}3TJ0ZmzV0#iAIojquRA$oPIppsM*=?4lCWhz|9vf8a-Ioj zFE8SrJv!>14><^SEPYB*;g|8?Pf ze@ONQwfQOERau^-?h{K37vx(0`h-j7F7A(yvjTjaCFWr(?1?*Y<)x1<_It97pPlT4 zkBna5+oh$~DR-2X?xj!F59)*H*||Hx^`Wc|jh*6M!<%SA^ptK7B+j+q!o9eQj&mD2 zuUC^>c+y&t*IK^J*yE3s86H*E=hXeE*ucB}^#tYkZ~MBP+t&}9w$HT7fmfL_rrBi% z$DLmWrq~Y|m~202;Q8;-sLdaGH+16oVlEedio+J4`xVDE$2LD68-4ELor*uHVz2T4 zC?6s6ou~7YXY!}p+`Pvdm}>vfK<)xGFx?&lRR2#wCXM2`oF|RvDC^wW6P&wwB#Zp) z@rn;6@m>ipFmn?68#%ntpC`MfxC4IryMVM#a1NpXnb6;pT|cw?;D++X#!=!KYu!Dn zV)B$Np?F4vX+NDk!8P^PKhFuqHh#&@>;g!_-*v|+a09H>6m*il=G z?|MvFn%$VM^toTaz!dwqfys8nK+(W8^ygsubrAh~HU0d3&Rh)Std8S%sj*!C>vWbU zf$&7)B@w>`{f`gOVqfqWJVL&>57GZe>3``W4e$sq=HUzqZA?BY(<+w-+zY%39&oJG zU*MN7!_GP@!#StY#Deg}*r1kjhN!W5$neGMu*>Rioz#5p31rNx+#|0s{&!RMG<%bQ znfAMGT^7+Ua~lV2&E?Fk{2Gb}h$f($1KE6w2Ku=)@CN^AKD>-HAE3{6`sCXX8erc& z4j%p!aF?65)E#R0*>vf^=&F2&Or8omHRgvIdf?8_rZD+Mbj~CiU6ry|5Vq8uF|$@` zpX&H&x=DsDUafL0B%XY;!|%^|zA(3m9y08Bk}T=QZ^6VEWnhmHA)D1+6I^a%IAC`djy`$|ukf`dfDr(oeQi-XiUT_Z&Qk^Fjlx zOJ(cBe&+};d#oLYG%nJ6G;BG39m;aq??CPqQC9WIQD{UoJd(DMPB|L9=8iu%_*DBk z7e8EeqYV$`TGdD48TuzcnC3Hwlb{*1-k54%15RZ-l5RzM$`&gd{vlf|&L}1%Sizpy zG5s4oc8NE$J|7#=wZL7?<$oo+e!1TowZxZPKLPlNFL@L8D+heMOWtlIuKanfZM-71 zVuR=XW64_g&A?VkzSxrOa?UP?-TjP+N7irn$)|3-9O9{cKIUxY zQl7bq|6Uy8>F@E^_qY^$ozn3yJ;I$V`re5BDQg5(QQHyPe82zhjzP2TMY_>D*ME6| zXo~ZOr289qMC?Dz;qWt;8@!eK+1n7tn%I`Zhp_8#+x5P~jcc@Ct@d2Q`-|uhXZ=4h zugP9zvht#RcL=6q18(xpur~sg{|xd7;|sMRzh%LpvGJkEo&HdGf%Q5om(`-3EbQ2@ zb6YJrthwM8{?k5B9{(BIy0xe`x z8DLdw-M1_IKf>kx+^miD*g|`Y#{R-T+S_~E{r)rG$Z7clT-}}jBx9C%;|@G=+1$l* zy{Yrk@OP>5b!9C<|NnvbqC1tz+p;KfJ7aR^a`6=AVeZ^Vy6(${Cb=sCn%qTv@oedg z+Y?o zU5Iz2TZ|kkf4I-#T=Wv(tUf!7@%6h)x(@!CslVzad%H~P_6GD(H0lDvgyW9n35|e0gT?#bjjV5mk8;A;0fM*n=@wD(>~Gz$0HLqPS2^3o{$hTSLkl$3dv@!kdm;K z@tJLZ&*jrE@vqKViH^LPMUjb&J!ib*A34#{A;yAJeW;fi>yAEwY;ec8^ib7lhZ`;* zmpf?}jrBezEW`dNHjK8qov_OZJA~e3^a$U>eGbB_G6J8U)Puc|$%h!v;zgn<#hVQNu9&eG_BAuI5_{_kAN_8|;U^aabBWWq zp&4_^Hq0rp)xNVG`b9E&Mhf~yDtclX{sx)_r8~&qfOJKTN!?}Kz?hW3c&Y! zra*Gh1Kl4_t4pc9mwnxjI|St*NZ8C4f0-f z89-ZzM}HrjS%ap{`?$D5#iK3NPrY2+Rl?;vWA-u^*HbvdFEi}R!R1;x^+#y;<ow zr^3s!ZTW}ZOWAX+wE78*UD0kxd*zDj!={A4PJ4p!-JNRpT=St zdd3oOdi~tX7Me{R1g>wL2E1lN_Qi zcg!iQHhRguU8r}m{WxtYo#cqClN8ZD+K-Ku4ThcvcMc9nz{eRhr7@^~dl6T9$>oBy zMR#DPcv^XLcv><%Erl_Z%2-NcOr>M%zc{&qw8ey(R0XM1Cg$AFov&5hm?%) zySm1XtI;*!Ytn75f}dsaMBry@@>vsWZnc}sx#=l<-@>E0N@Zu(J>YHYnQI(^|1gML z-jr-7(JrEg)+#$~s6KD*;u3}HE?kc7adFLrV~(w{cY=5QYYC?|XPh2&amSU1%M-RJPBe4=!_6-GW1 zyqNoc1iKeTwh8tsjC>#neZ3BpEHeM0ADx_fGwps8?LV4+xRL(20iHGro;H$os^*5L ziJ#3yC$ZsegQvY)5k?fm1uW zJaB$=E(g7Cw*1`;z5anR+sOW7j3K`-u|6NaVb6=7`jYB5;OjZpmtJ2EOz@=}o+$s% z3BIIF{bzU%Y{1@m3HS5P1&Tke#jlO#s*)A*V<6tH`%t78h*$Rck;7viqz|-@YPqAJ^AU9eNraLa$97uqdCdR?PlRU47TYFxw=Un#?)(T5K^cm}frOc}* zGS8MSn65P=Xhq|v(QDN+ZxpSYK1%i!8ozxSAGA|wJ^j`3-tQWIG}Ylfr}t%#?*w-+ zCa$6{)gBKL=gA^((A2#d>sp2mtOM)X6*kPJ|7sR^gD;MA+992G5WlzZ3nw1@nA^5( z!AqV=pWH|pcP^J4;GXA}j{f;7IPth^fRY26$0~d$wBL#M<=`DT0FHhe2<~a&j2r+* zU)>JwwBId{$c{Pa!Cvk<)Z9DO?n=8l z`ar6E2ko}wIU_qZ7md1vaOURYW9PG}_NopRZrZIB(Wz*(T})s4>2vf)r?1z2kN^F4 zE8?p^wRRw=G?#%pN_*CPTohWuyY#%@2~ze71Jmu_0$;_3^;`XPZD?Wq3dskY_F<$q zN7vkrp*OqhAXQQMa?SVIkH-%Qwn!uX&DeQ`=Sd#sv^{=Ip3*hUzKf%Colc{xFA45o z9Y}n;vAsh(WB5mDDZuO;R4N7^}khk*Gy1_7$PhsRbL1?+BfvI-mh8ExIw<)UQ zPIPr#_Vmxrcg1DF8R(h1_e#2}`1(ZVqv9cyakc8)+tee~)I;^U-2FZ$&wizQup@2w z57Jv(%DSLg?-T#jnqZ1uPQ7;B?u_e>)J5a^6#rBl?ImQ}AGvWdh$B9%_DH!9Uf79y z+Jff0wxFFok>l8U9>>=6IQEPk zcQ*@OAlSLNfejU;v&36nGZH({(fl)(XB^K2Peit_wVmUg|L%0*b1vNNz{WYANW%nA zb={r#1A5uQ-&cC*_&pi8#pZk*{)P@M@l@j%@TE|Z?^yVrEW)xw4I7C64)J#@etU2o zLXFt0J~O-7%4cTBtsKK1U_-a|1)NRBZ&~Zm@qL{C&E}t6{#hVgJ8;SD{iTNRe-LTt z)~Y~z1!49oj_basZYc#dqxGG{cZ-mb55w6{m;~-)^ztd3Q{HaY9ILE5uuY{;wZ<3S zN2;xuSuOuq3mZyV7fz^u<1%L-$?)qR42V2*X8a8^%=+R9SDuVRo<#Sa%s=hX|M|!0 z|IpB9yld^DW|b#+`41g>_#Jew@mz>}T;k1QE^zi8O)1E)!M>Cve=}>iKjDL{u+JHT z{yUsBen}dx&WX>T#Gp5!FfsrhxN{darRaUpJ+2;xFJ{MXUZQ_u07zw_spnXT2$Cn zt`n52CSH5(rPC1nR&gDL*9Inq)?nFE-eU-!Ls%kSgPqoo|%5xugtFk^- zIh}o9>D5!+eP8A@hobqPw&t2;&rtr`ocyH=>+Utv4sQPMo+JO&XW*3oi^~7Lvg)S1 z`+s}hw~@Da+79aSJ9y5HdtCXrv z`!BnAH}V!ZANi(v)HltcG;fN%U*e#s|a?DjW290zF^zqE}t~TH%=&O*QyzdyR|7F@>2MQI^&C zVKlPt4{q2?3d^@5znQ+qtV>pbPdhq&tJW%6SE+vknRk@_PWNwH9G;n0QAt^jq6ZwD zFfgS33e|%-t8|7f2OHRLpUp^lEjnlXK@o`q~ zOX)gs+Vf^@_z`TP5BpNP+U%)aGwnmxhZE{|&>rtjciv}6A24gjA68U4>&~aA|3S~- z`eu$E@}F#{en;Oc4jn@md|PrFy~C_Uq1R~sHdm1P4i-ee^b0bN+(?^;r>8OwJt05& z)uWqeZ%JcIcD=>)S@`0jkZ4)9e45YYGoKAl&!|v%2LG%w@ssT$oHjmj-9m4S^Yh~S8xUOKAfLu z*0hi2Co%VBjVZrnsCI0tP#t40+^scdciV*O$fqtJ-=JgLg&HfIxm9Xk+0>yk(Uwcv zv6eu2j7++4h>%X1QgLv^|;zs*P`ndj6`zxO22+5u_{Fo9SS`nYTgE+6bedRqP z{uIWqi3>g5PF(4~ueyD9ls=11drIOqXU`6rn?+pds(&_d;gx5^jh1%>@xD(y@zz~# z91{k;zDZa=!sLIV3-8Vyh;#cK=_TI7yvE18hIKK;Kje;Ot%+Ss`|em`_;yv%tSbml zxBpHbN!M50>9o7n_?`8!bo)WRMGyA_yFyouKJjS$$KILD`brAxEUB!wux>v!9p9$t zneJY{_Rw_KddzzL{OG)+TM=h4;>{VZ5x-$?{Q;g^c&_3}2Hybh9-@31gR1*2lwUM4 zUO4!u`0;2LH&!^wO7!3nF78I*82931*SWai;6#5nmaeM!z}TT?*a5=e2ZjgFWGtn! zR#iDOr9x{ve)rt0&tv8s_*=T7Xhj|dYe5q-L<>%YxdLNrFGaP z48|_OkKZlrwTYi<|7{X=yvz7Mb@=Hc)8z{_q5c#<{ioS~J1dWkSDO7d@y@#EJfV8c zbEwN;ja##(1cYyFWGx>b&8sV?Cs&B4sh=9CXBhsH>-X1hfNxYzPpgp5nFilepM6ER z*7bMM)*5SR^0P<3?Q!wqXJ?h?sjGq;RF=*ILI*qh4Np6qpAf2pztzFp>PEH*)st5E z;+CQA;;+M6h3fNLgU1KPJj2uGrx~7>X8)Cb8<*U~)8G#|4v4H;)d>nd$BgZ=N6-V|cg@o1l*u#de4Q4GUAx~>aaR*YRgL_iV zzMwzhpNqq^r^Z@mcVF>&H$Saa+{PH!xYaoHxqR*haAy2NtKugLJ3@abekaC#UlX2V ze;gCOlYSaVSWgp{ZGS+R_D+44-|)5*^xsbU<96am{-_V62MwN@JJL6}i^Km2pGEkE zZvGo$( zw95|salL_kMp0#-;9>9zTS0qAdDIQGnRt};A;t4GuCzy{cdcuVltt3S%#oF_^|!gm+D4t)B6B+|@CoYxA;C)BUQhj@iV+8VXrEVJ}f~ z<^k5;NAXhAYX@%vCc_7#mBxU96FnHiwj*`fpDg6lI=Vf*GV{+ z-(|bFT;UAA%e2#6T$XU~yZcMmR7kHBy`&SiF^0EAb;~a2;%(tR!5yq?Xg%eZnXZlq zjU4A)>rpsuG5qYPAaeAuAad-WAnpDMP%_lfEu|~oM4OJLZEvKFZ=kJ5!QV#WH_G8} zQC;z@vF`5|Tu(VZrJtlLI{YpBEdC~a@p;4FzFA)+{j>Rar~W|?`siDRr@-IfUD5;R z(k{{y2MaR3{DRbdqxc?eF;`IfA-q8Pq4XS$#n)+j@v>9v`&srYF*xzTSRGNcTt&Fn z@eLnjTuRpyf3#ivIrt#!`&JO=Tkzz<(BaMru5Rb@K=ix1u`NUO(hDzc6)I5qI=2pK zjjBE$J#TDVt!ZpFzUx>IL7$tSZg^t4{V;u3dLEwm5&l#}uQQ3GaV1&z3*N)e`&F0Pkc;N)`!ZiC4Xh3?)4&L9SO?Gg06JEHvsFT7o?AvH(hYzON$+T5e zSJRrZ#$OaFZW7_@vjkuZXy?Q|e`YLt7?WPcrjIci2jAnKhhluv7stPUn7v8vETmtZ zyUk_8ALV~qe-hn9b+|wGhyQVIFNZuUxV!FNo-sU^^ZbdnJ%X>4RnVh+rr6NIkAd2k z>C%=vqA%t=i1sPjhu8m&kB|TAR^DrS=}fJ^-ov}r#@@}K{6>#UwLhi~qL1yuAyY&H z+g#j7!kM;Av)^}d{}j&fSk8aAxXr@BV^0{pGRJ<~#s5`!!)LSY^)Bu$;o!4=UuJzd zHk`Fz57=6eI(lAL_J35)YuKw(Su5FVt%HU&x9sB1EyJ2iLXVY#(8feTXt0YQv=)Z9 z)S^e6FnVaJ{Q`N)?pt;uCulQh$N0@Ne15v!9N^6@$}0rGM{3 zTg9WqXP#6zV^#kY!-vGHgWz(@*y}^rlH7kRCeCfxh@QcdH(N`+X8k~W8!t$iuQ4#kh8|h7|2{N2 z5L#tEKduPc9e^BpyHfWotS!$xwqm*VCS_|FwY$!-)7^cr8%RfMn-=S%l@omL%MZfK z7hhO_E!yThe0VPPC7-y4y}eL*^08XzGc=_~=rv#Jv6stJUs+q6_KMb^69)K>$$mp~ z=Fsy!L-zB%LUs7ze7-#66}vd|l{(TI(6{KMXF&54^<$v{zCA6m>nNYsM{Di1&ol3S zo_Y84>@U&}wWV&Hwq_45E}K%dt#g0%GQ*ov?Lwf#-w31cZYO?)2}`ki$A;0rvk1dk z6@8m#Ultn%4XhySF%y<-cZ&^U%)Ck1Y;cF5S8sBF8G-EDxa==!d3k(ls9F;%P z$H>mNSPRZA>l-P?t^ye%x#a8{X4pB5A+@{ca5Qbd<3(40y+ZfQq}zw-Cx>Te*uQ6d zh-b@BuHPL~8Y_u0?>ZCQG=}*9xBMfWZjpgm_7lK@Z{z2_`1cQrpTifmW~w`T#LsnS z&k6Kdjg5)sETd!BdUZd}=(ezW=q%o1Y?vP68O_t3XEn5Z2-h_!A6a zZz4YK;hr-6w-!GB4E6@K^t*WD0N!s>nGL^9w#5s?!%KuSygA3d!^PbtoY8+%Z1Doc zyInY!FOPL`xa>DOpZi!uA$nfeL99~UXqP&{5zEPUf{B=>7RV@UU=dv3UV zL&H-y$JldJSyj!xeYWosw@s(=20!-tNMmUO>$+-qxiE^V>K;ki|3@?6d5 zLt}e{{shlma}J(+9)4R@2*0(&Z$}zlT4lj+Ysw$(BOYD*JZqgU&y|0F#%-15@Y*U5 zytZaeym)PuY(HuS!E3QU)w(CVw#u5--0<3K-1B{JQ5W&lb+V&i9dk5yEYVc9L^{4Oyhu5OFy1aG*xCmoe=YXBHOh>2f#P=7iIOC7!UGs5ysSeCs$HeKjUeAeNAX-&LzDRDIp{4Ou8LEjC-H*3o0ikDVd;-%ST zePx4j6xuUumF159`>vr&`Q}Zt>^+fct(1*R)AX}V^@v_(CVeYSakJo;Ucx$oi z8Nm3*@Adm-X@ysCd4WR!U2_=RQwR>kq1PmMJr5#Z6x%+W}y1igjQB`eKwfqR+nzYXy)I;ra!oW1U0jTv9&F`JL zRZ5- zAKT@oxxx_c9_PO@)(F(r($mwamuNB? zN99ty1H@CDJl0ONpQkusc$fEq`_Z+M?VAbbUb5hJZ$^C{cateCwNb7oy?!0vO6L*s zKM2k0{c+w^w)qAo+rI)5DUc_EZXXYa8P5 zAJK|_YfZnkq2K7UsqGjKaps)ZnSJ&PH_z3Sc^&IsOJ!GwKk+#5g?u|Y?DvA`;0xEW zCZ_+bf}+TEd}~}`6SKc)X>RaZc#7)2jC5!(##@TrADr|P-Q}eHP1*O#CguV9K=g0~ zUMQWCdj%KXz`V=!RXKfyF9)Ti@wl^?{+S@Yf<8#wKdy4pN1}ht#WSLPbVj_n#8aH{ z^bx$n>7&-_qX&!)+J4gRO&>LK_RsVYX*qqA;r0=0c*Id3vG2X5BYmtgbOxtB8%+9w zPf{1bPT*xb79GQ)9o20c@kDPI5H7je9{8?F!_r>d=8l6erf%u>{q&vm;?^cC)oy8E znw?}|ik)C!vKuZY&sM;#4)SY3<_l;)0ilZWGF zPpw}>(1Sli7d_Bae3EIK zxsMhec2d3ajLpD- z&wO(i7x}VT)7Sa*6kEOoe@dE583z%3g7uGg?8VJk%rGHUBbg<>gh$5IT3Hiq4KR-;#d=op+AP@2+lIT?|aMF9K#!u4L9q4{;{>pFE-b z0igz8cGre_Unt_s>>6QCq_e1n*yPo4e(O=*k9BL#9hvcrPd|GbkMybQoQQ9Wq>$Rk zx(fSX`fQxfsvq3FY;gi>9CfabgK^BsWVbwyHW_?r+2UMJR=xjH$8Jn#-UmY`=xpz2 zC49_Yb+SF(-Q)67PVqx8X-m)Dxl8kG{O+`M))8I+cLn7VPBf!AK_|YS1n=OmGp1h$ zf(wEhT*}>iteIKHuf@zhI@ey~o57yYDZe{|49`lp{{v0P?~XH9O%5hNJEhpz&7e>H z!NN$a-<>h;KY!;R<+}-Zr72gcz0u%OY|)tN_NIYZ@Vw#hyzAk4!{B)V+Vncsn67P- zi;cz7Ws<rUK1xOu){V5*J7KGWab>F*St!}NCp zecS~b*oZHqtL_UepuBnN>tuXP@?M7z6LYs=e)CZ6o$;Xo3X6|hY5XCu2RfDWBI6qe zL?-+{^m&$S)@h44x1Z-yKFOKeNUy*8d4sc_;%npd^JUE|5N&%%kv zIQQgoXohxXeT9G3_Z56cSo0jOK6m|^)Rf2iG|904YQ{x|J)UyNp8=4>C}Fem#9SjJ^!er`OT9*V5-h(O(^1sL|JqK5qrS zHQ{ZD*OvI`K~s~lagYuhPoFz}Ob#>7bv99cmgLt!Jn$0o$)=q?WRAFoXCY4|`a_6w zh(p+)>&8=CY*n}5E@QRl@nKf=W3`TV~p6{t7H+DyLk(z#j4 z;myD8<@m(#n|4UGn;V#J#~GMuZ=o%7EqKBu4o`^E$3yPkjzv7JKh7kbm!Y?vKIvBY zym9wtFg&KuHJ_7Ra)zOeC)_a^ZWj$ZMI+KxC6{(Ig|Y8VJKRqF=a{e*`y;}bGtT#9 zuJ3!CHJ%1|g`uI-e4}7{Xy_o*exLaAhjTvKkuQev@D7zT;Qq7T&3`S>q3>k-HG`8c zjFI&H2xwq9v~WE%F$`KkFY-C(BazFt=5jmP_YiLi0UOJG=t=SDN$2;4qW)NXC;kiI z0Xh?Q#NBt6&Hh2?$+4U9+F{o3R2S=T5xyO*)g3AGgM5$4PYxC?V1I3a6$w(-G04Rw zcX}hsm|qw5z@H`SOC2fKwvmmCjO{SrbBH%q`_jYOJ&;Xufm`H>ns1Z-6pJyRg`OV4fKTs(p0&$p6Is< zYIy^c!g9zCk6;Jby9Jld!L-L(LJlKp-7Tk`yN@pvD$r@hB_VEvD~ zsC^-SVcCfAc5mqL$DYu^t?n6$jU9um$wywNyc2!a$%E9Z5Idm-wBbQxN0n@kAV2Z5 zd}O=&q$|+S0e&C`a}Sky#|K1P@R5^^t3?AU=O+D!U1c3Io_ZO-5L?Lyo67^bM-08; zEWZ%K<^7zwEA_pWaUnhZ3ewU3TcP{igYQGEgUrQlnR6D%IKO=nxKjLC3a5K|{k7uJWU&(N@yYHWw|u2wL#lV;N5>V{7sk zk9t7mPnM3y`X)4`Fu%%6*izG;DfZX2K?FWOhB_%->%yYQr{JWM?ObaGmvc^k7H7O( zA0ucga8QoN8Ss>XB*ZgV)?I`5bBd)J@|x;)w2F22O}gWA%k5jdtKQ z4nsiXJM&uB{|yfN83WVpWd^3&OASo1pEfYre#$`kx;y)x>qeh9_;6eKwD@L!OQMU= z!K^DnyRxoWyCLiTrK_^8NMvl;-Fg%}vmx`9By_|2Nmg|leY-KMD6-??IAo3w-p0Ky zrJm4V8K*-EGJ_5sbq>~X|D|YYqf0LjQAW{{(Lr2V`lH)6KPN1fmL~BnTACe0OGCkl zmX;0jyf0dcyR2+P0ckHAs(n3Z30x;|n$Ij7b_zET9P3^SmyJAyyB%DXaHCJ*W`Ro; zZirv`z1Bnb2jX&7{Q{ z|I|k`-9-1@t;lEaS<$X&{z}?Ldi1gGqQwmRBI3)2PVafVH_<#iU+Wfm5XVSO29BGBCj*~ zq4XTJ*PDdJ((s@8K9e6V250!;D)^!3s~_hN`TsP22yP0vCc237!=+t=X{2b)BGdi{X^0-~AUw(sZ{uC_@$m+x+dnig z)xO0*WRHQ#_Du$!pC1nRHhN&6B7wcKbJN3x!3A!g4ER)_e%$?Z8a?#n`%HRB z0~bpVaXDop4)K31J#+%M58T=GaA6ZYTugW@J!F$^lpa!fKNmf;A>xQ0_5mwm(`bR8Xy{>xOAkAM zQF{2);L_|*3{1B_GBDNtmx0*)7?^B-VBq=b;q})4Z}Rb(<)>t15;XHXaxy9(>yVE- zPM42WLk8qXK2{awUDPBWqx@qvWpw3ZmBX*`3E;NPO2T4!%W}SB%y`Tx6;S4@^J;YTZD^|k8gq-EnJLz{0yA*<5>9^cTw4h>x3KY%01-mo8Sfu7b7#{ zx|EG57A{6+b^_N=xEPr^5L|C?u6(TOU7Ta&NqO$D-w5jq9CR}M1 z14Xm0Y?~jIk59KcjR&5VM!lOxFaDE!ybLH>Zc4+IkB^atUfaxSdtHLnHqg>)JFKnM_WD$-?eI*i?EuR&^ujo6_(gtec;^<@ z@a}D_;XP8U;Z}wfEWj4-@(gSEkn^bh^=m(E2crq(vY3}{wSifJ&e%32)*vx3yI>P+ctj9|wm-hH$NwCAEfuD7_EO2Soh(IuBav<1jMxWiYo(;5_ z{cK=mN9%xxvJG+jQESHQY11XtQ*`p3yQZ2lddS~1>zRPJIp@V^EerVKtzo`d%L82# zra%7OpHF|h74`!cQ}+G7mYXJ9o}^2?-l6E4`#XKGuJ6Oo#kZc#Idgq?u36W22kkhY zI<<}S4AZ*2Xy_lF*7Gc@^}JH@M+S|$o&J8Db{SV@O}>rw8{OT}g}9&lTG?OtTG$J6 zRs;^^JQqlvwK|YCYgJ&;>}LY^^Za)9vcQ8p6|7^QDqCJpatPA&}PVrIMq( zZ_64T7|r_?`p&v3@EhO*JQ>+H2iA1BB(RO=C{IT2C4n_J^79bI;;pZ^ERK?Jg)h?6w0-b{1$e-wbjB77qBrE>@3-5n6&I-N_jrI35s~-q}%wwOYZprM`r0~)$C?i39bm-yGYChC5&7{cJl4 z`EZnP>DV>d=-$hwmg2D~_PYkA+V233T?jV0AMmW<`H;Od_`lYPs{D5pvClyM?8~uM zQk8eKD57^JO;FFSjnb320 z82+DSUrai^nV+|WhNDnxS2_dZoD)ywALdHPg*yX{i;yF>)|OOerOTQ!^(efr0AUiJh#Nkf6Y|C4j+%4v7)wLdee>ZzY*TS=E;6cwo>!t9?{hgO& zZTGb7woi62)5d>wpxKhFyWtu4z!&y0@3{xw(8k-gYg_2^9gk<|0_b&$x7E-?zSf%# zLyy~-SHE$=`o4l2E?O^M*ZN87{1!Gu!o8ifzV8?8jhOciytgjvn}(jYnea6B_}>>~ z9=1i0`QKLHLU;@D_kYNf3g41my8{_0UQ+$pJXtd|2>v;Gvw?*HeKoc`4%nRBX3vgZ7`(@bN|2|&2^|;kx z=tJHPNk8;-*i`CkHfd(}F%Rxs@I;n(Qt$hFCt1O%@z(IC;;puy#yjJsH~xq-<1*)s z0XHV;?W~{T@0PuXEn_M3jqJ6Qy8IG*(k(^cjx!EVFdpwiR@{WFh|~{QId;zeKp&oy zv-bx&0LRTa5a_~FJNrN&5jb?tSAp;F?4A8ppcU}Fo<~dG?s=@_i_F=)M@ru5*-)}O zb57vxj6s2SdVXEQ15aiDATYbbj{^M$T{Uk`hdTom z9i|4J>hMtD?Obc+$5T8jd(Sx-$ly6T`(R*dIc>oEQ|0jFNaLur$WZG*BWDR((q}D= zzfA6%SUsC|`H;H*i#Dk6=FI!Vlar+SyrX($P>(LRwwj&uqgGFsmTtXhQoj>NXMau} zp9h{ww%Sfjw*L4G^6@x)tx@TJ**NMGPj*tNFROlM_b0M07~AK5`Y5PAD#fR~c=es| z>PMlkddAHj#?5@jjmCt=&H3c0887U0XuN1#?KI=6O}7J#tK8}1zq+LPlB^(UJj}TI zoVCk`i8sh<(={2no5I*S%y^p5*h*t;ah_unynk~W#+6_@#?@@b)qKWPJmW*SIL6gy zNo9T8FqYazag49e@X2wEaoL8kl?=WOV=G0Fv86GT%KMXyFV@5MFG8kgAj7ra@YM#- z%INr-f-S{VUkZMx8DHtvsHZf(TB3U*$J;=c{h`a>GM={2aK@Y$oYw9s*ZwTV-Blm1 z>$@M`xRXB2nf2#D`&q9BemLiuKq=4QIm-ff@eG->JTQsp^;Qz9-Ml~{cW0CLCM2XPa8u!moUC_;@Zr+-jk5j zA@S|3IgD?$*&CiVNk62G{v9*M)oug9?PQGa_qDahba*L{-JvRQ;%MQ@zc7xM@C@d; zi^pc1%;UM1=Wd=q%sCYJHP7`tKjZ1ttD)q=UdKyjWjq|Xu-A!_UcFA1Je#p7Fe~Hx zeAn_FF8Ms`;XtomjV1kheU0Aqbl};H(R}aadr!%S*^2`GdexWo?^Q>eF9{sY`eER* zUSE}5(rbT7o2vJm`XXZ*{mMu%*L&fz2I$8o=&j<%nX> z%BSWW4ou}4!$W_xeI3|lrZdL-dt20hwPCQ$6nCXUrXHn8pv2bIW>R`y$)G=Ei!c|vULc1hS%VO zVK6dx5VH5`yZ2r7eSECCdpqUd?3-HmCTPD|XY0>pXRt8I(QO_#Fx8$9)c*5GYz%tv zRANKez&Y`TNv=&vzQrD#YiCeCtIs36*Y0W-O296o_POSvhTZWY+3H>+{PG0H{$RPW zHJCrX|A5F~bd3L7`;r`EUy|e6mwaOE4!#)S*i`?R@=7M(M%o?GkDBZbT>Fv~aL&H$ z>2?QS8(rsgyMqWgV_(8LY1Gz$`8c-6r`sC5*g|cVVSk^zU0Varww-NX5^HPlhWpRu zrkyiv>^R(VrP`MmT#EfY1C#CV7xihMttsTv*`Bxosg2;sfg2;uhfD4cb=v$i)!M_EgdY5$A44;pAU1I(C z?%a)#=kR>=+AS9m_6zJ=q-XtxJgdp8fpSfyOwzj=;Jr_ESRI%~JwNRiDcRodnBgtk z`yDUY*slS8J~vP~=jD>noYzVc`h-gSeJV>DbGyLX3j$vw1EzPF9_WV-_9^A-J?Crq z$=8hauaWIvqd%+(JT+%cU<`U$N7f!9MAR5Bq)g?9=qHxBmxv*d6d@>0v)YADfCE_7Hm5TiH=P>?_*wE86iZ zR}cHDNe|oZX;D9Zzx1$H=wYqw7vakf(hd-^*s~eb0ls`k z&K*VvyU^%hpOOA&XXs#U>|FSN+1|!ceJn=@`?~w=tbQ>%*b-L@w)?FTi~gx$W7(WUHhebMoQ|B=^)m)pOWQodSyS6QlQlKItIDx45}eiEfe&|d;Oq<6 z_iaI*bKp${@J+K;#XPbd-_f8hkP2^llC`Ml{HixJKBnK1lCk}cmW*K@ zG`8Qtl3V&6Dw)bW=e60dl)OH>x}<%d*GqExyjC(bw@+Y9Zr{Lz%onpdJQ!Hay4*H+ z!9t!XJV$vl=KK-f^+&T#Hvm4xnxnhknpi)BwUVo;uhxZB&g&+(Z@1Uia_B#(>w4-c z_y%vhvUMw4UU>;M#@*3x1W=_I^ia-iMFF zap+*;#iy?!(dVqoot!!pIXVP+dJS@QF!FT}I@#6eWZy^b4n+PIqmvcg-RO(j+vqGr z5^-DbPfPx7g$%~-6P+#gUc1W^tc9zw;W~VkRo#>Ebz~6t3*nyvyRetS8+^w?_`-e^ zeBE<#A$)3v4r6a||%%O`UzZX z^b^@pJ2rQ+*R{{U$zJzagG;fG`PrLc{l@rSFQ3^*XC6_P*$x;?I*6z>adP> zPMvBk>uTfSor-(6`%ex3==)P(^qkSh2B&jI!)X5i{cs)qaV>p^t)|b_pEg+U$DZ3# zo+&MhBPr|wt;256y0?FDJn3j3PVJh?yD8VL8A14Uq?S2m)Gp26tPp?w+=={pyWj%W z`hM&!?2WDThWu0gi zyh87sVM(XGR{^>3eYMKkkG9de;xfXuZ^j)K@`Y)_dbwd0;IwD9mHt*7?IS$~ZhMw> z;4b7=nEL5lsf8`bM$$i$@7CiG=Q`q@yI$p+Z=0KLM>pMv-E=jle8I()fs>xDbxN&K z%2reBnmL9>GVFT@SN?Y^f6l_mcU&*>R9(1toUmm3M{b;Ro$YVLRz_$06~B@CsO}Sp zuRN8`1w4v-f8>*CUu*Kou!jJ*Ct3$;;EhVR)=l?1@M^ar z(!AGAleg6N7HO| zdYbRKX|k_GdDHDYrP@QbGKmIu5~i|!2wVhT zQP|6F*vD>|?q!g@R6cbYZ0HgDf5H^^DL3wBH||?8={(_vy?c&ydb;UU6GnUWS}K0R z`L=8M9uI#}+TV5CPjSMmIm~4o>D(B0hnqdYV)+1Pyc9;Bjiyf<>YXzUJ@tQk_x}*M zXk6KgwKjRD*^9xKF@~)d`Uk(qJ7rj7zVGiF?8>*rIXk7(-R;{&;M7*{Q76MV|&dA~nr{e8%F)qObsDc&$a+WI8H*Aa%~Iv0Qg)pWm;@nC3d?X1#xMDrbSoAKKk4{^^H*if%phMaN%ugXj3| z#l$Uy-tPNv{<%NF{PP%b^Z4h-`sWPU70oM|yz&XRtitLF>f%=!Qu_tbDMBXyhb}QZ z??E@M(ZJ~a;1+SMrG0{*G@=K%cZM4ra`3~`ar>?BSh}+(Hr{@#i#Pc9GjaENgB#Dp zz2=i&zSIA`Judi{GjV$ozlHqT6}lwDT~*L+m(lw&ipp+3J?mYALd8Ic}+2Qpf#L zcguESJ3FWQ?Cw6+>2r?GLysiRBq5Lhftv%FBrt(wV1`RFz!)yC;R2tBVYo~t0|qkO zd^`f-5=gii@bJ15aP0f9NA11#>+I7~7=Lb^+EuGot*TnJYSpS$RUb~qJ?VY)Sihf+ zd*0ps41#uU;YlHRyfkcVF{< zoOSg6{dJGM^LvS|djU&yA@1>Or*7~69rC{=mH$(Sds8Zo@;<0}$sS1eh3x^3J)`4& z(s#ZQX><5L z+`EqUA4|vGc%*-+h&I^7{t|Q@)poJ^DbtR%)t@1Kq9FbK=!?%I{q}-%?&oiReg8}U z-23D%wB7N~y}o~qkM}Ym2VRwKi%%TtFC=NlU2@Ou&noSX=dOGD;qRSAnbe-9jh^(r za!vo9H09!i4|Sgn!?J|CK}O)I@T9%BOULCPaOvzz6?C`YWQAUhq;m3lIWwhv9`s`)@%taogI)%>LG_`2`4;>|^?Bus`j2a#x8v9L>7Rg( zpFrF*&>vsue|&k5_lfo!QRW+e{1yG5{`@l^d0h_t4>|aIp(hjU*vh*Dues+JNr)nj{0t3 z`+xP${?7t#3~;V~?>1rZ3GU+_>3{TVSsjgdLgm-vx4z@W{af&TGyX`X+{0z;bfHq4%@#p&(7t77ZZ@v2^ zeUIQ%aE?Ef&mO<_`(ECE2VnlD4DPEh@3#T-7@M5w8w#$_a~9>-=_0^ z?nV8ZkT-#E?~D33q~q$>^-c#ij>cM`s&juG`WmpgiU{|$iY zrpl$c$o!oq#mX#cZ-BbsgdQ9Z7=aNqix{-*&)G^gQSVBvn?w*C`QKIZplQ8$-9YU*zDQGcb&c@%Nf2e;E2 z>k9|^hw=R%Q*hTkasGEG{+B4;i~-__V-Yr~gV5cblP^>$G}9{|1xJai6)d|I&2a=U&wxF>$|P$SLbq2p3>0buS1^j_`KJ{hP*X=*De8IgKe}T9+ zzWbZ{Z+M4y{)eEe-tmri{LX!~bN}<7;|=yb&{d&h(7RwyegLq+CHS-eW*#tatZn01 zg!ex_aLsol^w}>T#5)I&PrL?t&Gr4Sc;1KZCpuwQbM_y{pVxvvM_zO9C%zE1l=pZ|=X- zq~C4QiN{^}51TOK?f$cV%jDy@U%jD!E*Cj31n{9zOR zeiQyd6aFC+{t*-YlnMWY3ICJ{|EvlBf(ie!3IB=-|C$MZ+Jt|@gn!$Ff7gV6&xAj3 z!hd4Ie`dmeVZwiD!hdbTe{aJ7V8YLs@N*(w`r!31FyRpseu;#=od0lU^MkkUKmJwB zTOYjsjRNO;{%74Er%#roA1O({yCnVIlJx14^wTBjb0z6ZCF!dr=?|8qKU|Xj){^vU zN%~evdc7pQRg&H0nm8AbcN%|j` zr2lD2`j<-5zfzL^R7v{ZmZbmBlJuub(!CRd=bz`5q+eT-{-Tof>r2vaC`rGuB>j~o z>3&K2Yf930m!$74N#9?RK3S4}q$K_BlJt8^(x*$(PnV?6m836~q_38wKUk9fa7p@G zOVX<)>02e~^^){fNqV;={ZdK#J4({uRg(VRlJxhNq<^3!{evaxA1X=zXi56VO42`3 zoDSRNyRL`ce(nEvjn_SYjrXVD^7ONJBfJmcx4!r3XaD$rUgORl${0@XagZO7#*La^m_$kEyBf=j;_yY+4Il@mMydU1W{|~~yi15b{z72W*7~zj1 z{Az^%0O1cId<(*#L-;W@-Vf$*;*O!asH>T&Pi zU*r84;-02Bz-}UZ>06(E_Hl&Q5$+;bC zcnjeh0ROe-HC`3r_apo?!f!=*d1h*Qer9~T>b^>_jctaFv2OER*ywn5 zFFd$^a;&vg>4XzwTa`w& zxv_E7uY!zrZLQZ0tA4Z9tu-4Rf1`pd)uaAsXT<9@&NZ4B8-CbsH`|`1_}wO8LA=du zDG3{!wMJ;5*FjJ>EQIf%vM9Nj$~M|I^gF%n?MnM{f)ydzutpS`Wi& z$6xPW@_@!~Zur~bc9ZZ>qct~c-A-}Iwu-HGh{miZ%8y%Qz1g~)sG+v8D7`cXa=nS}<@^a+#-%dj8wV%6abdIZ?xilm?aF${(a8qj zZmBgk{Z6eKu2wo--_ zXxCNTUxHCamBCJ2BhV>+Np_X+DiNy{QZZ7!oRK{_tU)mfA=)zX<{aqpz1Colnj_w-m?Aklx#nG*18_}axiQGoN)&pW$ z3o4^NAgO1gG5X`23L{MzM?*RX={TW0U|AkRsw4>3w;&%8-4lvj^u-#a>%};}vfiy- zVA&L`LE6L#)o`u1iO&x5ciTM@ne|RcH8$cjV8M=DaeIW9Amt&l1DOtTAXs9e9b2X} ziBl;J zBQa?#BHDtr%iWOZuGd||Y68jF1RCX~fD;m|K!qeyc?OGWhg2RR0gcTBN)w$T&j^n| zMxm>xYla+%f)I&{A@B=>wQ;Uc6Bksr2rQb>YoZQI5{sD+m>w)4_>2DQLMXuWoU>ofwLn1wZd zMf8rbQaU!)xs2A{MzqNNF_Qc77m0g(k>Zw6os$|i(zLP0SR9*gX%&I}a423eXoOCsJRxaRqWY;gX#$N*HG{@xo5G(udi)(zx}ae) z5-pQWHVqY5%C*-cBcylJ(x|;QNP!d8s8FGiH2|$_u(rVB$m&ytnYy)YTG&ACzgVet zN!3OB`HX7BySQfb8de##9+Uy}55GCp{&Qk4MnAC6YF$^W>+A0OA;f1h{>a@LhZGCrltJXMok9YSz4G>k{ zMy~;l3Jb=&=`+CG)vI?I$bN2z-AdhC?^P=>H1ym`)`J8Ny{+2jmWSCXT1cx3tBYvY z$s{p7Gr=U2X@P#eSA$uAR_2@SN^8qst6*knRBZ=dZme&$n+*tfzp}m_*26Y0*JUbk ztM*2v)!AxxOXwkG1r_P^S|m`w+4*E+%I5X-efRsFtx6lq95xNKD~(Mo!kb~oZ!}?b zpedHCfVm&IRLP4nMSvT%uD{-Ex5Ea0n~iRWHDv^KvC{ErnMlSA8e0`zK@l+cmWn3v z8No|4v82|tG)1ncHgp>d-#9Dg6u(VlSa25Q%aBNOA=y(<$8{J~Lci7liuNX~C0%fE zaowOv`LU%XLeg$tL_2`Gm^2Hi^CYB<1B;h?ox#iywUVl1$pSEzYIUl=V^7wThhVkJ zMi+I>Aa_+$>EU=uu^YTr#uP(|d@Mi~l_jR0s0sv5RicpuHuM~NYS2d0S1T9kYprGt zECtgOm*7Q40?jd|WRE|{{~79a0bf8^+&2SinUc91^2hq*j%+aZh2=@pT?MdibedepCB zu5Z^aVb-eGVK^cqxz4in%Pe}K#PDi{RHhM+^TecS+hN{RH1h=rRBx>rPVaGs0mbNN2*8&NZ@X$B)Sw`HThakm_>ENfVA;Mt4TZvt77`0 z%^M1F^$>!M>cs+nvE78R+@VJ`rMhk-29=EvAc%b0L|Spbxdvre%!IIlFaXNke$Jg zvM`5Mpc6F4LTqbY*4`TN*6QcR_xqJ@w-KOA_4B;`p1WYv31i1bkY=j+Nks}6%hq}# zZeybnAWAoie1G(C7605hKDmLP@!MTju>nao_l6+aLbC{=B5b4<$6QcF-FeVr&_PoV zSqE6kMDYte>aR?S( z9WY$2US+)*%P}zE#aegEXWrS%YYEC9^Qs-VCX!>j(jpB}go=RsyGMK26se(Ls$4)+!Y3T7bqY?|Tvg!Xp?j)WVCMEb-(1Dm4rK$K1W$Y(R{zSFo7H z(7cQ#L#MZ~QCqLk8c5|bt&Gg#@BVo-X>~K~j>oN*EPfvS_rIJ3*KuT?t?|580I#BtLMx06iz z`be~vKrfL(K`YaEv)hpCZNtbxe8k0%39sp#?}0B8(KM4_gwPx#R7Eqq@bVaot*u(M zioJfGcfb$C=iYY2n?o6_F7nlop3XiYH|+$isX)D*AA!>wV1|c;Nx<@4NkWB+g=xxXD??HL z+ScWqMg5uq%=TxBOLdP}SC+KOp%ntzK87Jia}Ps~0S&9e;2s7k!2p}84zAsuSx4Jn z_FjqYF&KMf<#in+*?rObVXJ~UjyNG+Oi`u;;U%yRv5e-#*as$;s#LqRLcyv&k{0by zoGUo{C2+X?Oq;fNiEk?4phXF2V;33I^HH6PNIRtr^t)bx!c>FX06y5njA*Ks3FCAeaq{fk97W8ou0%j9OEV`Jh^Oc6Zi`)! zcnD+gV|UGWN(T$8L?)b1w)HW_l3O>6{tXcWjW9YcE~YFy%4=v30r_y7R*EL+6QSZiW2L?Pi1RP8W&pG>*kpn;)IN!y$NcQHwez{yG*ls4t;Qw8Iu=iDL);Y3mza!VV&~TevJ9dD#IK zvDH68BMdH?H0Bf!$0M2CA|Z>Y?^7^?`8=u)Bftm{fmVrGjd*SiPL&bwK|CRfwEY%| zDl#X~^z783N|ncxP8Sh=Z7wQ-nNYAOt&B0ro19W8)*`eK*+P%SouDwA0bYtU)NKw+ zO(OTr5AEOfZhq+CVg7f5|2;_m-YM}%?mBeW#Qq~3e_&hW!OZH^TySc6YUy;aJoNwx z5^p*TTPtCB&d1jI$vWIvq8Q#sf@osXCuvvE5y@$htstUCyH&32H*tMv5db3|nf^%q zj*WuC7uZh-+oY8`;~;D-)gG^|M?18H*gg8T-kx!v4DdQ#p=9TKMG~V_JbeZ5Zt=0_91O|}xFhPlbI9o9I^TI*G7a8AWq(FYXZnX0{Sysng6z2y3 zD5L#IwrnOxo2u73Mp(Ur0l8Y~Rxo$NQt63}vpx=s!)9X}VsRMv2swdo960QqpA7cXKL@I`e%~)rhks$ zpBj=cU4nN!{nF1t{e%}Gz9xf4og)Q8q6qGYS3}7)P*6KO>22VzcK$%H?X3|(ESaNr zSXx|xC4YWu`u^a7*}1uenVD(TKiTj^qBk<_wYcR-sPifxyDshV&CTt)`nr44Ze*dS zByb8s!ePYH&d38xoLWE9XkdZb3_EEw96JyV*GSDGxMotv)6~ej|ZnHF(exc za%6twVeU2(Xq-^b%ao)FUOLfozZAnn#e#-qNjg^oWem%rKMSix$8fUolm#>duwA*w z#P-fdtkA`U9ZClvP0^w zu&qoFSyLSwiD-&9Cqyz9I_{CpR!=sy3^cmC4SljF97`Ku(Y_a=vdh&Rs#ligW>+KH zqmmpwY(auF**A*Ks&vg4&#o?=#aeCgfx(r$h!u9|d@XhNkC>sjqGC37L~vD19ijAK zZi|+u@GV`(j$!moTo`?%nt>}wa=ngz#RlTocI8oYv@40te>n0n2)}Z3QI8g*Ev|Ag zL9YFIn<_zAy4Kij8kDY76Bp%C7?tyNuX}N=i)djx_)v5dVfZ>SOw98Oi(;$5P`__x zd0}QQcwlOI{_K+FeaA;QY1atra2;)L_gXqFS;;ZGFg^3&%rXpWQ>VxTB9bF63$~8| zsb^C8w$^3;5v6;y5$Peqg##?{w>|y`QNeldJPt0jEBL9vM+^pDjS#r|?q^6O%J&%o zSo6+sJoStwzze`@V{SlpIz2(S=mVl9ET6GGnz$UhOeyGupcaTVkAKkb>kp0 z$VD0@agc&e3TX)zw1-wj$fXH7LIMAUDq+S?{I z8QNkr2z(I5D~ZugFxnX#?Gcruz45hLLl9CPG<7x$CTqlI^gh{ek?nsPtLL2?FJ;T|DaSQHJHTLd1o%~}K6ZFd`|%p(U% zU69A!Aw{_nQ&tv90wTgvoMH!Bu7QKe-Gycy{L-Jy6BO8PhM05sw6y!g5Lm+r2~Ff7 ztGy+V8!MfPxDDHSDHaL%!Fv9?+7MW8rcDbx{BG$zH_ zjA-=8;~hD;2oeSI8Rh6~!GOnzD4(k^4O_wCys^j;la>*%!<@M z=!%@J3@KhqtiD8kpetmZL?!@Zwi32XFRB_9IKropCYN6+tZ6=1goOoh0R@@J3meYa zQobzaPGMax^PBNcW2Ydi7bNt59U{7`i>4JfE{xLD4lf_XR%j{BEw89lH}%1-N4>2$ zRmS_MbGFlEhI8(TE2c&$SjeIpL>`Q>XqumyUtE3@ZC@=euX-ZXq%vY>L)zyx|$OGhbE!9wVox?moCb#a$K0!hepBG`jU1&WlSa7|m|a0-Q=G6-Os9N4y?? zK2CW0zGVk8)5O@tJIpeIHbs&&RA?V)ui`w8DAm9clr#|)HA88vQue_Z^ z=t}3Zv!N=n82M>WL++{!JlAtSpL)TF=A|c``Hqcl`lJuEv7p_AN(%2p(!J^9JS!Fy zA`KX#fr62a9f4y&bJ#j2QUpm@Xy-2Iu!@|cSdq2C#VCwrv}8-5Bs@Z=G$eque{2;6 z87$c3HymQ)RgdAq*`U=s_7Hq@lm9>BgFW-&N7!KNTuIL-zMx3UbSB*(VpTfO(!$-N zLs`8$Xo*kijyf2~T@O4NI<-X*SWU?e=LluSh#|a$D^?(>&~DLYQ|wwKHsWYIsNzpd z`?RAW^MFW&({zQ*ijlhNzb0p`*l__~;7J^3V4ZbHq*vXXM046ctVE>*II%Q&eqtcF zw{b@C$^uh@=ooSLVw1=-s5@S(0>9E~BFTcY{kE*L6UH%0qAGU)LUl5a(;{1RRwyduAed@WB<= zgxYkN#v_O%!E&%m+a^D=Yb8EF=cQnZ^oFRoihpoANey=s=ua|RqEZR9Baz~>z7b(R zGl{lL0K^@gO-k0p<}Ip*ZGP_CL|H-%T0Ekm2oLr=aP|;9N~4!Y67{yT(Ub1ZMqU=K ztgW#=*R542!di7)^g`Y^;fw)H($V=N>Ldy&<{?y zF-l0sA_1xGVWbB07Y-fM=}Qr6?CqD4Y{e5#teD8kNK_AA8ma%4F$u5EOr1ClvlBbp z80Eue6@!(mt<0=ueEqrMv1-Kn2h$i%%F-Ny5UzOOi2{`;i%`NsAx@0s>ZO{Qh;zD8 z2Q#B{b9cz1Z$YWbhD((>NsFVoMtp$i)C4A&_(M}2l z!h$K4z-1DxfWCNUlrqTzNG`bc_I$#Ejls0#i|3O;N_xEBh&}1mULs?{ zW#R)la?V+F;6b)x(dS*bg!mQwCEnz87D#}#tNYl<{Bt1HtVcrTD zUih3KDU+c_B-06;%MwW^_Cvk|Aht)5t_#+HD>(w_U)lVk50x_%bb^NKMCJ>*i7Ljz z7rVTS!Yxx+i))4k^-xa1#4o-WVoewP}+N@Ya#sdWXpW54|DF><| z-H0Q{4ABgmVtzb&qlIA&K=^H%l)_(F=udJ!l&yTyC_BWGKPX%JKWaVK0ZhQufu_g^v6n_ zIu=J-;V4Xsd|@?J_Fd97h@7kDlBu9cZS1MoIj?QNp)7eR9&3U6vlJ9J|Is? zp?yZ88va_uc&d%IV2dVGp`KkcuqhZUv)BfN^R;|b0H-4Ocq$pe;4syJW98)d8WAA( zhMCxCQ5(q0%Ovs5PJBI;iG-+?ExvKyOO!QJTu5Fr?Uv<1oC_~!3yl%5=`jmHW|Q&A z^(s@JIKS+ZVpFkkF1L6LDB8@S&D2sLmI#@$g!hZ0=}cfz+6G)y0xWgV@6~J-6|c&H zbQ9B}L$2*A!ak5%Nz5fKZabW^A^{rcHClPSr~40OY~a93I@^K4_6YB@xV$a+!nILP zc>nV`*zrtjqygY@bZ)EJZUneyPEJpEybO~Y){ZM}7&?wLbjOh~r0xXkkVvp>E~Cac zl>Ka9#fg@8W(*5*vBEg!OB9$vH{0E-1`U5?9^ugfg3mi zfsOeD1sYe7<1&0cgEh>`!A6C*nIO7cbyI1j7&^2QohUoTz-cjtxOYf<#-445jm<$^ z;c|!=oAN+nTTks)K{7JV6XWOA9vi?(7Y#5O)#|vus}vx{mEkFeqc9=Po1&fduDm#& zvm-xFQjpn48H3;0rexEOL9H!pT8}PFina8ptW$Wu7;*<|;vS#;

$q6os)I@JJKD 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 b*86YR!O#)O^!U97f!b From 30c9832202b5fe36b2f525856a53d874323fd44a Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 13:59:47 +0100 Subject: [PATCH 10/17] phase 5 plan --- .../in-memory-payload-investigation.md | 265 +++++++ artifacts/issue-304/phase5-plan.md | 700 ++++++++++++++++++ 2 files changed, 965 insertions(+) create mode 100644 artifacts/issue-304/in-memory-payload-investigation.md create mode 100644 artifacts/issue-304/phase5-plan.md diff --git a/artifacts/issue-304/in-memory-payload-investigation.md b/artifacts/issue-304/in-memory-payload-investigation.md new file mode 100644 index 000000000..a642818fa --- /dev/null +++ b/artifacts/issue-304/in-memory-payload-investigation.md @@ -0,0 +1,265 @@ +# In-Memory Payload Handoff: Investigation + +## Question + +> Can the worker's KV cache be loaded directly from the wire as bytes arrive, +> eliminating the temp-file detour that the current snapshot framing uses? + +## Short answer + +Yes. The current path makes the KV shard hit `/tmp` four times per handoff +(once written and once read on each side, plus the wire transfer). The +streaming path eliminates the temp file entirely on each side, replacing it +with a fixed staging buffer that is reused for every chunk. For a 77-220 MB +payload this is roughly 0.5-1.5 GB of redundant data movement saved per +handoff, plus removal of disk-flush latency on each side, plus bounded +per-handoff memory regardless of payload size. Phase 5 should keep the +staging size as a compile-time constant, not a user-visible tuning flag. + +## Current data path + +Reading the code in `ds4.c` and `ds4_distributed.c`: + +**Coordinator (save) side** + +`ds4_session_save_layer_payload(session, FILE *fp, ...)` calls +`payload_write_tensor_span(fp, gpu_tensor, offset, bytes, buf, chunk, ...)` +for each tensor. `payload_write_tensor_span`: + +1. Reads `bytes` from `gpu_tensor` into `buf` using `ds4_gpu_tensor_read`. +2. Writes `buf` to `fp` with `fwrite`. + +`dist_save_remote_shard_to_file()` then streams `fp` to the wire via +`dist_send_snapshot_file_chunks()`. + +So the coordinator flow is: + +``` +GPU -> buf -> FILE (temp) -> [later] FILE -> buf -> socket +``` + +**Worker (load) side** + +`dist_worker_handle_snapshot_load()` reads chunks from the wire into `buf`, +then `fwrite`s them to a temp file. After all chunks arrive it `fflush`es, +`fseeko`s to the start, and calls +`ds4_session_load_layer_payload(session, FILE *fp, ...)` which calls +`payload_read_tensor_span(fp, gpu_tensor, ...)`: + +1. Reads `bytes` from `fp` into `buf` with `fread`. +2. Writes `buf` to `gpu_tensor` with `ds4_gpu_tensor_write`. + +So the worker flow is: + +``` +socket -> buf -> FILE (temp) -> [later] FILE -> buf -> GPU +``` + +**Total IO per handoff for a 77 MB payload:** + +- Coordinator: 77 MB GPU read + 77 MB temp file write + 77 MB temp file read + 77 MB wire send = ~308 MB of data movement, plus file flush latency +- Worker: 77 MB wire receive + 77 MB temp file write + 77 MB temp file read + 77 MB GPU write = ~308 MB of data movement, plus file flush latency + +The temp file is hit twice on each side, with no functional reason. + +For the README prompt (`ctx=16384`, 14,318 tokens, payload 221 MB) the +multipliers make the cost larger: ~884 MB of data movement per side. + +## Proposed change: streaming payload with a fixed staging buffer + +Add streaming variants of the save and load paths that operate on a +fixed reusable staging buffer instead of either a `FILE *` or a +full-payload in-memory buffer. The staging buffer is a compile-time +constant for Phase 5 and is the only memory that needs to be live +during a handoff. The data flows: + +- Sender: GPU → staging buffer → wire chunk +- Receiver: wire chunk → staging buffer → GPU + +The temp file is gone. The full-payload in-memory buffer is gone. The +single staging buffer is allocated once at the start of the transfer +and reused for every chunk. + +### New functions in `ds4.c` + +```c +typedef int (*ds4_payload_chunk_out_fn)(void *ctx, + const uint8_t *buf, uint64_t bytes, + char *err, size_t errlen); + +int ds4_session_save_layer_payload_stream( + ds4_session *s, + ds4_payload_chunk_out_fn write_chunk, + void *ctx, + uint32_t layer_start, + uint32_t layer_end, + uint64_t *bytes_out, // total payload size for the BEGIN frame + char *err, size_t errlen); + +typedef int (*ds4_payload_chunk_in_fn)(void *ctx, + uint8_t *buf, uint64_t bytes, + char *err, size_t errlen); + +int ds4_session_load_layer_payload_stream( + ds4_session *s, + ds4_payload_chunk_in_fn read_chunk, + void *ctx, + uint64_t payload_bytes, + const int *tokens, + uint32_t n_tokens, + uint32_t layer_start, + uint32_t layer_end, + char *err, size_t errlen); +``` + +Both functions walk the layer range in the same order as the existing +`ds4_session_save_layer_payload` / `ds4_session_load_layer_payload` +(header + per-layer `n_comp` / `n_index_comp` + raw cache rows + +compressed cache + state tensors + indexer tensors). For each tensor, +they transfer it in fixed-size staging chunks, calling the callback +once per chunk. The chunk callback is responsible for moving the bytes +to or from the wire. + +The save function pre-computes `*bytes_out` (the total payload size) +by summing the per-layer sizes. This lets the caller put the value in +the `DS4_DIST_MSG_SNAPSHOT_BEGIN` frame before any data is sent. + +The load function validates the header and per-layer metadata on the +first callback calls, then walks the layer range and writes to GPU. +Validation (token hash, model id, layer range, ctx, prefill_cap) all +happens before the first GPU write, exactly as today. + +### Internal refactor + +`payload_write_tensor_span(fp, ...)` and +`payload_read_tensor_span(fp, ...)` are replaced by +`payload_chunked_read(gpu_tensor, offset, n, staging_buf, ...)` and +`payload_chunked_write(gpu_tensor, offset, n, staging_buf, ...)`. The +chunked `ds4_gpu_tensor_read` / `ds4_gpu_tensor_write` calls are +unchanged; only the `FILE *` I/O around them moves to a streaming +callback. + +The header / per-layer metadata writes (`payload_write_u32`, +`payload_read_u32`) also become `payload_chunked_write_u32` / +`payload_chunked_read_u32` that use the same callback. + +The existing `FILE *`-based `ds4_session_save_layer_payload` / +`ds4_session_load_layer_payload` are re-implemented as thin wrappers +that provide a `FILE *`-based chunk callback. The local save/load tests +in `ds4_test.c` continue to work without changes. + +### Wire code + +The coordinator side change: + +- Compute `payload_bytes` by calling `ds4_session_save_layer_payload_stream` + with a counting callback, or by adding a pure + `ds4_session_layer_payload_size()` helper. +- Send `DS4_DIST_MSG_SNAPSHOT_BEGIN` with the computed size. +- Call `ds4_session_save_layer_payload_stream` for real. The + `write_chunk` callback sends `DS4_DIST_MSG_SNAPSHOT_CHUNK` frames. + `DS4_DIST_SNAPSHOT_CHUNK_BYTES` is the natural compile-time staging + size unless implementation constraints require a smaller internal + buffer. + +The worker side change: + +- Receive `DS4_DIST_MSG_SNAPSHOT_BEGIN`. Validate token count, model + id, layer range, ctx, prefill_cap. +- Receive `DS4_DIST_MSG_SNAPSHOT_CHUNK` frames into the wire receive + buffer (8 MB, unchanged). +- Call `ds4_session_load_layer_payload_stream` with a `read_chunk` + callback that fills the staging buffer from the wire receive buffer, + receiving more wire chunks as needed. +- After the load function returns, send `DS4_DIST_MSG_SNAPSHOT_DONE`. + +The wire framing is unchanged. The only difference is the source/sink +of the chunk payload: data flows through the existing wire chunk buffer +and the fixed staging buffer instead of through a temp file. + +### Memory cost + +- Sender: 1 fixed staging buffer + 1 wire chunk buffer. +- Receiver: 1 fixed staging buffer + 1 wire chunk buffer. + +Total per-handoff memory is bounded by the fixed buffers across both +processes regardless of payload size. For a 1M-token context the +savings versus the temp-file approach are not just disk IO but also +~6 GB of disk-resident temp files and the corresponding page cache +pressure. + +### Configuration + +Do not add `--dist-staging-bytes` in Phase 5. Use a compile-time +constant for the staging buffer, preferably aligned with +`DS4_DIST_SNAPSHOT_CHUNK_BYTES` unless code-level constraints require +a smaller internal buffer. Runtime tuning can be revisited after the +first performance artifacts show it matters. + +### Why streaming from day one + +A staging buffer is strictly better than a full-payload in-memory +buffer because: + +- Bounded memory regardless of payload size. +- No risk of a failed `malloc(payload_size)` on a constrained device. +- The staging buffer is reusable for future pipelined KV return + (Phase 6) — the same buffer can be passed across prefill chunks + with no additional allocation. +- A compile-time staging size keeps the Phase 5 operator surface small. +- The implementation is only marginally more complex than the + full-buffer version. The chunk callback abstraction is the same + whether the callback sends to a wire or to a FILE*. + +## Impact on Phase 5 plan + +The Phase 5 plan currently treats in-memory payload handling as +"rejected for Phase 5; only revisit if temp-file staging becomes a +measurable bottleneck." This investigation shows the bottleneck is +already measurable for the target prompt sizes (200+ MB redundant +disk I/O on each side per handoff) and the change is small (two new +functions plus minor refactoring of the wire code). + +**Recommendation: do the streaming refactor as part of Phase 5.** It +fits naturally into the new worker-pushed / HELLO-advertised path, and +it removes the only significant runtime cost of the current snapshot +framing. Phase 6 can then target pipelining or wire-to-GPU streaming +for further optimization. + +## Code touchpoints + +- `ds4.c` + - Add `ds4_session_save_layer_payload_stream()` and + `ds4_session_load_layer_payload_stream()` with chunk callbacks. + - Refactor `payload_write_tensor_span` / `payload_read_tensor_span` + into chunked GPU read / GPU write helpers that take a staging + buffer and a chunk callback. Keep the `FILE *`-based path as a + thin wrapper that provides a `FILE *`-based chunk callback. + - The header / per-layer metadata read / write also moves to the + chunk callback. +- `ds4_distributed.c` + - Coordinator: replace `dist_tmpfile_or_err(...)` + + `ds4_session_save_layer_payload(fp, ...)` with a fixed staging + buffer and `ds4_session_save_layer_payload_stream(...)`. The + `write_chunk` callback sends a `DS4_DIST_MSG_SNAPSHOT_CHUNK` per + staging buffer fill. + - Worker: replace the chunked `fwrite` to a temp file and + `ds4_session_load_layer_payload(tmp, ...)` with the streaming + load function. The `read_chunk` callback receives the next wire + chunk and copies bytes into the staging buffer. + - Wire framing (`DS4_DIST_MSG_SNAPSHOT_*`) is unchanged. + +## Validation + +- Same-pass comparison: existing `tests/issue304_phase4_handoff` and + `tests/issue304_phase4_diagnose` runs must produce identical token + sequences with the streaming path. +- Timing: the streaming path should be measurably faster than the + temp-file path for prompts that produce > 50 MB payloads, and at + least no slower for small payloads. +- Memory: per-handoff memory growth is bounded by the fixed staging + buffer plus the existing wire chunk buffer. No temp file is created. +- Failure cases: token-hash mismatch, layer-range mismatch, model-id + mismatch must still reject the handoff before any GPU write happens. +- No staging-size CLI: verify Phase 5 does not add + `--dist-staging-bytes`; staging-size tuning is deferred. diff --git a/artifacts/issue-304/phase5-plan.md b/artifacts/issue-304/phase5-plan.md new file mode 100644 index 000000000..704c2324e --- /dev/null +++ b/artifacts/issue-304/phase5-plan.md @@ -0,0 +1,700 @@ +# Issue 304 Phase 5 Plan: API Shape And User-Facing Handoff Workflow + +This plan converts the Phase 4 research-only handoff into a usable, benchmarkable, +operator-facing workflow. It is intentionally narrow: it does not reopen Phase 3 +variance forensics, does not change residency, and does not change route topology. +It is the smallest step that turns `tests/issue304_phase4_handoff` into something +a real frontend can call. + +## Source documents + +- `PLAN.md` Phase 5 section defines the goal, candidate options, and decision criteria. +- `NAVIGATION.md` documents the public API, distributed orchestration, and validation surface. +- `artifacts/issue-304/decision-log.md` records the upstream decisions: + - Phase 4 final-worker handoff is viable in both backend directions. + - `CUDA -> Metal` strict parity requires a fresh Metal worker process. + - Whole-payload `DSV4` handoff remains a debug/fallback, not the primary path. +- `artifacts/issue-304/runbook.md` captures the current closeout rules and the + Phase 4 operator workflow. +- `artifacts/issue-304/engine-residency.md` confirms the preferred residency + design (full-resident final worker, sliced distributed execution during prefill). +- `artifacts/issue-304/failure-cases.md` lists the rejection cases the new + workflow must continue to reject. + +## Current State After Phase 4 + +- A working same-session final-worker handoff exists and is reachable from C. +- The current public API is: + - `ds4_session_distributed_route_ready()` in `ds4.h` + - `ds4_session_distributed_route_summary()` in `ds4.h` + - `ds4_session_distributed_handoff_argmax()` in `ds4.h` + - `ds4_session_distributed_handoff_argmax_trace()` in `ds4.h` + - `ds4_dist_session_handoff_argmax()` / `..._trace()` in `ds4_distributed.h` +- The implementation is in `ds4_distributed.c`: + - `dist_session_handoff_argmax_trace()` validates route, validates shard layout, + saves the coordinator's local slice to a temp file via + `ds4_session_save_layer_payload()`, hands the bytes to the final worker via + `dist_load_remote_shard_from_payload()`, copies the current logits, and + dispatches `DS4_DIST_MSG_LOCAL_GENERATE_REQ` to the worker. + - The worker decodes locally and returns tokens through the new + `DS4_DIST_MSG_LOCAL_GENERATE_RES` message family. +- The current path is **coordinator-initiated**: the coordinator session + calls `ds4_dist_session_handoff_argmax()` and orchestrates the transfer. + Phase 5 inverts this: the **worker** initiates the local-decode transition + by asking the coordinator to ship its KV cache back. +- The harness in `tests/issue304_phase4_handoff.c` and + `tests/issue304_phase4_diagnose.c` is the only existing user of the API. +- No CLI flag, no server wiring, and no README documentation exists yet. +- `Makefile` already builds both helpers as standalone binaries. +- `ds4_dist_parse_cli_arg()` is the single shared CLI parser for + distributed options. It is already called by `ds4_cli.c`, + `ds4_server.c`, `ds4_bench.c`, `ds4_agent.c`, and `ds4_eval.c`. New + distributed flags added here are automatically recognized by all five + frontends. + +## Phase 5 Goal + +> Turn the Phase 4 in-process handoff into a real, user-facing, benchmarkable +> workflow by having the worker advertise its local-decode intent and full +> residency during the normal HELLO handshake, then letting the coordinator +> push its KV cache back to the worker in memory (no temp file) using the +> existing snapshot framing. No new decode or catch-up protocol is required. + +### Architectural direction + +The Phase 4 path is coordinator-initiated: the coordinator calls +`ds4_dist_session_handoff_argmax()`, saves its local shard, ships it to the +worker, and dispatches the local-generate request. Phase 5 inverts the +direction while reusing more of the existing machinery: + +- The **worker** owns the `--local-decode` flag and the local-decode + decision. +- During the existing HELLO handshake, the worker advertises + `wants_local_decode = true` to the coordinator. The coordinator records + this on its `ds4_dist_worker_entry` for the worker. +- After distributed prefill completes, the coordinator pushes its local + KV shard back to the output-owning worker using the **existing** + `DS4_DIST_MSG_SNAPSHOT_*` family (`BEGIN`/`CHUNK`/`DONE` and the + corresponding `SNAPSHOT_LOAD_BEGIN` on the worker). +- The worker's existing `dist_worker_handle_snapshot_load()` receives the + bytes, validates them, and calls `ds4_session_load_layer_payload()` on + its own session. +- The worker then owns local generation using the existing local + `ds4_session_eval()` path and returns generated token ids through the + existing local-generate response. +- Reusable coordinator sessions use those returned token ids to catch up + their coordinator-owned KV before accepting a subsequent prompt. One-off + coordinator runs can ignore catch-up because they exit after printing the + worker output. + +Why this is simpler than a dedicated pull protocol: + +- The coordinator already serializes worker-owned shards and the worker + already loads them. The new direction is just "coordinator serializes + its own shard, worker loads it." The framing and chunking code paths + are reused as-is. +- The decision to push is communicated once, in HELLO, not as a + separate request after prefill. This avoids a new request-response + roundtrip and a new message family. +- The same push channel can later stream KV chunks during prefill instead + of after, which is the natural Phase 6 (pipelined KV return) extension. + No protocol rework is needed to add KV pipelining; only the timing of + the push changes. + +Implications for the coordinator: + +- A new boolean field on `ds4_dist_worker_entry` records + `wants_local_decode`. Set during HELLO parsing. +- A new post-prefill step in the coordinator checks whether the final + route entry has `wants_local_decode = true`, and if so, triggers the + existing snapshot-push path to that worker. +- The coordinator's startup code path does not change. The new field is + learned through HELLO, which is the normal registration event. +- Reusable coordinator sessions must track whether local KV is current + after worker-owned generation. If not current, they forced-evaluate the + exact returned worker tokens through the coordinator-owned slice before + processing the next prompt. + +Implications for the worker: + +- A new field on `ds4_dist_options` (e.g. `bool local_decode`) is parsed + by the shared CLI parser. +- The worker startup path validates: + - the worker's layer range is `N:output` (or otherwise owns the output + head), + - and exits with a clear error if not. +- `--local-decode` implies full worker residency, replacing the operator + need to set `DS4_DIST_WORKER_FULL_RESIDENT` for the user-facing path. +- During HELLO, the worker sends `wants_local_decode = opt->local_decode` + to the coordinator. +- The existing `dist_worker_handle_snapshot_load()` handler does not + need to change. It already calls `ds4_session_load_layer_payload()` + and validates token hash, model id, and layer range. The handler + only needs to know it is being called for the local-decode handoff + case so it can also accept the coordinator's local-start range + (currently the snapshot path expects the worker's own range). + +### Single-flag parsing + +`ds4_dist_parse_cli_arg()` in `ds4_distributed.c` is the only place that +parses distributed CLI flags today. It is already invoked by `ds4_cli.c`, +`ds4_server.c`, `ds4_bench.c`, `ds4_agent.c`, and `ds4_eval.c`. Adding +`--local-decode` here makes it recognized by all five frontends at once. +The worker is the only consumer of the parsed value; the coordinator +simply ignores it. + +### Narrow current support + +The Phase 4 implementation only supports local decode on a worker that owns +the output head (`--layers N:output`). Until Phase 9 (topology rewiring) +lands, `--local-decode` must succeed only in the narrow configuration and +must fail loudly everywhere else. + +| Configuration | `--local-decode` behavior | +| --- | --- | +| worker role + `--layers N:output` (or any range that owns the output head) | succeed: worker advertises local-decode/full-resident capability in HELLO, coordinator pushes KV after prefill, worker owns local generation | +| worker role + `--layers N:42` (output on coordinator) | fail at startup: "local-decode requires worker-owned output head; use --layers N:output" | +| worker role + multi-worker route where this worker is not the final hop | fail at startup: "local-decode is only valid on the worker that owns the final layer range" | +| coordinator role | ignored (with a stderr note that it only applies to workers) | +| none role (not distributed) | fail at startup: "local-decode requires --role worker" | +| any frontend in any config | flag is accepted and forwarded; the startup check above still applies | + +Note: the "no coordinator connection yet" case is intentionally absent. +The worker has not connected to the coordinator at startup, so the +check would always trigger. The connection is a transient state that +resolves at HELLO time. The runtime guarantee is that +`wants_local_decode` only takes effect once the worker successfully +registers; the coordinator will not push a KV shard to a worker that +never advertised the intent. + +The validation belongs in the worker-side `ds4_distributed.c` startup +path, not in each frontend's `parse_options`. This keeps the frontends +dumb: they accept the flag, write it to the shared `ds4_dist_options` +field, and let the worker session code apply or reject it. + +The phase 5 exit gate, copied from `PLAN.md`: + +> A user-visible path can run distributed prefill and then local-only decode with +> measured speedup and correctness artifacts. + +## API Shape Decision + +Phase 5 must pick one of these before adding any public wiring: + +| Option | How the KV gets to the worker | Reuses existing machinery? | Verdict | +| --- | --- | --- | --- | +| (a) **Coordinator pushes KV, advertised in HELLO, streaming with fixed staging buffer** | Worker advertises `wants_local_decode` and full residency in HELLO; coordinator pushes via the existing snapshot framing using a compile-time staging size after prefill | Yes — same `DS4_DIST_MSG_SNAPSHOT_*` family and `dist_worker_handle_snapshot_load()`; `ds4_session_*_layer_payload_stream` replaces the temp-file detour | **Preferred.** Smallest protocol delta. Bounded per-handoff memory. No disk IO on the handoff path. Naturally extends to pipelined push in Phase 6. | +| (b) Coordinator-initiated handoff (current Phase 4 path) | Coordinator calls `ds4_dist_session_handoff_argmax()` directly | N/A | Keep as a low-level primitive and debug/diagnostic surface. Do not expose through `--local-decode`. | +| (c) Worker-pulled KV with a dedicated protocol | Worker sends a new `DS4_DIST_MSG_KV_PULL_REQ` after prefill | No — new request/response family | Reject. Adds a new roundtrip and message family for no benefit over (a). | +| (d) Whole-payload `DSV4` handoff (Phase 2 path) | Coordinator stages `DSV4` to disk, worker loads | Partially | Keep as debug/fallback only. Do not expose as primary. | +| (e) In-memory payload handoff (without the HELLO advertisement change) | In-memory snapshot transfer | No | Subsumed by (a) — (a) already does the in-memory path. | + +### Decision + +**Adopt option (a): coordinator pushes KV, advertised in HELLO, +streaming with a fixed staging buffer.** The new user-facing flag +`--local-decode` lives on the worker. The worker advertises its +local-decode intent and full-resident capability during the normal +HELLO handshake. The coordinator records the intent on the worker +entry, then pushes its local KV shard back to the worker after prefill +using the existing snapshot framing, but with a streaming payload path +(`ds4_session_save_layer_payload_stream` / +`ds4_session_load_layer_payload_stream`) that uses a compile-time +staging size and eliminates the temp-file detour. No new decode or +catch-up protocol is required, no disk IO is involved in the handoff, +and the design naturally extends to pipelined KV return in Phase 6. + +The existing `ds4_session_distributed_handoff_argmax()` / +`..._trace()` API remains available as a coordinator-side low-level +primitive and as a debug/diagnostic surface. It is no longer wired to +the user-facing flag. + +The new API surface for option (a): + +- `ds4_dist_options` gains one field: + - `bool local_decode` — parsed from `--local-decode`. +- `ds4_dist_worker_entry` gains a `bool wants_local_decode` field. + The coordinator sets it from the worker's HELLO message. +- A new post-prefill step in the coordinator (in + `dist_coordinator_*` somewhere after the final prefill chunk ACK): + - checks whether the final route entry has `wants_local_decode = true`, + - and if so, calls the streaming snapshot-push path + (`ds4_session_save_layer_payload_stream`) targeted at the final + worker. The `write_chunk` callback sends + `DS4_DIST_MSG_SNAPSHOT_CHUNK` frames using the fixed staging size. +- The worker's existing `dist_worker_handle_snapshot_load()` handler + does not need a new dispatch path. It already receives wire + chunks; the change is that the chunks are streamed into + `ds4_session_load_layer_payload_stream` via a `read_chunk` + callback instead of being accumulated in a temp file. The handler + must accept the coordinator's local layer range (currently the + snapshot path expects the worker's own range). + +The API must satisfy these contract rules: + +- `--local-decode` on the worker must require the worker to own the + output head (`N:output`). Reject `N:42` at startup because the + worker would not have the output head to produce logits locally. +- `--local-decode` on the worker must require this worker to be the + final hop in the route. Reject intermediate workers at startup. +- The KV push must validate token hash, model id, ctx, prefill_cap, + and layer range exactly as the existing `dist_kv_route_validate()` + does for save/load. +- The push must preserve the token timeline, logits, raw SWA rows in + logical order, compressed KV rows, compressor frontier state, and + indexer state. The existing `DSVL` shard load path already covers + these. +- After the worker loads the coordinator's KV shard, the worker + owns generation using the existing local session API and returns + generated token ids via the existing local-generate response. +- Reusable coordinators must forced-evaluate returned worker token ids + through their local slice before processing a subsequent prompt. + One-off coordinators may skip this catch-up. +- The flag must surface timing for KV push and local decode so callers + can attribute end-to-end cost. + +## Phase 5 Work Items + +The items are ordered so each one produces a small, testable artifact before +the next one is started. + +### 1. Extend the HELLO protocol with the local-decode advertisement + +Goal: let the worker tell the coordinator it wants local decode during the +existing registration handshake. + +Work: + +- In `ds4_distributed.c` and `ds4_distributed.h`: + - Add a `bool local_decode` field to `ds4_dist_options` (parsed from CLI + in work item 2). + - Add a `bool wants_local_decode` field to `ds4_dist_worker_entry`. + - Extend the HELLO message wire format to include a local-decode/full-resident + flag. The current HELLO already advertises layer range and output-head + ownership; this is a small extension in the same record. + - Update HELLO parsing on the coordinator side to read the new byte and + set `entry->wants_local_decode` accordingly. + - Update HELLO serialization on the worker side to write the new byte + from `opt->local_decode`. +- No new message types are introduced. HELLO is already the registration + message; the new field is an extension of its existing payload. + +Exit evidence: a focused unit test in `tests/ds4_test.c` that round-trips +a HELLO with `wants_local_decode = true` through the wire format and +verifies the coordinator reads it back correctly. + +### 2. Parse `--local-decode` in the shared distributed CLI parser + +Goal: make the flag recognized by all five frontends at the CLI level +without per-frontend changes. + +Work: + +- In `ds4_distributed.c`: + - The `bool local_decode` field on `ds4_dist_options` was added in + work item 1. + - Add a `--local-decode` case to `ds4_dist_parse_cli_arg()` that sets + `opt->local_decode = true`. No argument. + - Add the new flag to `ds4_dist_usage()` with the + "worker-only" caveat. +- No frontend-level changes are required: + - `ds4_cli.c`, `ds4_server.c`, `ds4_bench.c`, `ds4_agent.c`, and + `ds4_eval.c` all call `ds4_dist_parse_cli_arg()` already. They pick + up the new flag automatically. + - The worker reads `opt->local_decode` and advertises it in HELLO; the + coordinator ignores it. + +Exit evidence: `ds4 --help` and `ds4-bench --help` both list +`--local-decode`; running the binary with the flag in an unsupported +configuration produces the documented error message and a non-zero exit. + +### 3. Wire the worker-side local-decode startup check + +Goal: the worker rejects the configuration at startup if it cannot do +local decode, before any prefill work, and loads enough model state to +own decode after handoff. + +Work: + +- In `ds4_distributed.c`, the worker startup path (the part that runs + when a `--role worker` process opens its engine and prepares to + connect to the coordinator) must: + - check `opt->local_decode`, + - verify that the worker's layer range is `N:output` (or otherwise + owns the output head), + - verify that this worker is the final hop in the route + (i.e., it is the only worker, or the last in a multi-worker + chain), + - make the worker full-resident for model weights/output when + `--local-decode` is set, + - and reject the configuration with the documented error message if + any check fails. +- The check must run before any distributed prefill or decode work + begins so the failure cost is zero. +- The "coordinator connection" state is intentionally not checked here: + the worker has not yet connected, and the check would always + trigger. The runtime guarantee is that the KV push only happens when + the worker has successfully registered via HELLO with + `wants_local_decode = true`. +- Frontend `parse_options` code must not duplicate this validation; + they only forward the boolean. + +Exit evidence: a focused unit test in `tests/ds4_test.c` that calls the +startup check on each unsupported configuration and verifies the right +error code and message. + +### 4. Add the coordinator-side KV push after prefill + +Goal: when the final worker has advertised local decode, the coordinator +pushes its own KV shard back to that worker using the existing snapshot +framing. + +Work: + +- In `ds4_distributed.c`, the coordinator's prefill completion path + (after the final prefill chunk is acknowledged) must: + - check whether the final route entry has `wants_local_decode = true`, + - and if so, call the snapshot-push path targeted at the final + worker. The path now uses the streaming payload API (work item + 4b), not a temp file. +- Extend `dist_worker_handle_snapshot_load()` to accept the + coordinator's local layer range (the worker's own range is the + current default). Token hash, model id, and layer range validation + already exist and should be reused. +- Capture timing for the push so the helper and CLI can report it. +- The existing coordinator-initiated + `ds4_dist_session_handoff_argmax()` / `..._trace()` stays as a + low-level primitive. It is not exposed through the user-facing flag. + +Exit evidence: a focused unit test in `tests/ds4_test.c` that exercises +the coordinator's post-prefill KV push against a fake worker and +verifies the worker receives the bytes and can resume local decode. + +### 4b. Add streaming payload path with a fixed staging buffer (eliminates the temp file) + +Goal: avoid the temp-file detour on both coordinator and worker sides +of the handoff. Per `in-memory-payload-investigation.md`, the current +snapshot framing makes the KV shard hit `/tmp` four times per +handoff. The streaming path replaces the temp file with a small +fixed staging buffer that is reused for every chunk. The staging size +is a compile-time constant for Phase 5; do not add CLI tuning until +measurements show it is needed. + +Work: + +- In `ds4.c`: + - Add `ds4_session_save_layer_payload_stream(session, + write_chunk, ctx, layer_start, layer_end, + bytes_out, err, errlen)`. Walks the layer range, reads from GPU + in fixed-size staging chunks, and calls `write_chunk` for each + chunk. The total payload size is returned in `*bytes_out` so the + caller can populate the `DS4_DIST_MSG_SNAPSHOT_BEGIN` frame. + - Add `ds4_session_load_layer_payload_stream(session, read_chunk, + ctx, payload_bytes, tokens, n_tokens, + layer_start, layer_end, err, errlen)`. Walks the layer range, + calls `read_chunk` to fill the staging buffer, and writes to + GPU. Validation (token hash, model id, layer range, ctx, + prefill_cap) all happens before the first GPU write. + - Refactor `payload_write_tensor_span` and `payload_read_tensor_span` + into chunked GPU read / GPU write helpers that take a staging + buffer and a chunk callback. Keep the `FILE *`-based path as a + thin wrapper that provides a `FILE *`-based chunk callback so + the existing local save/load tests continue to work. + - The header / per-layer metadata read / write also moves to the + chunk callback. +- In `ds4_distributed.c`: + - Coordinator: replace `dist_tmpfile_or_err(...)` + + `ds4_session_save_layer_payload(fp, ...)` with the fixed staging + buffer and `ds4_session_save_layer_payload_stream(...)`. The + `write_chunk` callback sends a `DS4_DIST_MSG_SNAPSHOT_CHUNK` + per staging-buffer fill. + - Worker: replace the chunked `fwrite` to a temp file and + `ds4_session_load_layer_payload(tmp, ...)` with the streaming + load function. The `read_chunk` callback receives the next + wire chunk and copies bytes into the staging buffer. + - Wire framing (`DS4_DIST_MSG_SNAPSHOT_*`) is unchanged. The wire + chunk size (`DS4_DIST_SNAPSHOT_CHUNK_BYTES`, 8 MB) is + the natural default for the fixed staging size unless code-level + implementation constraints require a smaller internal buffer. + +Exit evidence: + +- The streaming path produces the same token sequences as the + existing temp-file path on the authoritative DGX/Mac topology. +- Per-handoff memory growth is bounded by the fixed staging buffer + plus the existing wire chunk buffer. + No temp file is created. +- No `/tmp/ds4-dist-*` files appear during a successful handoff + (verifiable with `ls /tmp/ds4-dist-*` before/after). +- Timing is at least no worse than the temp-file path for small + payloads and measurably faster for payloads above ~50 MB. +- No staging-size CLI or public API is added in Phase 5. + +### 4c. Add coordinator catch-up for reusable sessions + +Goal: keep coordinator-owned KV current after worker-owned local +generation so subsequent prompts can safely reuse the distributed +session. + +Work: + +- Use the generated token ids already returned by + `DS4_DIST_MSG_LOCAL_GENERATE_RES`; do not add a new catch-up + protocol. +- In reusable coordinator/session paths, after worker local generation + returns: + - append the generated token ids to the coordinator transcript, + - forced-evaluate those exact tokens through the coordinator's local + layer slice, + - mark coordinator local KV current only after replay reaches the + worker decode frontier. +- In one-off coordinator paths, skip coordinator catch-up after + receiving and printing the worker output. +- If catch-up fails in a reusable session, reject the next prompt + rather than continuing with stale coordinator KV. + +Exit evidence: a reusable-session integration run can perform +distributed prefill -> worker local generation -> coordinator catch-up +-> subsequent prompt prefill -> second worker local generation without +stale-token or layer-layout failures. + +### 5. Regression test in `tests/ds4_test.c` + +Goal: make the new flow executable by the standard regression target. + +Work: + +- Add a `--local-decode-push` test entry in `ds4_test.c` that: + - constructs a `ds4_dist_options` with + `role = DS4_DISTRIBUTED_WORKER`, + `layers = {start, has_output = true}`, + `local_decode = true`, + - requires a worker process to be reachable on `127.0.0.1:1234` (or + skips if no worker is present), + - runs a small distributed prefill, + - waits for the coordinator's post-prefill KV push to complete, + - receives generated token ids from the worker local-generate path, + - catches up the coordinator local KV when the test is running in + reusable-session mode, + - validates timing fields are populated, + - and emits a one-line summary. +- Gate the test behind an environment variable (e.g. + `DS4_RUN_DISTRIBUTED_TEST=1`) so default `make test` still passes + without a second process. + +Exit evidence: +`DS4_RUN_DISTRIBUTED_TEST=1 ./ds4_test --local-decode-push` +prints a `pass` line and `make test` remains green without the variable +set. + +### 6. Runbook update + +Goal: an operator can run the new workflow from a copy-pasteable command. + +Work: + +- Update `artifacts/issue-304/runbook.md` with: + - the new worker-side CLI form (`--role worker --layers N:output --local-decode`), + - the fact that `--local-decode` implies full worker residency, + - the same startup memory guard rules as Phase 4, + - the `CUDA -> Metal` fresh-worker caveat, + - the one-off vs reusable-session catch-up rule, + - and a "what good output looks like" example. +- Add a Phase 5 section above the existing Phase 4 closeout rules so the + workflow steps are obvious to the next engineer. + +Exit evidence: the runbook has a "Phase 5 worker-initiated workflow" section +that matches the flag set actually implemented in `ds4_distributed.c`. + +### 7. README update (minimal, deferred-until-stable) + +Goal: do not over-document while the workflow is still moving. + +Work: + +- Add a short paragraph in the distributed-inference section noting that + distributed prefill can hand off to local-only decode on the worker. +- Point at the runbook for the exact commands. +- Do not promise strict same-token parity across repeated runs; preserve the + Phase 3.5 caveat language about backend variance. + +Exit evidence: the README has at least one sentence about the handoff workflow +that is consistent with what the CLI actually does. + +### 8. Failure case documentation + +Goal: keep the negative cases recorded so the next implementer does not +regress them. + +Work: + +- Append to `artifacts/issue-304/failure-cases.md`: + - `--local-decode` on a worker that does not own `N:output`. + - `--local-decode` on an intermediate worker in a multi-worker route. + - `--local-decode` on a coordinator process (silently ignored with a + stderr note). + - `--local-decode` on a non-distributed (none-role) process. + - Stale coordinator/worker session (token hash mismatch on the + pushed shard). + - Worker prefill-cap mismatch (already known from Phase 3). + - `--local-decode` accepted (not rejected as unknown) by `ds4`, + `ds4-server`, `ds4-bench`, `ds4-agent`, and `ds4-eval` `--help`, + but the worker startup check fails the runtime configuration. + - Note that "no coordinator connection" is intentionally not a + failure case: the connection is a transient state and the KV push + only happens once HELLO has been processed. + - In-memory staging buffer allocation failure. The handoff should + fail with a clear "out of memory" diagnostic before any GPU + write happens. + - Reusable coordinator catch-up failure after worker local + generation. The next prompt must fail clearly rather than using + stale coordinator KV. + +Exit evidence: `failure-cases.md` has a "Phase 5" section that lists each +case and the diagnostic the user sees. + +### 9. Performance and correctness refresh + +Goal: re-collect the post-implementation numbers in the existing artifacts. + +Work: + +- Run the new worker-side CLI form on the DGX/Mac topology for both + `Metal -> CUDA` and `CUDA -> Metal` (with the fresh-Metal-worker + rule for the latter). +- Update `artifacts/issue-304/perf-breakdown.md` with: + - prefill sec, in-memory KV push sec, local decode sec, local tok/s, + - reusable-session coordinator catch-up sec and any catch-up tail + latency, + - the existing distributed decode sec/tok/s for comparison, + - the issue-reference distributed prefill and pure local generation + timing for comparison, + - and a side-by-side row comparing the old temp-file KV push + timing to the new in-memory KV push timing on the same prompt + (verifies work item 4b delivered the expected speedup). +- Update `artifacts/issue-304/logit-comparisons.md` with: + - handoff logits parity (expect `top1` match, `rms=0`, `max_abs=0`), + - greedy continuation for the sampled window, + - and the standard same-backend fresh-local comparison. +- Update `artifacts/issue-304/compatibility-matrix.md` with a Phase 5 row + per backend direction. + +Exit evidence: a `## Phase 5` section in each of the three artifacts that +shows the new numbers and routes them to the correct cells. + +### 10. Decision log update + +Goal: leave a clear record of what was decided and what was rejected. + +Work: + +- Append a `2026-06-XX` entry to `artifacts/issue-304/decision-log.md` + recording: + - the selected API shape (coordinator-pushed KV, advertised in HELLO), + - the rejected alternatives with one-line reasons (coordinator-initiated + is kept only as a low-level primitive; worker-pulled with a dedicated + protocol was rejected in favor of reusing the snapshot framing; whole- + payload and explicit shard merge are deferred), + - the inclusion of the streaming payload path with a compile-time + fixed staging buffer (work item 4b) and the side-by-side timing + comparison vs. the previous temp-file path, + - the reusable-session coordinator catch-up requirement and the + one-off coordinator exemption, + - the inversion of the Phase 4 design: the coordinator no longer + needs to know about `--local-decode` at startup, + - the operator-facing rules the workflow assumes (full-decode worker + weights, fresh Metal worker for strict `CUDA -> Metal` parity, + matching `ctx` and `prefill_cap`). + +Exit evidence: the decision log has a Phase 5 entry dated within the same +session that the code lands. + +## Validation Plan + +After implementation, run these in order and stop on the first failure: + +1. `make` +2. `make test` (must pass without `DS4_RUN_DISTRIBUTED_TEST`) +3. `DS4_RUN_DISTRIBUTED_TEST=1 ./ds4_test --local-decode-push` + (must pass with the second-process setup if available, otherwise + skip) +4. The new worker-side CLI form on the DGX/Mac topology in both + directions: + - `Metal -> CUDA` on a reused CUDA worker + - `CUDA -> Metal` on a fresh Metal worker +5. `./ds4_test --logprob-vectors` (must still pass) +6. `./ds4_test --local-golden-vectors` (must still pass) +7. `./ds4_test --local-payload-resume` (must still pass) +8. Spot-check that `--local-decode` is accepted (and not rejected as + unknown) by `ds4 --help`, `ds4-server --help`, `ds4-bench --help`, + `ds4-agent --help`, and `ds4-eval --help`. +9. Negative cases: invoke `--local-decode` in each unsupported + configuration (none role, `N:42` worker layers, intermediate + worker in a multi-worker route) and verify the failure messages + match the "Narrow current support" table. +10. Streaming path verification: run the authoritative DGX/Mac + handoff with the new streaming path. Confirm that + `ls /tmp/ds4-dist-*` is empty during a successful handoff (no + temp files are created). Confirm the streaming KV push time is + at least no worse than the previous temp-file KV push time on + the same prompt, and ideally measurably faster for payloads + above 50 MB. Confirm the generated token sequence is identical + to the previous Phase 4 helper output. +11. Reusable-session verification: run distributed prefill -> worker + local generation -> coordinator catch-up -> next prompt prefill -> + second worker local generation, and confirm no stale-KV or token-hash + failure occurs. + +If any step regresses, fix or document the regression in +`artifacts/issue-304/failure-cases.md` before declaring Phase 5 +complete. + +## Phase 5 Exit Gate + +Phase 5 is complete when: + +- A single boolean flag (`--local-decode`) is parsed by + `ds4_dist_parse_cli_arg()` and recognized by `ds4`, `ds4-server`, + `ds4-bench`, `ds4-agent`, and `ds4-eval` `--help`. +- The flag is read only by the worker. The coordinator's startup path + is unchanged. +- The flag succeeds in the narrow current configuration (worker role + with `--layers N:output`, on the final hop of a single-worker + route) and fails with the documented message in every other + configuration, regardless of which frontend passed it in. +- `--local-decode` implies full worker residency and advertises that + capability in HELLO. +- The coordinator pushes its KV shard after distributed prefill, and + the worker owns local generation through the existing local-generate + request/response path. +- Reusable coordinator sessions catch up their local KV from the + generated token ids returned by the worker before accepting another + prompt. One-off coordinator sessions may skip catch-up. +- The CLI invocation produces the same kind of timing data the + Phase 4 helper produces. +- Both `Metal -> CUDA` and `CUDA -> Metal` pass at least once on the + authoritative DGX/Mac topology. +- The regression test in `tests/ds4_test.c` runs (or cleanly skips) + under `make test`. +- The decision log, runbook, perf breakdown, logit comparisons, and + compatibility matrix all have a Phase 5 entry. +- The README has at least one paragraph about the handoff workflow. +- The failure cases doc lists the user-visible negative cases the new + flag can produce. + +## Out Of Scope For Phase 5 + +These are explicitly deferred to later phases and should not block Phase 5: + +- Pipelined / incremental KV return (Phase 6). The in-memory buffer + path from work item 4b is a prerequisite for this: it removes the + disk IO so the remaining cost is wire time plus memory copies. + Pipelining then re-orders the chunked transfer relative to + prefill. +- Topology decoupling (Phase 9). +- Multi-worker route handoff (deferred to topology work). +- Strict same-token parity on a reused Metal worker (carried forward as a + Phase 3.5-class caveat). +- New official/local-golden vector cases (revisit after Phase 6 if needed). +- Wire-to-GPU streaming (defer; the in-memory buffer path is enough + for current payload sizes). From e2bd47abb8473996f087798d01196e923b3ae1b5 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 17:27:48 +0100 Subject: [PATCH 11/17] phase 5 first implementation with initial tests --- Makefile | 12 +- artifacts/issue-304/compatibility-matrix.md | 8 + artifacts/issue-304/decision-log.md | 43 ++ .../in-memory-payload-investigation.md | 37 + artifacts/issue-304/perf-breakdown.md | 33 + artifacts/issue-304/phase5-plan.md | 39 + artifacts/issue-304/research-notes.md | 53 ++ artifacts/issue-304/runbook.md | 73 ++ ds4.c | 566 ++++++++++---- ds4.h | 23 + ds4_cli.c | 50 ++ ds4_distributed.c | 523 ++++++++++--- tests/ds4_test.c | 238 +++++- tests/issue304_phase5_multiturn.c | 719 ++++++++++++++++++ 14 files changed, 2140 insertions(+), 277 deletions(-) create mode 100644 tests/issue304_phase5_multiturn.c diff --git a/Makefile b/Makefile index e975ed43a..d064973a7 100644 --- a/Makefile +++ b/Makefile @@ -260,6 +260,16 @@ else $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase4_handoff.o $(CORE_OBJS) $(CUDA_LDLIBS) endif +tests/issue304_phase5_multiturn.o: tests/issue304_phase5_multiturn.c ds4.h ds4_distributed.h + $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase5_multiturn.c + +tests/issue304_phase5_multiturn: tests/issue304_phase5_multiturn.o $(CORE_OBJS) +ifeq ($(UNAME_S),Darwin) + $(CC) $(CFLAGS) -o $@ tests/issue304_phase5_multiturn.o $(CORE_OBJS) $(METAL_LDLIBS) +else + $(NVCC) $(NVCCFLAGS) -o $@ tests/issue304_phase5_multiturn.o $(CORE_OBJS) $(CUDA_LDLIBS) +endif + tests/issue304_phase4_diagnose.o: tests/issue304_phase4_diagnose.c ds4.h ds4_distributed.h $(CC) $(CFLAGS) -c -o $@ tests/issue304_phase4_diagnose.c @@ -289,4 +299,4 @@ q4k-dot-test: tests/test_q4k_dot.c ./tests/test_q4k_dot clean: - rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o tests/issue304_phase2_handoff tests/issue304_phase2_handoff.o tests/issue304_phase3_vectors tests/issue304_phase3_vectors.o tests/issue304_phase35_vectors tests/issue304_phase35_vectors.o tests/issue304_phase4_handoff tests/issue304_phase4_handoff.o + rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test tests/test_q4k_dot *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/issue304_phase0_local tests/issue304_phase0_local.o tests/issue304_phase0_dgx tests/issue304_phase0_dgx.o tests/issue304_phase1_matrix tests/issue304_phase1_matrix.o tests/issue304_phase2_handoff tests/issue304_phase2_handoff.o tests/issue304_phase3_vectors tests/issue304_phase3_vectors.o tests/issue304_phase35_vectors tests/issue304_phase35_vectors.o tests/issue304_phase4_handoff tests/issue304_phase4_handoff.o tests/issue304_phase5_multiturn tests/issue304_phase5_multiturn.o diff --git a/artifacts/issue-304/compatibility-matrix.md b/artifacts/issue-304/compatibility-matrix.md index 76afe267e..d1556a5d7 100644 --- a/artifacts/issue-304/compatibility-matrix.md +++ b/artifacts/issue-304/compatibility-matrix.md @@ -37,6 +37,14 @@ | 2026-06-04 | local working tree synced to `dgx-direct:~/ds4`, remote host `ilo037@10.77.0.2`, worker/runtime `--power 50` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | routes `1-6`: local CUDA, local Metal, distributed `CUDA -> Metal`, distributed `Metal -> CUDA`, resumed `CUDA -> Metal`, resumed `Metal -> CUDA` | official vectors, worst@5, all four official cases | Mixed | Official top-logprob behavior was route-dependent. `short_code_completion` failed official acceptance on routes `1`, `3`, and `5`, but passed on routes `2`, `4`, and `6`. All six routes passed official acceptance for `short_italian_fact`, `short_reasoning_plain`, and `long_code_audit`. Resumed routes still showed weaker parity than direct generation: e.g. `short_reasoning_plain` route `5` `top64=61/64`, `rms=0.382280707`; route `6` `top20=18/20`, `top64=59/64`, `rms=0.504765928`. | | 2026-06-04 | local working tree synced to `dgx-direct:~/ds4`, remote host `ilo037@10.77.0.2`, worker/runtime `--power 50` | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | routes `1-6` | local-golden frontier `long_story_4096`, worst@5 | Mixed | Route `2` pure local Metal did not satisfy the stored local-golden fixture (`top5=3/5`, `top20=16/20`, `top64=46/64`, `top20_max_abs=5.2168293`), while routes `1`, `3`, `4`, `5`, and `6` all passed the coarse golden gate. Same-route parity remained exact for direct generation routes `2-4`, but resumed routes stayed loose against their direct-route references: route `5` `top5=3/5`, `top20=13/20`, `top64=42/64`, `rms=2.14919782`; route `6` `top5=3/5`, `top20=14/20`, `top64=40/64`, `rms=1.60283542`. | +## Phase 5: CLI worker-owned local decode + +| Date | Commit | Model | Route | Validation path | Result | Notes | +| --- | --- | --- | --- | --- | --- | --- | +| 2026-06-05 | local working tree after `--local-decode` CLI and stream-handoff changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `Metal -> CUDA`, `0:21 -> 22:output` | plain `ds4` CLI, worker `--local-decode`, one-shot greedy coordinator `--temp 0 --debug`, full `README.md` | Pass | Route formed cleanly, worker advertised `local_decode=1`, distributed prefill reached `603.15 tok/s`, KV handoff moved `105,725,160` bytes in `0.345 s`, and worker local generation completed at `13.08 tok/s`. | +| 2026-06-05 | local working tree after `--local-decode` CLI and stream-handoff changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `CUDA -> Metal`, `0:21 -> 22:output` | plain `ds4` CLI, fresh Metal worker `--local-decode`, DGX one-shot greedy coordinator `--temp 0 --debug`, full `README.md` | Pass | Fresh Metal worker run matched the authoritative validation rule. Distributed prefill reached `589.93 tok/s`, KV handoff moved `107,097,320` bytes in `0.350 s`, and worker local generation completed at `30.33 tok/s`. | +| 2026-06-05 | local working tree after `--local-decode` CLI and stream-handoff changes | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | pure local Metal baseline | plain `ds4` CLI, full `README.md` | Pass | Reference Mac-only baseline on the same prompt: prefill `413.44 tok/s`, generation `34.78 tok/s`. | + ## Representative `DSVL` shard smoke | Date | Commit | Backend | Layer | Result | Notes | diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index 8a1e8bc4a..4393fdec6 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -341,3 +341,46 @@ Implications: - Phase 4 answered its actual question: the final-worker residency and in-process handoff workflow is viable and benchmarkable. - The remaining reused-Metal-worker drift should not block Phase 5+ work unless those phases require strict repeated token parity on a long-lived Metal worker. - Research documentation should now describe Phase 4 as complete with an operational validation caveat, not as an open residency/workflow question. + +## 2026-06-05: Phase 5 should ship the worker-owned CLI path first, without KV pipelining + +Decision: + +- Treat the current worker-owned `--local-decode` CLI path as the Phase 5 + implementation baseline. +- Keep KV pipelining out of Phase 5. +- Keep the existing `LOCAL_GENERATE` protocol surface for now; do not add a + new catch-up or decode message family just to finish the first user-visible + path. + +Evidence: + +- `--local-decode` now: + - parses in the shared distributed CLI layer, + - requires worker role plus `N:output`, + - implies full worker residency, + - and is advertised in HELLO/route metadata. +- The coordinator now pushes its own KV shard directly from the live session + with stream-based `DSVL` helpers; the temp-file detour is removed from the + Phase 5 handoff path. +- Reusable sessions now have coordinator catch-up from returned worker token + ids, while one-shot CLI can ignore catch-up and exit after printing. +- Plain CLI measurements on 2026-06-05 showed: + - `Metal -> CUDA`, full `README.md`: prefill `603.15 tok/s`, KV handoff + `0.345 s` for `105,725,160` bytes, generation `13.08 tok/s` + - `CUDA -> Metal`, fresh Metal worker, full `README.md`: prefill + `589.93 tok/s`, KV handoff `0.350 s` for `107,097,320` bytes, + generation `30.33 tok/s` + - pure local Mac baseline, full `README.md`: generation `34.78 tok/s` + +Why this changes the next steps: + +- The current bottleneck is not KV handoff throughput. At roughly `100 MiB` + the handoff stayed near `0.35 s`, which is small relative to the + `23-25 s` distributed prefill runs. +- The next product-level gap is not transport but surface coverage: + the worker-owned path is currently wired into greedy one-shot coordinator + runs, not yet into the normal sampled distributed eval path. +- That makes the most defensible next task explicit: + extend the user-facing decode surfaces only after preserving the current + simple worker protocol and measured handoff cost. diff --git a/artifacts/issue-304/in-memory-payload-investigation.md b/artifacts/issue-304/in-memory-payload-investigation.md index a642818fa..d9b367d8b 100644 --- a/artifacts/issue-304/in-memory-payload-investigation.md +++ b/artifacts/issue-304/in-memory-payload-investigation.md @@ -226,6 +226,43 @@ it removes the only significant runtime cost of the current snapshot framing. Phase 6 can then target pipelining or wire-to-GPU streaming for further optimization. +## 2026-06-05 implementation update + +This recommendation is now implemented on the Phase 5 handoff path. + +What landed: + +- `ds4_session_save_layer_payload_stream()` +- `ds4_session_load_layer_payload_stream()` +- stream-based coordinator KV push directly from the owning session +- stream-based worker restore directly into the resident decode session + +What did not land: + +- no public staging-size tuning flag +- no broader rewrite of every existing distributed save/load path +- no KV pipelining during prefill + +Measured CLI handoff timings with the new stream path: + +| Route | Prompt | Tokens | Payload bytes | Handoff sec | Effective MiB/s | +| --- | --- | ---: | ---: | ---: | ---: | +| `Metal -> CUDA` | `ping` | 10 | 6,564,072 | 0.025 | 248.27 | +| `Metal -> CUDA` | `README` 4 KiB slice | 958 | 18,091,240 | 0.055 | 313.91 | +| `Metal -> CUDA` | full `README.md` | 14,318 | 105,725,160 | 0.345 | 292.47 | +| `CUDA -> Metal` | `ping` | 10 | 6,564,072 | 0.019 | 335.60 | +| `CUDA -> Metal` | full `README.md` | 14,524 | 107,097,320 | 0.350 | 291.42 | + +Interpretation: + +- The stream path keeps handoff as a small linear tail relative to + 24-second-class distributed prefill runs. +- At roughly 100 MiB payload size the handoff stayed around `0.35 s` in + both directions. +- That is small enough that Phase 5 does not need KV pipelining for + throughput. Pipelining can stay deferred unless first-token latency for + very short generations becomes the priority metric. + ## Code touchpoints - `ds4.c` diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md index 49c9b428e..a1f182da9 100644 --- a/artifacts/issue-304/perf-breakdown.md +++ b/artifacts/issue-304/perf-breakdown.md @@ -1,5 +1,38 @@ # Issue 304 Performance Breakdown +## Phase 5 CLI worker-owned local-decode timings + +These measurements use the plain `ds4` CLI and the in-process final-worker +handoff path with stream-based KV transfer. The coordinator was run with +`--debug` so the new KV handoff timing line was emitted directly from the +user-visible path. + +### 2026-06-05 CLI measurements + +| Route | Prompt | Prompt tokens | KV bytes | KV handoff sec | KV MiB/s | Prefill tok/s | Worker/local generation tok/s | Notes | +| --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | +| `Metal -> CUDA` | `ping` | 10 | 6,564,072 | 0.025 | 248.27 | 14.27 | 14.88 | tiny prompt sanity check | +| `Metal -> CUDA` | README 4 KiB slice | 958 | 18,091,240 | 0.055 | 313.91 | 314.80 | 14.13 | mid-sized prompt | +| `Metal -> CUDA` | full `README.md` | 14,318 | 105,725,160 | 0.345 | 292.47 | 603.15 | 13.08 | reused CUDA worker | +| `CUDA -> Metal` | `ping` | 10 | 6,564,072 | 0.019 | 335.60 | 10.87 | 38.69 | fresh Metal worker | +| `CUDA -> Metal` | full `README.md` | 14,524 | 107,097,320 | 0.350 | 291.42 | 589.93 | 30.33 | fresh Metal worker | +| local Mac baseline | full `README.md` | 14,318 | n/a | n/a | n/a | 413.44 | 34.78 | no distributed route | + +Interpretation: + +- For long prompts, distributed prefill still dominates runtime. The new KV + handoff stayed around `0.35 s` for roughly `100 MiB` payloads in both + directions. +- That keeps KV handoff in the "small tail" category relative to + `23-25 s` distributed prefill on the README prompt. +- On the Mac decode side, worker-owned local generation reached + `30.33 tok/s` against a pure local Mac baseline of `34.78 tok/s`, which + is close enough that the main performance question is no longer decode + throughput. +- For very short generations the one-time handoff can still matter to + first-token latency, but the current data does not justify KV pipelining + for throughput-oriented Phase 5 benchmarking. + ## Phase 4 final-worker handoff timings Tool: diff --git a/artifacts/issue-304/phase5-plan.md b/artifacts/issue-304/phase5-plan.md index 704c2324e..cadb68ac3 100644 --- a/artifacts/issue-304/phase5-plan.md +++ b/artifacts/issue-304/phase5-plan.md @@ -6,6 +6,45 @@ variance forensics, does not change residency, and does not change route topolog It is the smallest step that turns `tests/issue304_phase4_handoff` into something a real frontend can call. +## 2026-06-05 implementation status + +Phase 5 is now partially implemented in the main CLI/runtime path. + +Implemented: + +- `--local-decode` is parsed by the shared distributed CLI parser and is + accepted only on worker processes that own `N:output`. +- `--local-decode` implies full worker residency and is advertised in + HELLO/route metadata. +- The coordinator pushes its local KV shard to the output-owning worker + after distributed prefill using stream-based `DSVL` helpers; the + temp-file detour was removed from this handoff path. +- Reusable coordinator sessions catch up their local slice from the + generated token ids returned by worker local generation. +- One-shot greedy CLI coordinator runs (`--temp 0`) now attempt the + worker-owned handoff path directly. + +Measured on 2026-06-05 with the plain `ds4` CLI: + +- `Metal -> CUDA`, full `README.md`, `ctx=16384`: + - distributed prefill: `603.15 tok/s` + - KV handoff: `105,725,160` bytes in `0.345 s` (`292.47 MiB/s`) + - worker local generation: `13.08 tok/s` +- `CUDA -> Metal`, fresh Metal worker, full `README.md`, `ctx=16384`: + - distributed prefill: `589.93 tok/s` + - KV handoff: `107,097,320` bytes in `0.350 s` (`291.42 MiB/s`) + - worker local generation: `30.33 tok/s` +- Pure local Mac baseline, full `README.md`, `ctx=16384`: + - local prefill: `413.44 tok/s` + - local generation: `34.78 tok/s` + +Current limitation: + +- The worker-owned handoff is wired into the one-shot greedy coordinator + path. The normal sampled distributed `ds4_session_eval(token)` path is + still the old per-token distributed decode surface, so full sampled + coordinator/server delegation remains follow-on work. + ## Source documents - `PLAN.md` Phase 5 section defines the goal, candidate options, and decision criteria. diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index b529bd3e7..9c23b6094 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -370,3 +370,56 @@ The remaining work should separate: - backend-specific generation variance on long prompts, - fixture drift in `local-golden.vec`, - and any additional error introduced specifically by distributed payload resume. + +## Phase 5: CLI worker-owned local decode + +### What was completed + +- Landed the worker-owned `--local-decode` CLI/runtime path. +- Made `--local-decode` imply full worker residency and advertise through + HELLO/route metadata. +- Replaced the Phase 5 handoff temp-file path with stream-based `DSVL` + save/load helpers. +- Added coordinator catch-up from returned worker token ids for reusable + sessions. +- Validated the path with the plain `ds4` CLI in both backend directions. + +### Findings + +1. The user-visible worker-owned path now exists without a harness. + - One-shot greedy coordinator runs (`--temp 0`) can prefill over the + distributed route, push the coordinator KV shard, and let the + output-owning worker finish generation. + +2. KV handoff cost is measurable but small relative to prefill. + - `Metal -> CUDA`, full `README.md`: + - prompt tokens `14,318` + - KV bytes `105,725,160` + - handoff `0.345 s` + - prefill `603.15 tok/s` + - `CUDA -> Metal`, fresh Metal worker, full `README.md`: + - prompt tokens `14,524` + - KV bytes `107,097,320` + - handoff `0.350 s` + - prefill `589.93 tok/s` + +3. Local decode on the Mac side is close to the pure local baseline. + - `CUDA -> Metal` worker-owned local generation reached `30.33 tok/s`. + - Pure local Mac generation on the same `README.md` prompt reached + `34.78 tok/s`. + - That is close enough that Phase 5 no longer needs to justify itself on + decode throughput alone. + +4. The remaining surface gap is protocol usage, not handoff mechanics. + - The current worker-owned path is wired into the greedy one-shot + coordinator flow. + - The normal sampled distributed eval/decode path is still the older + token-by-token coordinator-owned surface. + +### Implication + +Phase 5 has crossed the implementation threshold: the intended CLI workflow +is real, benchmarkable, and no longer dependent on the issue harnesses. +The next work should focus on extending surface coverage and preserving +correctness for reusable/sample-driven flows, not on adding KV pipelining +prematurely. diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md index 35d8bcee5..d2d202f2b 100644 --- a/artifacts/issue-304/runbook.md +++ b/artifacts/issue-304/runbook.md @@ -1,5 +1,78 @@ # Issue 304 Runbook +## Phase 5 worker-owned local-decode workflow + +Phase 5 now has a CLI-visible path. Use these rules for authoritative +validation: + +- use the plain `ds4` CLI, not the older issue harnesses, when validating + the user-visible workflow, +- `--local-decode` belongs on the worker that owns `N:output`, +- `--local-decode` implies full worker residency, +- for strict `CUDA -> Metal` checks, start a fresh Metal worker process, +- for `Metal -> CUDA`, a reused CUDA worker remains acceptable coverage, +- pass `--debug` on the coordinator to record the KV handoff timing line. + +The coordinator now logs: + +```text +ds4: distributed coordinator: local-decode KV handoff tokens=... layers=... bytes=... total=... MiB/s worker=... +``` + +This is the timing surface to use when deciding whether KV pipelining is +worth implementing. + +### CLI commands + +`Metal -> CUDA` worker startup on DGX: + +```sh +ssh dgx-direct 'pkill -9 ds4 >/dev/null 2>&1 || true; sh -c "cd ~/ds4; nohup ./ds4 -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --local-decode --coordinator 10.77.0.1 1234 >/tmp/ds4-phase5-worker.log 2>&1 < /dev/null &"' +``` + +`Metal -> CUDA` one-shot coordinator run on the Mac: + +```sh +./ds4 -m ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --temp 0 --nothink --role coordinator --layers 0:21 --listen 10.77.0.1 1234 --prompt-file README.md -n 8 --debug +``` + +`CUDA -> Metal` fresh worker startup on the Mac: + +```sh +./ds4 -m ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --local-decode --coordinator 10.77.0.2 1234 +``` + +`CUDA -> Metal` one-shot coordinator run on DGX: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./ds4 -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --temp 0 --nothink --role coordinator --layers 0:21 --listen 10.77.0.2 1234 --prompt-file README.md -n 8 --debug' +``` + +### Authoritative 2026-06-05 CLI timings + +| Route | Prompt | Prompt tokens | KV handoff bytes | KV handoff sec | Prefill tok/s | Generation tok/s | +| --- | --- | ---: | ---: | ---: | ---: | ---: | +| `Metal -> CUDA` | `ping` | 10 | 6,564,072 | 0.025 | 14.27 | 14.88 | +| `Metal -> CUDA` | README 4 KiB slice | 958 | 18,091,240 | 0.055 | 314.80 | 14.13 | +| `Metal -> CUDA` | full `README.md` | 14,318 | 105,725,160 | 0.345 | 603.15 | 13.08 | +| `CUDA -> Metal` | `ping` | 10 | 6,564,072 | 0.019 | 10.87 | 38.69 | +| `CUDA -> Metal` | full `README.md` | 14,524 | 107,097,320 | 0.350 | 589.93 | 30.33 | + +Reference local Mac baseline: + +```sh +./ds4 -m ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --temp 0 --nothink --prompt-file README.md -n 8 +``` + +- full `README.md`: prefill `413.44 tok/s`, generation `34.78 tok/s` + +Current limitation: + +- the worker-owned handoff is wired into the greedy one-shot coordinator + path. Normal sampled distributed decode/server reuse still needs follow-on + work, even though reusable coordinators now have catch-up logic in the + session layer. + ## Phase 4 closeout rules Phase 4 is complete. Use these rules for ongoing validation and follow-on work: diff --git a/ds4.c b/ds4.c index 13256af51..2b92c7542 100644 --- a/ds4.c +++ b/ds4.c @@ -17911,6 +17911,43 @@ static DS4_MAYBE_UNUSED int payload_read_u32(FILE *fp, uint32_t *v, uint64_t *re return 0; } +static int payload_file_write_cb(void *ud, const void *ptr, uint64_t bytes, + char *err, size_t errlen) { + return payload_write_bytes((FILE *)ud, ptr, bytes, err, errlen); +} + +static int payload_file_read_cb(void *ud, void *ptr, uint64_t bytes, + char *err, size_t errlen) { + return payload_read_bytes((FILE *)ud, ptr, bytes, NULL, err, errlen); +} + +static int payload_stream_write_u32(ds4_payload_write_fn write_fn, + void *write_ud, + uint32_t v, + char *err, + size_t errlen) { + uint8_t b[4]; + payload_put_u32(b, v); + return write_fn(write_ud, b, sizeof(b), err, errlen); +} + +static int payload_stream_read_u32(ds4_payload_read_fn read_fn, + void *read_ud, + uint32_t *v, + uint64_t *remaining, + char *err, + size_t errlen) { + uint8_t b[4]; + if (remaining && *remaining < sizeof(b)) { + payload_set_err(err, errlen, "truncated session payload"); + return 1; + } + if (read_fn(read_ud, b, sizeof(b), err, errlen) != 0) return 1; + if (remaining) *remaining -= sizeof(b); + *v = payload_get_u32(b); + return 0; +} + static int payload_copy_file_bytes(FILE *src, FILE *dst, uint64_t bytes, char *err, size_t errlen) { uint8_t *buf = xmalloc(DS4_SESSION_IO_CHUNK); int rc = 0; @@ -18003,6 +18040,34 @@ static int payload_write_tensor_span(FILE *fp, const ds4_gpu_tensor *tensor, return 0; } +static int payload_write_tensor_span_stream(ds4_payload_write_fn write_fn, + void *write_ud, + const ds4_gpu_tensor *tensor, + uint64_t offset, + uint64_t bytes, + uint8_t *buf, + size_t cap, + char *err, + size_t errlen) { + if (!tensor || offset > ds4_gpu_tensor_bytes(tensor) || + bytes > ds4_gpu_tensor_bytes(tensor) - offset) + { + payload_set_err(err, errlen, "session tensor is smaller than the payload"); + return 1; + } + uint64_t done = 0; + while (done < bytes) { + const size_t n = bytes - done > (uint64_t)cap ? cap : (size_t)(bytes - done); + if (ds4_gpu_tensor_read(tensor, offset + done, buf, n) == 0) { + payload_set_err(err, errlen, "failed to read accelerator session tensor"); + return 1; + } + if (write_fn(write_ud, buf, n, err, errlen) != 0) return 1; + done += n; + } + return 0; +} + static int payload_read_tensor_span(FILE *fp, ds4_gpu_tensor *tensor, uint64_t offset, uint64_t bytes, uint8_t *buf, size_t cap, uint64_t *remaining, @@ -18026,6 +18091,40 @@ static int payload_read_tensor_span(FILE *fp, ds4_gpu_tensor *tensor, return 0; } +static int payload_read_tensor_span_stream(ds4_payload_read_fn read_fn, + void *read_ud, + ds4_gpu_tensor *tensor, + uint64_t offset, + uint64_t bytes, + uint8_t *buf, + size_t cap, + uint64_t *remaining, + char *err, + size_t errlen) { + if (!tensor || offset > ds4_gpu_tensor_bytes(tensor) || + bytes > ds4_gpu_tensor_bytes(tensor) - offset) + { + payload_set_err(err, errlen, "session tensor is smaller than the payload"); + return 1; + } + uint64_t done = 0; + while (done < bytes) { + const size_t n = bytes - done > (uint64_t)cap ? cap : (size_t)(bytes - done); + if (remaining && *remaining < n) { + payload_set_err(err, errlen, "truncated session payload"); + return 1; + } + if (read_fn(read_ud, buf, n, err, errlen) != 0) return 1; + if (remaining) *remaining -= n; + if (ds4_gpu_tensor_write(tensor, offset + done, buf, n) == 0) { + payload_set_err(err, errlen, "failed to restore accelerator session tensor"); + return 1; + } + done += n; + } + return 0; +} + static DS4_MAYBE_UNUSED int payload_write_tensor_span_f16_as_f32(FILE *fp, const ds4_gpu_tensor *tensor, uint64_t offset_f16, uint64_t count, uint8_t *buf, size_t cap, char *err, size_t errlen) { @@ -18065,6 +18164,52 @@ static DS4_MAYBE_UNUSED int payload_write_tensor_span_f16_as_f32(FILE *fp, const return 0; } +static DS4_MAYBE_UNUSED int payload_write_tensor_span_f16_as_f32_stream( + ds4_payload_write_fn write_fn, + void *write_ud, + const ds4_gpu_tensor *tensor, + uint64_t offset_f16, + uint64_t count, + uint8_t *buf, + size_t cap, + char *err, + size_t errlen) { + if (!tensor || + count > (UINT64_MAX / sizeof(uint16_t)) || + count > (UINT64_MAX / sizeof(float)) || + offset_f16 > ds4_gpu_tensor_bytes(tensor) || + count * sizeof(uint16_t) > ds4_gpu_tensor_bytes(tensor) - offset_f16) + { + payload_set_err(err, errlen, "session tensor is smaller than the F16 payload"); + return 1; + } + + size_t cap_elems = cap / (sizeof(uint16_t) + sizeof(float)); + cap_elems &= ~(size_t)1u; + if (cap_elems == 0) { + payload_set_err(err, errlen, "session tensor conversion buffer is too small"); + return 1; + } + uint16_t *h = (uint16_t *)buf; + float *f = (float *)(void *)(buf + cap_elems * sizeof(uint16_t)); + + uint64_t done = 0; + while (done < count) { + const size_t n = count - done > (uint64_t)cap_elems + ? cap_elems + : (size_t)(count - done); + if (ds4_gpu_tensor_read(tensor, offset_f16 + done * sizeof(uint16_t), + h, n * sizeof(uint16_t)) == 0) { + payload_set_err(err, errlen, "failed to read Metal F16 session tensor"); + return 1; + } + for (size_t i = 0; i < n; i++) f[i] = f16_to_f32(h[i]); + if (write_fn(write_ud, f, (uint64_t)n * sizeof(float), err, errlen) != 0) return 1; + done += n; + } + return 0; +} + static DS4_MAYBE_UNUSED int payload_read_tensor_span_f32_as_f16(FILE *fp, ds4_gpu_tensor *tensor, uint64_t offset_f16, uint64_t count, uint8_t *buf, size_t cap, uint64_t *remaining, @@ -18104,6 +18249,58 @@ static DS4_MAYBE_UNUSED int payload_read_tensor_span_f32_as_f16(FILE *fp, ds4_gp } return 0; } + +static DS4_MAYBE_UNUSED int payload_read_tensor_span_f32_as_f16_stream( + ds4_payload_read_fn read_fn, + void *read_ud, + ds4_gpu_tensor *tensor, + uint64_t offset_f16, + uint64_t count, + uint8_t *buf, + size_t cap, + uint64_t *remaining, + char *err, + size_t errlen) { + if (!tensor || + count > (UINT64_MAX / sizeof(uint16_t)) || + count > (UINT64_MAX / sizeof(float)) || + offset_f16 > ds4_gpu_tensor_bytes(tensor) || + count * sizeof(uint16_t) > ds4_gpu_tensor_bytes(tensor) - offset_f16) + { + payload_set_err(err, errlen, "session tensor is smaller than the F16 payload"); + return 1; + } + + size_t cap_elems = cap / (sizeof(uint16_t) + sizeof(float)); + cap_elems &= ~(size_t)1u; + if (cap_elems == 0) { + payload_set_err(err, errlen, "session tensor conversion buffer is too small"); + return 1; + } + uint16_t *h = (uint16_t *)buf; + float *f = (float *)(void *)(buf + cap_elems * sizeof(uint16_t)); + + uint64_t done = 0; + while (done < count) { + const size_t n = count - done > (uint64_t)cap_elems + ? cap_elems + : (size_t)(count - done); + if (remaining && *remaining < (uint64_t)n * sizeof(float)) { + payload_set_err(err, errlen, "truncated session payload"); + return 1; + } + if (read_fn(read_ud, f, (uint64_t)n * sizeof(float), err, errlen) != 0) return 1; + if (remaining) *remaining -= (uint64_t)n * sizeof(float); + for (size_t i = 0; i < n; i++) h[i] = f32_to_f16(f[i]); + if (ds4_gpu_tensor_write(tensor, offset_f16 + done * sizeof(uint16_t), + h, n * sizeof(uint16_t)) == 0) { + payload_set_err(err, errlen, "failed to restore Metal F16 session tensor"); + return 1; + } + done += n; + } + return 0; +} #endif static bool ds4_session_is_cpu(const ds4_session *s) { @@ -18194,10 +18391,14 @@ uint64_t ds4_session_layer_payload_bytes(ds4_session *s, #endif } -int ds4_session_save_layer_payload(ds4_session *s, FILE *fp, - uint32_t layer_start, uint32_t layer_end, - char *err, size_t errlen) { - if (!s || !fp || !s->checkpoint_valid || +int ds4_session_save_layer_payload_stream(ds4_session *s, + ds4_payload_write_fn write_fn, + void *write_ud, + uint32_t layer_start, + uint32_t layer_end, + char *err, + size_t errlen) { + if (!s || !write_fn || !s->checkpoint_valid || !ds4_layer_payload_range_valid(layer_start, layer_end)) { payload_set_err(err, errlen, "invalid session layer payload save"); return 1; @@ -18234,13 +18435,13 @@ int ds4_session_save_layer_payload(ds4_session *s, FILE *fp, raw_live, }; for (uint32_t i = 0; i < DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS; i++) { - if (payload_write_u32(fp, header[i], err, errlen) != 0) return 1; + if (payload_stream_write_u32(write_fn, write_ud, header[i], err, errlen) != 0) return 1; } for (uint32_t il = layer_start; il <= layer_end; il++) { - if (payload_write_u32(fp, g->layer_n_comp[il], err, errlen) != 0) return 1; + if (payload_stream_write_u32(write_fn, write_ud, g->layer_n_comp[il], err, errlen) != 0) return 1; } for (uint32_t il = layer_start; il <= layer_end; il++) { - if (payload_write_u32(fp, g->layer_n_index_comp[il], err, errlen) != 0) return 1; + if (payload_stream_write_u32(write_fn, write_ud, g->layer_n_index_comp[il], err, errlen) != 0) return 1; } uint8_t *buf = xmalloc(DS4_SESSION_IO_CHUNK); @@ -18250,77 +18451,85 @@ int ds4_session_save_layer_payload(ds4_session *s, FILE *fp, for (uint32_t r = 0; rc == 0 && r < raw_live; r++) { const uint32_t pos = raw_first + r; const uint32_t phys = pos % g->raw_cap; - rc = payload_write_tensor_span(fp, - g->layer_raw_cache[il], - (uint64_t)phys * DS4_N_HEAD_DIM * sizeof(float), - (uint64_t)DS4_N_HEAD_DIM * sizeof(float), - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); + rc = payload_write_tensor_span_stream(write_fn, + write_ud, + g->layer_raw_cache[il], + (uint64_t)phys * DS4_N_HEAD_DIM * sizeof(float), + (uint64_t)DS4_N_HEAD_DIM * sizeof(float), + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); } const uint32_t ratio = ds4_layer_compress_ratio(il); if (rc != 0 || ratio == 0) continue; if (DS4_GPU_ATTN_COMP_CACHE_F16) { - rc = payload_write_tensor_span_f16_as_f32(fp, - g->layer_attn_comp_cache[il], - 0, - (uint64_t)g->layer_n_comp[il] * DS4_N_HEAD_DIM, - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); + rc = payload_write_tensor_span_f16_as_f32_stream(write_fn, + write_ud, + g->layer_attn_comp_cache[il], + 0, + (uint64_t)g->layer_n_comp[il] * DS4_N_HEAD_DIM, + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); } else { - rc = payload_write_tensor_span(fp, - g->layer_attn_comp_cache[il], - 0, - (uint64_t)g->layer_n_comp[il] * DS4_N_HEAD_DIM * sizeof(float), - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); - } - if (rc == 0) rc = payload_write_tensor_span(fp, - g->layer_attn_state_kv[il], - 0, - layer_attn_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); - if (rc == 0) rc = payload_write_tensor_span(fp, - g->layer_attn_state_score[il], - 0, - layer_attn_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); + rc = payload_write_tensor_span_stream(write_fn, + write_ud, + g->layer_attn_comp_cache[il], + 0, + (uint64_t)g->layer_n_comp[il] * DS4_N_HEAD_DIM * sizeof(float), + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); + } + if (rc == 0) rc = payload_write_tensor_span_stream(write_fn, + write_ud, + g->layer_attn_state_kv[il], + 0, + layer_attn_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); + if (rc == 0) rc = payload_write_tensor_span_stream(write_fn, + write_ud, + g->layer_attn_state_score[il], + 0, + layer_attn_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); if (rc == 0 && ratio == 4) { - rc = payload_write_tensor_span(fp, - g->layer_index_comp_cache[il], - 0, - (uint64_t)g->layer_n_index_comp[il] * DS4_N_INDEXER_HEAD_DIM * sizeof(float), - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); - if (rc == 0) rc = payload_write_tensor_span(fp, - g->layer_index_state_kv[il], - 0, - layer_index_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); - if (rc == 0) rc = payload_write_tensor_span(fp, - g->layer_index_state_score[il], - 0, - layer_index_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - err, - errlen); + rc = payload_write_tensor_span_stream(write_fn, + write_ud, + g->layer_index_comp_cache[il], + 0, + (uint64_t)g->layer_n_index_comp[il] * DS4_N_INDEXER_HEAD_DIM * sizeof(float), + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); + if (rc == 0) rc = payload_write_tensor_span_stream(write_fn, + write_ud, + g->layer_index_state_kv[il], + 0, + layer_index_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); + if (rc == 0) rc = payload_write_tensor_span_stream(write_fn, + write_ud, + g->layer_index_state_score[il], + 0, + layer_index_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + err, + errlen); } } free(buf); @@ -18328,12 +18537,33 @@ int ds4_session_save_layer_payload(ds4_session *s, FILE *fp, #endif } -int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, - uint64_t payload_bytes, - const int *tokens, uint32_t n_tokens, +int ds4_session_save_layer_payload(ds4_session *s, FILE *fp, uint32_t layer_start, uint32_t layer_end, char *err, size_t errlen) { - if (!s || !fp || !tokens || + if (!fp) { + payload_set_err(err, errlen, "invalid session layer payload save"); + return 1; + } + return ds4_session_save_layer_payload_stream(s, + payload_file_write_cb, + fp, + layer_start, + layer_end, + err, + errlen); +} + +int ds4_session_load_layer_payload_stream(ds4_session *s, + ds4_payload_read_fn read_fn, + void *read_ud, + uint64_t payload_bytes, + const int *tokens, + uint32_t n_tokens, + uint32_t layer_start, + uint32_t layer_end, + char *err, + size_t errlen) { + if (!s || !read_fn || !tokens || !ds4_layer_payload_range_valid(layer_start, layer_end)) { payload_set_err(err, errlen, "invalid session layer payload load"); return 1; @@ -18351,7 +18581,7 @@ int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, uint64_t remaining = payload_bytes; uint32_t h[DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS]; for (uint32_t i = 0; i < DS4_SESSION_LAYER_PAYLOAD_U32_FIELDS; i++) { - if (payload_read_u32(fp, &h[i], &remaining, err, errlen) != 0) return 1; + if (payload_stream_read_u32(read_fn, read_ud, &h[i], &remaining, err, errlen) != 0) return 1; } if (h[0] != DS4_SESSION_LAYER_PAYLOAD_MAGIC || h[1] != DS4_SESSION_LAYER_PAYLOAD_VERSION) { @@ -18405,7 +18635,7 @@ int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, uint32_t *n_index_comp = xcalloc(n_layers, sizeof(n_index_comp[0])); for (uint32_t i = 0; i < n_layers; i++) { const uint32_t il = layer_start + i; - if (payload_read_u32(fp, &n_comp[i], &remaining, err, errlen) != 0) { + if (payload_stream_read_u32(read_fn, read_ud, &n_comp[i], &remaining, err, errlen) != 0) { free(n_comp); free(n_index_comp); return 1; @@ -18419,7 +18649,7 @@ int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, } for (uint32_t i = 0; i < n_layers; i++) { const uint32_t il = layer_start + i; - if (payload_read_u32(fp, &n_index_comp[i], &remaining, err, errlen) != 0) { + if (payload_stream_read_u32(read_fn, read_ud, &n_index_comp[i], &remaining, err, errlen) != 0) { free(n_comp); free(n_index_comp); return 1; @@ -18450,85 +18680,93 @@ int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, for (uint32_t r = 0; rc == 0 && r < saved_raw_live; r++) { const uint32_t pos = raw_first + r; const uint32_t phys = pos % g->raw_cap; - rc = payload_read_tensor_span(fp, - g->layer_raw_cache[il], - (uint64_t)phys * DS4_N_HEAD_DIM * sizeof(float), - (uint64_t)DS4_N_HEAD_DIM * sizeof(float), - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); + rc = payload_read_tensor_span_stream(read_fn, + read_ud, + g->layer_raw_cache[il], + (uint64_t)phys * DS4_N_HEAD_DIM * sizeof(float), + (uint64_t)DS4_N_HEAD_DIM * sizeof(float), + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); } const uint32_t ratio = ds4_layer_compress_ratio(il); if (rc != 0 || ratio == 0) continue; if (DS4_GPU_ATTN_COMP_CACHE_F16) { - rc = payload_read_tensor_span_f32_as_f16(fp, - g->layer_attn_comp_cache[il], - 0, - (uint64_t)n_comp[i] * DS4_N_HEAD_DIM, - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); + rc = payload_read_tensor_span_f32_as_f16_stream(read_fn, + read_ud, + g->layer_attn_comp_cache[il], + 0, + (uint64_t)n_comp[i] * DS4_N_HEAD_DIM, + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); } else { - rc = payload_read_tensor_span(fp, - g->layer_attn_comp_cache[il], - 0, - (uint64_t)n_comp[i] * DS4_N_HEAD_DIM * sizeof(float), - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); + rc = payload_read_tensor_span_stream(read_fn, + read_ud, + g->layer_attn_comp_cache[il], + 0, + (uint64_t)n_comp[i] * DS4_N_HEAD_DIM * sizeof(float), + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); } - if (rc == 0) rc = payload_read_tensor_span(fp, - g->layer_attn_state_kv[il], - 0, - layer_attn_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); - if (rc == 0) rc = payload_read_tensor_span(fp, - g->layer_attn_state_score[il], - 0, - layer_attn_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); + if (rc == 0) rc = payload_read_tensor_span_stream(read_fn, + read_ud, + g->layer_attn_state_kv[il], + 0, + layer_attn_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); + if (rc == 0) rc = payload_read_tensor_span_stream(read_fn, + read_ud, + g->layer_attn_state_score[il], + 0, + layer_attn_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); if (rc == 0 && ratio == 4) { - rc = payload_read_tensor_span(fp, - g->layer_index_comp_cache[il], - 0, - (uint64_t)n_index_comp[i] * DS4_N_INDEXER_HEAD_DIM * sizeof(float), - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); - if (rc == 0) rc = payload_read_tensor_span(fp, - g->layer_index_state_kv[il], - 0, - layer_index_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); - if (rc == 0) rc = payload_read_tensor_span(fp, - g->layer_index_state_score[il], - 0, - layer_index_state_bytes(ratio), - buf, - DS4_SESSION_IO_CHUNK, - &remaining, - err, - errlen); + rc = payload_read_tensor_span_stream(read_fn, + read_ud, + g->layer_index_comp_cache[il], + 0, + (uint64_t)n_index_comp[i] * DS4_N_INDEXER_HEAD_DIM * sizeof(float), + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); + if (rc == 0) rc = payload_read_tensor_span_stream(read_fn, + read_ud, + g->layer_index_state_kv[il], + 0, + layer_index_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); + if (rc == 0) rc = payload_read_tensor_span_stream(read_fn, + read_ud, + g->layer_index_state_score[il], + 0, + layer_index_state_bytes(ratio), + buf, + DS4_SESSION_IO_CHUNK, + &remaining, + err, + errlen); } } free(buf); @@ -18559,6 +18797,27 @@ int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, #endif } +int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, + uint64_t payload_bytes, + const int *tokens, uint32_t n_tokens, + uint32_t layer_start, uint32_t layer_end, + char *err, size_t errlen) { + if (!fp) { + payload_set_err(err, errlen, "invalid session layer payload load"); + return 1; + } + return ds4_session_load_layer_payload_stream(s, + payload_file_read_cb, + fp, + payload_bytes, + tokens, + n_tokens, + layer_start, + layer_end, + err, + errlen); +} + int ds4_engine_routed_quant_bits(ds4_engine *e) { if (!e) return 0; for (uint32_t il = 0; il < DS4_N_LAYER; il++) { @@ -20017,8 +20276,9 @@ int ds4_engine_open(ds4_engine **out, const ds4_engine_options *opt) { bool load_output_optional = false; const bool full_resident_worker = opt->distributed.role == DS4_DISTRIBUTED_WORKER && - getenv("DS4_DIST_WORKER_FULL_RESIDENT") != NULL && - strcmp(getenv("DS4_DIST_WORKER_FULL_RESIDENT"), "0") != 0; + (opt->distributed.local_decode || + (getenv("DS4_DIST_WORKER_FULL_RESIDENT") != NULL && + strcmp(getenv("DS4_DIST_WORKER_FULL_RESIDENT"), "0") != 0)); if (opt->distributed.role != DS4_DISTRIBUTED_NONE && opt->distributed.layers.set && !full_resident_worker) diff --git a/ds4.h b/ds4.h index 9f94b368c..6ed355c58 100644 --- a/ds4.h +++ b/ds4.h @@ -82,6 +82,7 @@ typedef struct { uint32_t prefill_chunk; uint32_t prefill_window; uint32_t activation_bits; + bool local_decode; bool replay_check; bool debug; } ds4_distributed_options; @@ -131,6 +132,11 @@ typedef struct { uint64_t bytes; } ds4_session_payload_file; +typedef int (*ds4_payload_write_fn)(void *ud, const void *ptr, uint64_t bytes, + char *err, size_t errlen); +typedef int (*ds4_payload_read_fn)(void *ud, void *ptr, uint64_t bytes, + char *err, size_t errlen); + int ds4_engine_open(ds4_engine **out, const ds4_engine_options *opt); void ds4_engine_close(ds4_engine *e); void ds4_engine_summary(ds4_engine *e); @@ -331,9 +337,26 @@ void ds4_session_snapshot_free(ds4_session_snapshot *snap); uint64_t ds4_session_layer_payload_bytes(ds4_session *s, uint32_t layer_start, uint32_t layer_end); +int ds4_session_save_layer_payload_stream(ds4_session *s, + ds4_payload_write_fn write_fn, + void *write_ud, + uint32_t layer_start, + uint32_t layer_end, + char *err, + size_t errlen); int ds4_session_save_layer_payload(ds4_session *s, FILE *fp, uint32_t layer_start, uint32_t layer_end, char *err, size_t errlen); +int ds4_session_load_layer_payload_stream(ds4_session *s, + ds4_payload_read_fn read_fn, + void *read_ud, + uint64_t payload_bytes, + const int *tokens, + uint32_t n_tokens, + uint32_t layer_start, + uint32_t layer_end, + char *err, + size_t errlen); int ds4_session_load_layer_payload(ds4_session *s, FILE *fp, uint64_t payload_bytes, const int *tokens, uint32_t n_tokens, diff --git a/ds4_cli.c b/ds4_cli.c index 298aad401..0fc32433c 100644 --- a/ds4_cli.c +++ b/ds4_cli.c @@ -456,6 +456,56 @@ static int run_sampled_generation(ds4_engine *engine, const cli_config *cfg, con if (room <= 1) max_tokens = 0; else if (max_tokens > room - 1) max_tokens = room - 1; + if (cli_distributed_coordinator(cfg) && + cfg->gen.temperature <= 0.0f && + max_tokens > 0) { + int *handoff_tokens = calloc((size_t)max_tokens, sizeof(handoff_tokens[0])); + if (!handoff_tokens) { + fprintf(stderr, "ds4: out of memory allocating handoff tokens\n"); + ds4_session_free(session); + return 1; + } + double shard_load_s = 0.0; + double worker_decode_s = 0.0; + cli_dist_busy_set(cfg, true); + const int handoff_rc = ds4_session_distributed_handoff_argmax(session, + max_tokens, + handoff_tokens, + max_tokens, + &shard_load_s, + &worker_decode_s, + err, + sizeof(err)); + cli_dist_busy_set(cfg, false); + if (handoff_rc >= 0) { + for (int i = 0; i < handoff_rc; i++) { + if (handoff_tokens[i] == ds4_token_eos(engine)) break; + size_t piece_len = 0; + char *piece = ds4_token_text(engine, handoff_tokens[i], &piece_len); + token_printer_write_text(&printer, piece, piece_len); + fflush(stdout); + free(piece); + } + generation_done(&printer); + if (cli_interrupt_requested()) cli_interrupt_clear(); + const double prefill_s = t_prefill1 - t_prefill0; + ds4_log(stderr, + DS4_LOG_TIMING, + "ds4: prefill: %.2f t/s, generation: %.2f t/s\n", + prefill_s > 0.0 ? (double)prompt->len / prefill_s : 0.0, + worker_decode_s > 0.0 ? (double)handoff_rc / worker_decode_s : 0.0); + free(handoff_tokens); + ds4_session_free(session); + return 0; + } + free(handoff_tokens); + if (strstr(err, "distributed handoff requires") == NULL) { + fprintf(stderr, "ds4: decode failed: %s\n", err); + ds4_session_free(session); + return 1; + } + } + uint64_t rng = cfg->gen.seed ? cfg->gen.seed : ((uint64_t)time(NULL) ^ ((uint64_t)getpid() << 32) ^ (uint64_t)clock()); int generated = 0; diff --git a/ds4_distributed.c b/ds4_distributed.c index c6c98ebfe..f8c56a10e 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #define DS4_DIST_MSG_LOCAL_GENERATE_REQ 10u #define DS4_DIST_MSG_LOCAL_GENERATE_RES 11u #define DS4_DIST_MAX_MODEL_NAME 127u +#define DS4_DIST_HELLO_F_LOCAL_DECODE 0x00000001u #define DS4_DIST_WORK_F_INPUT_HC 0x00000001u #define DS4_DIST_WORK_F_OUTPUT_LOGITS 0x00000002u #define DS4_DIST_WORK_F_RESET_SESSION 0x00000004u @@ -67,6 +69,7 @@ #define DS4_DIST_RESULT_LOGITS 2u #define DS4_DIST_ACTIVATION_BITS_DEFAULT 32u #define DS4_DIST_ROUTE_F_OUTPUT_LOGITS 0x00000001u +#define DS4_DIST_ROUTE_F_LOCAL_DECODE 0x00000002u #define DS4_DIST_ROUTE_RETURN_UPSTREAM 1u #define DS4_DIST_RECV_TRANSPORT_ERROR 1 #define DS4_DIST_RECV_REMOTE_ERROR 2 @@ -89,6 +92,7 @@ typedef struct { uint32_t n_layers; uint32_t listen_port; uint32_t model_name_len; + uint32_t flags; } ds4_dist_hello_fixed; typedef struct { @@ -250,6 +254,7 @@ typedef struct ds4_dist_worker_entry { uint32_t ctx_size; uint32_t n_layers; uint32_t listen_port; + bool wants_local_decode; struct ds4_dist_worker_entry *next; } ds4_dist_worker_entry; @@ -300,6 +305,8 @@ typedef struct { uint32_t layer_start; uint32_t layer_end; bool has_output; + bool local_decode; + bool full_resident; int ctx_size; int listen_fd; pthread_mutex_t mu; @@ -385,6 +392,7 @@ typedef struct { uint32_t layer_start; uint32_t layer_end; uint32_t flags; + bool wants_local_decode; int fd; } ds4_dist_route_entry; @@ -429,6 +437,7 @@ struct ds4_dist_session { uint64_t plan_generation; uint64_t session_id; uint64_t request_id; + bool local_decode_active; }; typedef struct { @@ -563,6 +572,24 @@ static int dist_coordinator_prefill_prompt( float *logits, char *err, size_t errlen); +static int dist_load_remote_shard_from_session( + ds4_dist_session *d, + const ds4_dist_route_entry *entry, + ds4_session *owner, + const int *tokens, + uint32_t token_count, + uint64_t token_hash, + uint32_t layer_start, + uint32_t layer_end, + char *err, + size_t errlen); +static int dist_coordinator_catch_up_generated_tokens( + ds4_dist_session *d, + ds4_session *owner, + const int *tokens, + uint32_t token_count, + char *err, + size_t errlen); static int dist_validate_options(const ds4_dist_options *opt, char *err, size_t errlen); static uint32_t dist_resolved_layer_end(const ds4_dist_options *opt, uint32_t n_layers) { @@ -584,6 +611,11 @@ static bool dist_worker_full_resident_enabled(void) { return env && env[0] && strcmp(env, "0") != 0; } +static bool dist_worker_full_resident_requested(const ds4_dist_options *opt) { + return (opt && opt->role == DS4_DISTRIBUTED_WORKER && opt->local_decode) || + dist_worker_full_resident_enabled(); +} + static void dist_sleep_reconnect(void) { sleep(1); } @@ -1496,6 +1528,7 @@ static void dist_hello_to_wire(ds4_dist_hello_fixed *h) { h->n_layers = htonl(h->n_layers); h->listen_port = htonl(h->listen_port); h->model_name_len = htonl(h->model_name_len); + h->flags = htonl(h->flags); } static void dist_hello_from_wire(ds4_dist_hello_fixed *h) { @@ -1509,6 +1542,7 @@ static void dist_hello_from_wire(ds4_dist_hello_fixed *h) { h->n_layers = ntohl(h->n_layers); h->listen_port = ntohl(h->listen_port); h->model_name_len = ntohl(h->model_name_len); + h->flags = ntohl(h->flags); } static uint64_t dist_u64_from_halves(uint32_t hi, uint32_t lo) { @@ -1861,7 +1895,8 @@ static int dist_send_hello(ds4_engine *engine, const ds4_dist_options *opt, int ctx_size > 0 ? (uint32_t)ctx_size : 0u, n_layers, listen_port, - (uint32_t)model_name_len + (uint32_t)model_name_len, + opt->local_decode ? DS4_DIST_HELLO_F_LOCAL_DECODE : 0u, }; ds4_dist_hello_fixed wire = h; dist_hello_to_wire(&wire); @@ -1964,6 +1999,7 @@ static void dist_coordinator_add_worker( entry->ctx_size = hello->ctx_size; entry->n_layers = hello->n_layers; entry->listen_port = hello->listen_port; + entry->wants_local_decode = (hello->flags & DS4_DIST_HELLO_F_LOCAL_DECODE) != 0; pthread_mutex_lock(&state->mu); if (state->shutting_down) { @@ -2002,7 +2038,7 @@ static void dist_coordinator_add_worker( if (entry->has_output) snprintf(layer_end, sizeof(layer_end), "output"); else snprintf(layer_end, sizeof(layer_end), "%u", entry->layer_end); DIST_COORD_DEBUG(state, - "ds4: distributed coordinator: registered worker %s:%s data_port=%u model_id=%u quant=Q%u layers=%u:%s hidden=%u ctx=%u\n", + "ds4: distributed coordinator: registered worker %s:%s data_port=%u model_id=%u quant=Q%u layers=%u:%s hidden=%u ctx=%u%s\n", entry->peer_host, entry->peer_port, entry->listen_port, @@ -2011,7 +2047,8 @@ static void dist_coordinator_add_worker( entry->layer_start, layer_end, entry->has_hidden, - entry->ctx_size); + entry->ctx_size, + entry->wants_local_decode ? " local_decode=1" : ""); if (dist_coordinator_debug_enabled(state)) dist_coordinator_report_plan(state); } @@ -2407,7 +2444,9 @@ static bool dist_coordinator_build_route_plan( entry.port = w->listen_port; entry.layer_start = w->layer_start; entry.layer_end = w->layer_end; - entry.flags = w->has_output ? DS4_DIST_ROUTE_F_OUTPUT_LOGITS : 0u; + entry.flags = (w->has_output ? DS4_DIST_ROUTE_F_OUTPUT_LOGITS : 0u) | + (w->wants_local_decode ? DS4_DIST_ROUTE_F_LOCAL_DECODE : 0u); + entry.wants_local_decode = w->wants_local_decode; if (state->use_control_for_work && plan->count == 0) { entry.fd = dup(w->fd); if (entry.fd < 0) { @@ -4351,6 +4390,13 @@ static void *dist_coordinator_client_main(void *arg) { close(fd); return NULL; } + if ((hello.flags & ~DS4_DIST_HELLO_F_LOCAL_DECODE) != 0u) { + snprintf(err, sizeof(err), "invalid worker hello flags 0x%x", hello.flags); + DIST_COORD_DEBUG(state, "ds4: distributed coordinator: rejecting %s:%s: %s\n", peer_host, peer_port, err); + dist_send_error(fd, err); + close(fd); + return NULL; + } if (hello.layer_start >= hello.n_layers || hello.layer_end >= hello.n_layers || hello.layer_end < hello.layer_start) { snprintf(err, sizeof(err), "invalid worker layer range %u:%u for %u layers", hello.layer_start, hello.layer_end, hello.n_layers); DIST_COORD_DEBUG(state, "ds4: distributed coordinator: rejecting %s:%s: %s\n", peer_host, peer_port, err); @@ -4370,6 +4416,13 @@ static void *dist_coordinator_client_main(void *arg) { close(fd); return NULL; } + if ((hello.flags & DS4_DIST_HELLO_F_LOCAL_DECODE) != 0u && !hello.has_output) { + snprintf(err, sizeof(err), "worker local decode requires output head ownership"); + DIST_COORD_DEBUG(state, "ds4: distributed coordinator: rejecting %s:%s: %s\n", peer_host, peer_port, err); + dist_send_error(fd, err); + close(fd); + return NULL; + } if (state->ctx_size != 0 && hello.ctx_size < state->ctx_size) { snprintf(err, sizeof(err), @@ -5802,6 +5855,10 @@ static int dist_session_handoff_argmax_trace( if (errlen) snprintf(err, errlen, "distributed handoff requires worker-owned output head"); return -1; } + if ((entry->flags & DS4_DIST_ROUTE_F_LOCAL_DECODE) == 0u) { + if (errlen) snprintf(err, errlen, "distributed handoff requires worker local-decode capability"); + return -1; + } const ds4_tokens *timeline = ds4_session_tokens(owner); if (!timeline || timeline->len < 0 || (uint64_t)timeline->len > UINT32_MAX) { @@ -5809,43 +5866,37 @@ static int dist_session_handoff_argmax_trace( return -1; } const uint64_t token_hash = dist_token_hash_prefix(timeline->v, (uint32_t)timeline->len); - - FILE *tmp = dist_tmpfile_or_err("dist-handoff-local", err, errlen); - if (!tmp) return -1; + const uint64_t payload_bytes = ds4_session_layer_payload_bytes(owner, + d->state.local_start, + d->state.local_end); int rc = -1; - uint64_t shard_bytes = 0; - if (ds4_session_save_layer_payload(owner, - tmp, - d->state.local_start, - d->state.local_end, - err, - errlen) != 0) { - fclose(tmp); - return -1; - } - if (dist_measure_file(tmp, &shard_bytes, "distributed handoff shard", err, errlen) != 0 || - dist_rewind_file(tmp, "distributed handoff shard", err, errlen) != 0) { - fclose(tmp); - return -1; - } - const double load_t0 = dist_now_sec(); - if (dist_load_remote_shard_from_payload(d, + if (dist_load_remote_shard_from_session(d, entry, - d->state.local_start, - d->state.local_end, + owner, timeline->v, (uint32_t)timeline->len, token_hash, - tmp, - shard_bytes, + d->state.local_start, + d->state.local_end, err, errlen) != 0) { - fclose(tmp); return -1; } const double load_t1 = dist_now_sec(); - fclose(tmp); + const double load_sec = load_t1 - load_t0; + const double load_mib_s = load_sec > 0.0 ? + ((double)payload_bytes / (1024.0 * 1024.0)) / load_sec : 0.0; + DIST_COORD_DEBUG(&d->state, + "ds4: distributed coordinator: local-decode KV handoff tokens=%u layers=%u:%u bytes=%" PRIu64 " total=%.3fs %.2f MiB/s worker=%s:%u\n", + (uint32_t)timeline->len, + d->state.local_start, + d->state.local_end, + payload_bytes, + load_sec, + load_mib_s, + entry->host, + entry->port); const int vocab = ds4_engine_vocab_size(d->state.engine); float *logits = malloc((size_t)vocab * sizeof(logits[0])); @@ -5872,8 +5923,26 @@ static int dist_session_handoff_argmax_trace( err, errlen); free(logits); + if (rc > 0 && + dist_coordinator_catch_up_generated_tokens(d, + owner, + tokens_out, + (uint32_t)rc, + err, + errlen) != 0) { + return -1; + } + if (rc > 0 && logits_trace_out) { + const int vocab = ds4_engine_vocab_size(d->state.engine); + const int trace_values = rc > INT_MAX / vocab ? 0 : rc * vocab; + if (trace_values != 0 && logits_trace_cap >= trace_values) { + (void)ds4_session_set_logits(owner, + logits_trace_out + (size_t)(rc - 1) * (size_t)vocab, + vocab); + } + } if (rc >= 0 && shard_load_sec_out) { - *shard_load_sec_out = load_t1 - load_t0; + *shard_load_sec_out = load_sec; } return rc; } @@ -6642,6 +6711,247 @@ static int dist_send_snapshot_file_chunks(int fd, uint64_t request_id, FILE *fp, return rc; } +typedef struct { + int fd; + uint64_t request_id; +} ds4_dist_snapshot_stream_writer; + +typedef struct { + int fd; + uint64_t request_id; + uint64_t payload_bytes; + uint64_t received; + uint8_t *buf; + uint32_t chunk_bytes; + uint32_t chunk_pos; +} ds4_dist_snapshot_stream_reader; + +static int dist_snapshot_stream_write_cb(void *ud, + const void *ptr, + uint64_t bytes, + char *err, + size_t errlen) { + ds4_dist_snapshot_stream_writer *writer = ud; + const uint8_t *p = ptr; + if (!writer) { + if (errlen) snprintf(err, errlen, "missing distributed snapshot writer"); + return 1; + } + while (bytes != 0) { + const uint32_t n = bytes > DS4_DIST_SNAPSHOT_CHUNK_BYTES ? + DS4_DIST_SNAPSHOT_CHUNK_BYTES : (uint32_t)bytes; + ds4_dist_snapshot_chunk_fixed chunk; + dist_u64_to_halves(writer->request_id, &chunk.request_hi, &chunk.request_lo); + chunk.chunk_bytes = n; + ds4_dist_snapshot_chunk_fixed wire = chunk; + dist_snapshot_chunk_to_wire(&wire); + const uint32_t frame_bytes = (uint32_t)sizeof(wire) + n; + if (dist_write_frame_header(writer->fd, DS4_DIST_MSG_SNAPSHOT_CHUNK, frame_bytes) != 0 || + dist_write_full(writer->fd, &wire, sizeof(wire)) != 0 || + dist_write_full(writer->fd, p, n) != 0) { + if (errlen) snprintf(err, errlen, "failed to send distributed KV shard chunk"); + return 1; + } + p += n; + bytes -= n; + } + return 0; +} + +static int dist_snapshot_stream_read_refill(ds4_dist_snapshot_stream_reader *reader, + char *err, + size_t errlen) { + uint32_t type = 0, bytes = 0; + int rc; + if (!reader || !reader->buf) { + if (errlen) snprintf(err, errlen, "missing distributed snapshot reader"); + return 1; + } + if (reader->received >= reader->payload_bytes) { + if (errlen) snprintf(err, errlen, "distributed KV shard over-read"); + return 1; + } + rc = dist_read_frame_header(reader->fd, &type, &bytes, err, errlen); + if (rc <= 0) { + if (rc == 0 && errlen) snprintf(err, errlen, "distributed worker closed while sending KV shard"); + return 1; + } + if (type != DS4_DIST_MSG_SNAPSHOT_CHUNK || + bytes < sizeof(ds4_dist_snapshot_chunk_fixed)) { + dist_discard_bytes(reader->fd, bytes); + if (errlen) snprintf(err, errlen, "expected distributed KV shard chunk"); + return 1; + } + ds4_dist_snapshot_chunk_fixed chunk; + rc = dist_read_full(reader->fd, &chunk, sizeof(chunk)); + if (rc <= 0) { + if (errlen) snprintf(err, errlen, "failed to read distributed KV shard chunk header"); + return 1; + } + dist_snapshot_chunk_from_wire(&chunk); + reader->chunk_bytes = bytes - (uint32_t)sizeof(chunk); + if (dist_u64_from_halves(chunk.request_hi, chunk.request_lo) != reader->request_id || + chunk.chunk_bytes != reader->chunk_bytes || + reader->chunk_bytes > DS4_DIST_SNAPSHOT_CHUNK_BYTES || + reader->chunk_bytes > reader->payload_bytes - reader->received) { + dist_discard_bytes(reader->fd, reader->chunk_bytes); + if (errlen) snprintf(err, errlen, "invalid distributed KV shard chunk"); + return 1; + } + rc = dist_read_full(reader->fd, reader->buf, reader->chunk_bytes); + if (rc <= 0) { + if (errlen) snprintf(err, errlen, "failed to read distributed KV shard chunk"); + return 1; + } + reader->chunk_pos = 0; + reader->received += reader->chunk_bytes; + return 0; +} + +static int dist_snapshot_stream_read_cb(void *ud, + void *ptr, + uint64_t bytes, + char *err, + size_t errlen) { + ds4_dist_snapshot_stream_reader *reader = ud; + uint8_t *out = ptr; + if (!reader) { + if (errlen) snprintf(err, errlen, "missing distributed snapshot reader"); + return 1; + } + while (bytes != 0) { + if (reader->chunk_pos == reader->chunk_bytes && + dist_snapshot_stream_read_refill(reader, err, errlen) != 0) { + return 1; + } + const uint32_t avail = reader->chunk_bytes - reader->chunk_pos; + const size_t n = bytes < avail ? (size_t)bytes : (size_t)avail; + memcpy(out, reader->buf + reader->chunk_pos, n); + out += n; + reader->chunk_pos += (uint32_t)n; + bytes -= n; + } + return 0; +} + +static int dist_snapshot_stream_discard_remaining(ds4_dist_snapshot_stream_reader *reader, + char *err, + size_t errlen) { + if (!reader) return 1; + reader->chunk_pos = reader->chunk_bytes; + while (reader->received < reader->payload_bytes) { + if (dist_snapshot_stream_read_refill(reader, err, errlen) != 0) return 1; + reader->chunk_pos = reader->chunk_bytes; + } + return 0; +} + +static int dist_load_remote_shard_from_session( + ds4_dist_session *d, + const ds4_dist_route_entry *entry, + ds4_session *owner, + const int *tokens, + uint32_t token_count, + uint64_t token_hash, + uint32_t layer_start, + uint32_t layer_end, + char *err, + size_t errlen) { + const uint64_t payload_bytes = ds4_session_layer_payload_bytes(owner, layer_start, layer_end); + if (payload_bytes == 0) { + if (errlen) snprintf(err, errlen, "distributed handoff shard is empty"); + return 1; + } + + uint64_t request_id = d->request_id++; + int fd = dist_connect_endpoint(entry->host, (int)entry->port, err, errlen); + if (fd < 0) return 1; + + ds4_dist_snapshot_begin_fixed begin; + memset(&begin, 0, sizeof(begin)); + begin.model_id = d->state.model_id; + dist_u64_to_halves(d->session_id, &begin.session_hi, &begin.session_lo); + dist_u64_to_halves(request_id, &begin.request_hi, &begin.request_lo); + dist_u64_to_halves(token_hash, &begin.token_hash_hi, &begin.token_hash_lo); + begin.token_count = token_count; + begin.layer_start = layer_start; + begin.layer_end = layer_end; + dist_u64_to_halves(payload_bytes, &begin.payload_hi, &begin.payload_lo); + begin.token_bytes = token_count * sizeof(uint32_t); + + int rc = 1; + if (dist_write_snapshot_load_begin(fd, &begin, tokens) <= 0) { + if (errlen) snprintf(err, errlen, "failed to send distributed KV shard restore request"); + goto cleanup; + } + + ds4_dist_snapshot_stream_writer writer = { + .fd = fd, + .request_id = request_id, + }; + if (ds4_session_save_layer_payload_stream(owner, + dist_snapshot_stream_write_cb, + &writer, + layer_start, + layer_end, + err, + errlen) != 0) { + goto cleanup; + } + if (dist_read_snapshot_done_frame(fd, request_id, err, errlen) != 0) goto cleanup; + rc = 0; + +cleanup: + close(fd); + return rc; +} + +static int dist_coordinator_catch_up_generated_tokens(ds4_dist_session *d, + ds4_session *owner, + const int *tokens, + uint32_t token_count, + char *err, + size_t errlen) { + if (!d || !owner || !tokens) { + if (errlen) snprintf(err, errlen, "invalid coordinator catch-up request"); + return 1; + } + if (token_count == 0) return 0; + const int cap_i = ds4_session_prefill_cap(owner); + if (cap_i <= 0) { + if (errlen) snprintf(err, errlen, "coordinator catch-up has no prefill capacity"); + return 1; + } + const uint32_t chunk_cap = (uint32_t)cap_i; + const ds4_tokens *timeline = ds4_session_tokens(owner); + if (!timeline || timeline->len < 0) { + if (errlen) snprintf(err, errlen, "coordinator catch-up requires a valid token timeline"); + return 1; + } + uint32_t pos = (uint32_t)timeline->len; + uint32_t done = 0; + while (done < token_count) { + const uint32_t chunk = token_count - done < chunk_cap ? token_count - done : chunk_cap; + if (ds4_session_eval_layer_slice(owner, + tokens + done, + chunk, + pos, + d->state.local_start, + d->state.local_end, + NULL, + NULL, + false, + NULL, + err, + errlen) != 0) { + return 1; + } + pos += chunk; + done += chunk; + } + return 0; +} + /* ========================================================================= * Worker Route Parsing And Forwarding * ========================================================================= */ @@ -6685,6 +6995,7 @@ static bool dist_route_get_entry( out->layer_start = fixed.layer_start; out->layer_end = fixed.layer_end; out->flags = fixed.flags; + out->wants_local_decode = (fixed.flags & DS4_DIST_ROUTE_F_LOCAL_DECODE) != 0; out->fd = -1; return true; } @@ -6814,7 +7125,7 @@ static bool dist_route_validate_blob( if (errlen) snprintf(err, errlen, "invalid route layer range"); return false; } - if ((fixed.flags & ~DS4_DIST_ROUTE_F_OUTPUT_LOGITS) != 0) { + if ((fixed.flags & ~(DS4_DIST_ROUTE_F_OUTPUT_LOGITS | DS4_DIST_ROUTE_F_LOCAL_DECODE)) != 0) { if (errlen) snprintf(err, errlen, "invalid route flags"); return false; } @@ -6823,6 +7134,11 @@ static bool dist_route_validate_blob( if (errlen) snprintf(err, errlen, "route logits require final layer"); return false; } + if ((fixed.flags & DS4_DIST_ROUTE_F_LOCAL_DECODE) != 0 && + (fixed.flags & DS4_DIST_ROUTE_F_OUTPUT_LOGITS) == 0) { + if (errlen) snprintf(err, errlen, "route local decode requires logits ownership"); + return false; + } if (i != 0 && fixed.layer_start != prev_end + 1u) { if (errlen) snprintf(err, errlen, "route layer ranges are not contiguous"); return false; @@ -7722,7 +8038,7 @@ static int dist_worker_handle_snapshot_load( dist_token_hash_prefix(tokens, begin.token_count) != token_hash) { snprintf(err, sizeof(err), "snapshot load token hash mismatch"); } - const bool full_resident_worker = dist_worker_full_resident_enabled(); + const bool full_resident_worker = state->full_resident; if (!err[0] && (begin.model_id != state->model_id || begin.token_count > (uint32_t)state->ctx_size || @@ -7732,90 +8048,31 @@ static int dist_worker_handle_snapshot_load( snprintf(err, sizeof(err), "snapshot load request does not match worker state"); } - FILE *tmp = NULL; - char tmp_path[PATH_MAX]; - if (!err[0] && dist_temp_file("ds4-dist-load", tmp_path, sizeof(tmp_path), &tmp) != 0) { - snprintf(err, sizeof(err), "failed to create worker snapshot restore temp file"); - } - - uint8_t *buf = NULL; + ds4_dist_snapshot_stream_reader reader = { + .fd = upstream->fd, + .request_id = request_id, + .payload_bytes = payload_bytes, + .buf = NULL, + }; if (!err[0]) { - buf = malloc(DS4_DIST_SNAPSHOT_CHUNK_BYTES); - if (!buf) snprintf(err, sizeof(err), "out of memory restoring worker KV shard"); - } - uint64_t received = 0; - while (!err[0] && received < payload_bytes) { - uint32_t type = 0, chunk_frame_bytes = 0; - rc = dist_read_frame_header(upstream->fd, &type, &chunk_frame_bytes, err, sizeof(err)); - if (rc <= 0) { - free(buf); - free(tokens); - if (tmp) fclose(tmp); - if (tmp) unlink(tmp_path); - return rc == 0 ? 0 : -1; - } - if (type != DS4_DIST_MSG_SNAPSHOT_CHUNK || - chunk_frame_bytes < sizeof(ds4_dist_snapshot_chunk_fixed)) { - dist_discard_bytes(upstream->fd, chunk_frame_bytes); - snprintf(err, sizeof(err), "expected distributed snapshot chunk"); - break; - } - ds4_dist_snapshot_chunk_fixed chunk; - rc = dist_read_full(upstream->fd, &chunk, sizeof(chunk)); - if (rc <= 0) { - free(buf); - free(tokens); - if (tmp) fclose(tmp); - if (tmp) unlink(tmp_path); - return rc == 0 ? 0 : -1; - } - dist_snapshot_chunk_from_wire(&chunk); - uint64_t got_request = dist_u64_from_halves(chunk.request_hi, chunk.request_lo); - uint32_t chunk_bytes = chunk_frame_bytes - (uint32_t)sizeof(chunk); - if (got_request != request_id || - chunk.chunk_bytes != chunk_bytes || - chunk_bytes > DS4_DIST_SNAPSHOT_CHUNK_BYTES || - chunk_bytes > payload_bytes - received) { - dist_discard_bytes(upstream->fd, chunk_bytes); - snprintf(err, sizeof(err), "invalid distributed snapshot chunk"); - break; - } - rc = dist_read_full(upstream->fd, buf, chunk_bytes); - if (rc <= 0) { - free(buf); - free(tokens); - if (tmp) fclose(tmp); - if (tmp) unlink(tmp_path); - return rc == 0 ? 0 : -1; - } - if (fwrite(buf, 1, chunk_bytes, tmp) != chunk_bytes) { - snprintf(err, sizeof(err), "failed to write worker KV shard temp file"); - break; - } - received += chunk_bytes; - } - free(buf); - - if (!err[0] && fflush(tmp) != 0) { - snprintf(err, sizeof(err), "failed to flush worker KV shard restore file"); - } - if (!err[0] && fseeko(tmp, 0, SEEK_SET) != 0) { - snprintf(err, sizeof(err), "failed to rewind worker KV shard restore file"); + reader.buf = malloc(DS4_DIST_SNAPSHOT_CHUNK_BYTES); + if (!reader.buf) snprintf(err, sizeof(err), "out of memory restoring worker KV shard"); } if (!err[0]) { pthread_mutex_lock(&state->mu); ds4_dist_worker_session *session = dist_worker_get_session_locked(state, session_id, err, sizeof(err)); if (session && - ds4_session_load_layer_payload(session->session, - tmp, - payload_bytes, - tokens, - begin.token_count, - begin.layer_start, - begin.layer_end, - err, - sizeof(err)) == 0) { + ds4_session_load_layer_payload_stream(session->session, + dist_snapshot_stream_read_cb, + &reader, + payload_bytes, + tokens, + begin.token_count, + begin.layer_start, + begin.layer_end, + err, + sizeof(err)) == 0) { session->token_hash = token_hash; session->token_hash_valid = true; } else { @@ -7824,16 +8081,22 @@ static int dist_worker_handle_snapshot_load( } pthread_mutex_unlock(&state->mu); } - - if (tmp) fclose(tmp); - if (tmp) unlink(tmp_path); + if (err[0] && reader.buf) { + char discard_err[256] = {0}; + (void)dist_snapshot_stream_discard_remaining(&reader, discard_err, sizeof(discard_err)); + } + if (!err[0] && + (reader.received != payload_bytes || reader.chunk_pos != reader.chunk_bytes)) { + snprintf(err, sizeof(err), "worker KV shard payload size mismatch"); + } + free(reader.buf); free(tokens); pthread_mutex_lock(&upstream->write_mu); rc = dist_send_snapshot_done(upstream->fd, request_id, err[0] ? 1u : 0u, err[0] ? err : NULL); pthread_mutex_unlock(&upstream->write_mu); - if (err[0] && received < payload_bytes) return -1; + if (err[0] && reader.received < payload_bytes) return -1; return rc; } @@ -8799,6 +9062,8 @@ static int dist_run_worker(ds4_engine *engine, const ds4_dist_options *opt, int state.layer_start = opt->layers.start; state.layer_end = dist_resolved_layer_end(opt, (uint32_t)ds4_engine_layer_count(engine)); state.has_output = opt->layers.has_output; + state.local_decode = opt->local_decode; + state.full_resident = dist_worker_full_resident_requested(opt); state.ctx_size = ctx_size; state.listen_fd = listen_fd; pthread_mutex_init(&state.mu, NULL); @@ -8812,14 +9077,16 @@ static int dist_run_worker(ds4_engine *engine, const ds4_dist_options *opt, int pthread_detach(data_tid); fprintf(stderr, - "ds4: distributed worker: layers %u:%s model_id=%d data_listen=%s:%u connecting to coordinator %s:%d\n", + "ds4: distributed worker: layers %u:%s model_id=%d data_listen=%s:%u connecting to coordinator %s:%d%s%s\n", opt->layers.start, layer_end, ds4_engine_model_id(engine), listen_host ? listen_host : "*", listen_port, opt->coordinator_host, - opt->coordinator_port); + opt->coordinator_port, + state.local_decode ? " local_decode=1" : "", + state.full_resident ? " full_resident=1" : ""); for (;;) { int fd = dist_connect_endpoint(opt->coordinator_host, opt->coordinator_port, err, sizeof(err)); @@ -8988,6 +9255,8 @@ void ds4_dist_usage(FILE *fp) { " Coordinator TCP listen address. Workers may later use it to force their data listener.\n" " --coordinator HOST PORT\n" " Coordinator TCP address for --role worker.\n" + " --local-decode\n" + " Worker-only: advertise full-resident local decode on an output-owning worker.\n" " --dist-prefill-chunk N\n" " Coordinator prefill pipeline chunk size. Default: session cap, normally 4096.\n" " Non-default values are experimental and can change logits unless validated.\n" @@ -9073,6 +9342,14 @@ ds4_dist_cli_parse_result ds4_dist_parse_cli_arg( opt->coordinator_host = host; return DS4_DIST_CLI_MATCHED; } + if (!strcmp(arg, "--local-decode")) { + if (!opt) { + if (errlen) snprintf(err, errlen, "missing distributed options"); + return DS4_DIST_CLI_ERROR; + } + opt->local_decode = true; + return DS4_DIST_CLI_MATCHED; + } if (!strcmp(arg, "--dist-prefill-chunk")) { if (!opt) { if (errlen) snprintf(err, errlen, "missing distributed options"); @@ -9148,7 +9425,7 @@ static int dist_validate_options(const ds4_dist_options *opt, char *err, size_t if (opt->layers.set || opt->listen_host || opt->listen_port || opt->coordinator_host || opt->coordinator_port || opt->prefill_chunk != 0 || opt->prefill_window != 0 || - opt->activation_bits != 0) { + opt->activation_bits != 0 || opt->local_decode) { if (errlen) snprintf(err, errlen, "distributed options require --role coordinator or --role worker"); return 1; } @@ -9169,6 +9446,10 @@ static int dist_validate_options(const ds4_dist_options *opt, char *err, size_t } if (opt->role == DS4_DISTRIBUTED_COORDINATOR) { + if (opt->local_decode) { + if (errlen) snprintf(err, errlen, "--local-decode requires --role worker"); + return 1; + } if (!opt->listen_host || opt->listen_port <= 0) { if (errlen) snprintf(err, errlen, "--role coordinator requires --listen HOST PORT"); return 1; @@ -9185,6 +9466,10 @@ static int dist_validate_options(const ds4_dist_options *opt, char *err, size_t if (errlen) snprintf(err, errlen, "--role worker requires --coordinator HOST PORT"); return 1; } + if (opt->local_decode && !opt->layers.has_output) { + if (errlen) snprintf(err, errlen, "--local-decode requires --layers N:output"); + return 1; + } if (opt->prefill_chunk != 0) { if (errlen) snprintf(err, errlen, "--dist-prefill-chunk requires --role coordinator"); return 1; @@ -9217,9 +9502,7 @@ int ds4_dist_prepare_engine_options( if (engine && opt) { engine->distributed = *opt; if (ds4_dist_enabled(opt)) { - const bool full_resident_worker = - opt->role == DS4_DISTRIBUTED_WORKER && - dist_worker_full_resident_enabled(); + const bool full_resident_worker = dist_worker_full_resident_requested(opt); if (!full_resident_worker) { engine->load_slice = true; engine->load_layer_start = opt->layers.start; diff --git a/tests/ds4_test.c b/tests/ds4_test.c index 13da4f0b5..3763c52a3 100644 --- a/tests/ds4_test.c +++ b/tests/ds4_test.c @@ -1341,6 +1341,79 @@ static bool test_save_layer_payload_bytes(ds4_session *session, return true; } +typedef struct { + uint8_t *buf; + size_t len; + size_t cap; + size_t pos; +} test_payload_stream_buf; + +static int test_payload_stream_write(void *ud, + const void *ptr, + uint64_t bytes, + char *err, + size_t errlen) { + test_payload_stream_buf *stream = ud; + if (!stream || bytes > (uint64_t)SIZE_MAX) { + if (errlen) snprintf(err, errlen, "invalid test payload stream write"); + return 1; + } + size_t need = stream->len + (size_t)bytes; + if (need > stream->cap) { + size_t new_cap = stream->cap ? stream->cap : 4096u; + while (new_cap < need) new_cap *= 2u; + uint8_t *new_buf = realloc(stream->buf, new_cap); + if (!new_buf) { + if (errlen) snprintf(err, errlen, "out of memory growing test payload stream"); + return 1; + } + stream->buf = new_buf; + stream->cap = new_cap; + } + memcpy(stream->buf + stream->len, ptr, (size_t)bytes); + stream->len += (size_t)bytes; + return 0; +} + +static int test_payload_stream_read(void *ud, + void *ptr, + uint64_t bytes, + char *err, + size_t errlen) { + test_payload_stream_buf *stream = ud; + if (!stream || bytes > (uint64_t)(stream->len - stream->pos)) { + if (errlen) snprintf(err, errlen, "truncated test payload stream"); + return 1; + } + memcpy(ptr, stream->buf + stream->pos, (size_t)bytes); + stream->pos += (size_t)bytes; + return 0; +} + +static bool test_save_layer_payload_stream_bytes(ds4_session *session, + uint32_t layer_start, + uint32_t layer_end, + uint8_t **out, + size_t *len_out) { + test_payload_stream_buf stream = {0}; + char err[160]; + const int rc = ds4_session_save_layer_payload_stream(session, + test_payload_stream_write, + &stream, + layer_start, + layer_end, + err, + sizeof(err)); + TEST_ASSERT(rc == 0); + if (rc != 0) { + free(stream.buf); + return false; + } + *out = stream.buf; + *len_out = stream.len; + return true; +} + static bool test_load_layer_payload_bytes(ds4_session *session, const uint8_t *buf, size_t len, @@ -1371,6 +1444,33 @@ static bool test_load_layer_payload_bytes(ds4_session *session, return rc == 0; } +static bool test_load_layer_payload_stream_bytes(ds4_session *session, + const uint8_t *buf, + size_t len, + const int *tokens, + uint32_t n_tokens, + uint32_t layer_start, + uint32_t layer_end) { + test_payload_stream_buf stream = { + .buf = (uint8_t *)buf, + .len = len, + }; + char err[160]; + const int rc = ds4_session_load_layer_payload_stream(session, + test_payload_stream_read, + &stream, + (uint64_t)len, + tokens, + n_tokens, + layer_start, + layer_end, + err, + sizeof(err)); + TEST_ASSERT(rc == 0); + TEST_ASSERT(stream.pos == len); + return rc == 0 && stream.pos == len; +} + static void test_local_layer_payload_smoke(ds4_engine *engine, const ds4_tokens *prompt, int ctx, @@ -1385,8 +1485,10 @@ static void test_local_layer_payload_smoke(ds4_engine *engine, ds4_session_payload_file full_payload = {0}; test_dsv4_metadata full_meta = {0}; uint8_t *src_buf = NULL; + uint8_t *stream_buf = NULL; uint8_t *roundtrip_buf = NULL; size_t src_len = 0; + size_t stream_len = 0; size_t roundtrip_len = 0; TEST_ASSERT(ds4_session_create(&base, engine, ctx) == 0); @@ -1438,13 +1540,19 @@ static void test_local_layer_payload_smoke(ds4_engine *engine, if (duplicate) continue; free(src_buf); + free(stream_buf); free(roundtrip_buf); src_buf = NULL; + stream_buf = NULL; roundtrip_buf = NULL; src_len = 0; + stream_len = 0; roundtrip_len = 0; TEST_ASSERT(test_save_layer_payload_bytes(base, layer, layer, &src_buf, &src_len)); + TEST_ASSERT(test_save_layer_payload_stream_bytes(base, layer, layer, &stream_buf, &stream_len)); + TEST_ASSERT(src_len == stream_len); + TEST_ASSERT(memcmp(src_buf, stream_buf, src_len) == 0); test_dsvl_metadata dsvl = {0}; TEST_ASSERT(test_parse_dsvl_metadata_bytes(src_buf, src_len, &dsvl)); TEST_ASSERT(dsvl.layer_start == layer); @@ -1455,9 +1563,9 @@ static void test_local_layer_payload_smoke(ds4_engine *engine, TEST_ASSERT(restored != NULL); if (!restored) break; - TEST_ASSERT(test_load_layer_payload_bytes(restored, src_buf, src_len, - prompt->v, (uint32_t)frontier, - layer, layer)); + TEST_ASSERT(test_load_layer_payload_stream_bytes(restored, stream_buf, stream_len, + prompt->v, (uint32_t)frontier, + layer, layer)); TEST_ASSERT(test_save_layer_payload_bytes(restored, layer, layer, &roundtrip_buf, &roundtrip_len)); TEST_ASSERT(src_len == roundtrip_len); @@ -1478,6 +1586,7 @@ static void test_local_layer_payload_smoke(ds4_engine *engine, cleanup: free(src_buf); + free(stream_buf); free(roundtrip_buf); test_dsv4_metadata_free(&full_meta); ds4_session_payload_file_free(&full_payload); @@ -1777,6 +1886,75 @@ static void test_local_payload_resume(void) { test_restore_env("DS4_METAL_PREFILL_CHUNK", saved_prefill_chunk); } +static void test_local_payload_stream(void) { + char *saved_prefill_chunk = test_save_env("DS4_METAL_PREFILL_CHUNK"); + char *saved_disable_metal4 = test_save_env("DS4_METAL_DISABLE_METAL4"); + char *saved_moe_tile_max = test_save_env("DS4_METAL_MOE_TILE_MAX"); + setenv("DS4_METAL_PREFILL_CHUNK", "4096", 1); + setenv("DS4_METAL_DISABLE_METAL4", "1", 1); + unsetenv("DS4_METAL_MOE_TILE_MAX"); + + ds4_engine *engine = test_open_engine(false); + if (!engine) { + test_restore_env("DS4_METAL_MOE_TILE_MAX", saved_moe_tile_max); + test_restore_env("DS4_METAL_DISABLE_METAL4", saved_disable_metal4); + test_restore_env("DS4_METAL_PREFILL_CHUNK", saved_prefill_chunk); + return; + } + + ds4_tokens prompt = {0}; + if (!test_tokenize_phase1_prompt(engine, &prompt)) { + ds4_engine_close(engine); + test_restore_env("DS4_METAL_MOE_TILE_MAX", saved_moe_tile_max); + test_restore_env("DS4_METAL_DISABLE_METAL4", saved_disable_metal4); + test_restore_env("DS4_METAL_PREFILL_CHUNK", saved_prefill_chunk); + return; + } + + ds4_session *base = NULL; + ds4_session *restored = NULL; + uint8_t *file_buf = NULL; + uint8_t *stream_buf = NULL; + uint8_t *roundtrip_buf = NULL; + size_t file_len = 0; + size_t stream_len = 0; + size_t roundtrip_len = 0; + char err[160]; + ds4_tokens prefix = { .v = prompt.v, .len = 1, .cap = 1 }; + + TEST_ASSERT(ds4_session_create(&base, engine, 16384) == 0); + TEST_ASSERT(base != NULL); + TEST_ASSERT(ds4_session_sync(base, &prefix, err, sizeof(err)) == 0); + TEST_ASSERT(test_save_layer_payload_bytes(base, 0, 0, &file_buf, &file_len)); + TEST_ASSERT(test_save_layer_payload_stream_bytes(base, 0, 0, &stream_buf, &stream_len)); + TEST_ASSERT(file_len == stream_len); + TEST_ASSERT(memcmp(file_buf, stream_buf, file_len) == 0); + + TEST_ASSERT(ds4_session_create(&restored, engine, 16384) == 0); + TEST_ASSERT(restored != NULL); + TEST_ASSERT(test_load_layer_payload_stream_bytes(restored, + stream_buf, + stream_len, + prefix.v, + (uint32_t)prefix.len, + 0, + 0)); + TEST_ASSERT(test_save_layer_payload_bytes(restored, 0, 0, &roundtrip_buf, &roundtrip_len)); + TEST_ASSERT(file_len == roundtrip_len); + TEST_ASSERT(memcmp(file_buf, roundtrip_buf, file_len) == 0); + + free(file_buf); + free(stream_buf); + free(roundtrip_buf); + ds4_session_free(restored); + ds4_session_free(base); + ds4_tokens_free(&prompt); + ds4_engine_close(engine); + test_restore_env("DS4_METAL_MOE_TILE_MAX", saved_moe_tile_max); + test_restore_env("DS4_METAL_DISABLE_METAL4", saved_disable_metal4); + test_restore_env("DS4_METAL_PREFILL_CHUNK", saved_prefill_chunk); +} + #define TEST_MPP_EQ_MAX_CASES 8 #define TEST_MPP_EQ_TOPK 20 #define TEST_MPP_EQ_TOP5 5 @@ -2273,6 +2451,58 @@ static void test_server_unit_group(void) { ds4_server_unit_tests_run(); } +static void test_distributed_cli_parse(void) { + ds4_engine_options engine = {0}; + char err[160]; + + ds4_dist_options *worker = ds4_dist_options_create(); + TEST_ASSERT(worker != NULL); + if (!worker) return; + char *worker_argv[] = { + "ds4", + "--role", "worker", + "--layers", "21:output", + "--coordinator", "127.0.0.1", "9000", + "--local-decode", + }; + for (int i = 1; i < (int)(sizeof(worker_argv) / sizeof(worker_argv[0])); i++) { + ds4_dist_cli_parse_result rc = ds4_dist_parse_cli_arg(worker_argv[i], + &i, + (int)(sizeof(worker_argv) / sizeof(worker_argv[0])), + worker_argv, + worker, + err, + sizeof(err)); + TEST_ASSERT(rc == DS4_DIST_CLI_MATCHED); + } + TEST_ASSERT(worker->local_decode); + TEST_ASSERT(ds4_dist_prepare_engine_options(worker, &engine, err, sizeof(err)) == 0); + ds4_dist_options_free(worker); + + ds4_dist_options *invalid = ds4_dist_options_create(); + TEST_ASSERT(invalid != NULL); + if (!invalid) return; + char *invalid_argv[] = { + "ds4", + "--role", "worker", + "--layers", "21:42", + "--coordinator", "127.0.0.1", "9000", + "--local-decode", + }; + for (int i = 1; i < (int)(sizeof(invalid_argv) / sizeof(invalid_argv[0])); i++) { + ds4_dist_cli_parse_result rc = ds4_dist_parse_cli_arg(invalid_argv[i], + &i, + (int)(sizeof(invalid_argv) / sizeof(invalid_argv[0])), + invalid_argv, + invalid, + err, + sizeof(err)); + TEST_ASSERT(rc == DS4_DIST_CLI_MATCHED); + } + TEST_ASSERT(ds4_dist_prepare_engine_options(invalid, &engine, err, sizeof(err)) != 0); + ds4_dist_options_free(invalid); +} + typedef void (*test_fn)(void); typedef struct { @@ -2288,12 +2518,14 @@ static const ds4_test_entry test_entries[] = { {"--tool-call-quality", "tool-call-quality", "model emits valid DSML tool calls", test_tool_call_quality}, {"--logprob-vectors", "logprob-vectors", "official API top-logprob vector comparison on the standard Metal path", test_official_logprob_vectors}, {"--local-payload-resume", "local-payload-resume", "local DSV4 save/load resume and DSVL shard smoke", test_local_payload_resume}, + {"--local-payload-stream", "local-payload-stream", "stream-vs-file DSVL payload roundtrip smoke", test_local_payload_stream}, {"--local-golden-vectors", "local-golden-vectors", "local top-k/logit drift regression for long Metal prefill", test_local_golden_vectors}, {"--metal-short-prefill", "metal-short-prefill", "Metal ratio-4 short prefill regression", test_metal_short_prefill_ratio4}, {"--metal-kernels", "metal-kernels", "isolated Metal kernel numeric regressions", test_metal_kernel_group}, {"--metal-tensor-equivalence", "metal-tensor-equivalence", "fast/quality Metal prompt-logit and greedy equivalence", test_metal_mpp_equivalence}, #endif {"--server", "server", "server parser/rendering/cache unit tests", test_server_unit_group}, + {"--dist-cli-parse", "dist-cli-parse", "distributed CLI parsing and --local-decode validation", test_distributed_cli_parse}, }; static void test_print_help(const char *prog) { diff --git a/tests/issue304_phase5_multiturn.c b/tests/issue304_phase5_multiturn.c new file mode 100644 index 000000000..49786bbe6 --- /dev/null +++ b/tests/issue304_phase5_multiturn.c @@ -0,0 +1,719 @@ +#include "../ds4.h" +#include "../ds4_distributed.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + const char *model_path; + const char *prompt_file; + const char *system_prompt; + const char *followup_prompt; + const char *listen_host; + const char *coordinator_layers; + const char *worker_layers; + const char *lock_file; + int listen_port; + int ctx_size; + int gen_tokens; + uint32_t prefill_chunk; + uint32_t prefill_window; + uint32_t activation_bits; + bool debug; +} phase5_cfg; + +typedef struct { + int *tokens; + int token_count; + double shard_load_sec; + double decode_sec; +} handoff_run; + +typedef struct { + int top1_ref; + int top1_cand; + int top5_overlap; + int top10_overlap; + int top20_overlap; + int nonfinite; + float rms; + float max_abs; + float top20_max_abs; +} parity_metrics; + +static double now_sec(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; +} + +static void die_usage(const char *argv0) { + fprintf(stderr, + "usage: %s --model FILE --listen-host IPV4 --listen-port N " + "[--prompt-file FILE] [--system TEXT] [--followup TEXT] [--ctx N] " + "[--gen-tokens N] [--prefill-chunk N] [--prefill-window N] " + "[--activation-bits N] [--coordinator-layers A:B|A:output] " + "[--worker-layers A:B|A:output] [--lock-file FILE] [--no-debug]\n", + argv0); + exit(2); +} + +static void die(const char *msg) { + fprintf(stderr, "issue304-phase5-multiturn: %s\n", msg); + exit(1); +} + +static char *read_file(const char *path) { + FILE *fp = fopen(path, "rb"); + if (!fp) return NULL; + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + return NULL; + } + long len = ftell(fp); + if (len < 0) { + fclose(fp); + return NULL; + } + rewind(fp); + char *buf = malloc((size_t)len + 1u); + if (!buf) { + fclose(fp); + return NULL; + } + if (len != 0 && fread(buf, 1, (size_t)len, fp) != (size_t)len) { + free(buf); + fclose(fp); + return NULL; + } + fclose(fp); + buf[len] = '\0'; + return buf; +} + +static bool parse_layer_spec(const char *spec, ds4_distributed_layers *out) { + if (!spec || !out) return false; + const char *colon = strchr(spec, ':'); + if (!colon || colon == spec || colon[1] == '\0') return false; + + errno = 0; + char *end = NULL; + unsigned long start = strtoul(spec, &end, 10); + if (errno != 0 || end != colon || start > UINT32_MAX) return false; + + ds4_distributed_layers layers = {0}; + layers.start = (uint32_t)start; + layers.set = true; + if (strcmp(colon + 1, "output") == 0) { + layers.has_output = true; + layers.end = 0; + } else { + errno = 0; + unsigned long layer_end = strtoul(colon + 1, &end, 10); + if (errno != 0 || *end != '\0' || layer_end > UINT32_MAX) return false; + layers.end = (uint32_t)layer_end; + } + *out = layers; + return true; +} + +static bool set_process_lock_file(const char *path, char *err, size_t errlen) { + if (!path || !path[0]) { + snprintf(err, errlen, "invalid lock file path"); + return false; + } + if (setenv("DS4_LOCK_FILE", path, 1) != 0) { + snprintf(err, errlen, "failed to set DS4_LOCK_FILE: %s", strerror(errno)); + return false; + } + return true; +} + +static int wait_route(ds4_session *session, double timeout_sec) { + double deadline = now_sec() + timeout_sec; + while (now_sec() < deadline) { + char err[256] = {0}; + int ready = ds4_session_distributed_route_ready(session, err, sizeof(err)); + if (ready == 1) return 1; + if (ready < 0) { + fprintf(stderr, "issue304-phase5-multiturn: route readiness failed: %s\n", + err[0] ? err : "unknown error"); + return -1; + } + usleep(100000); + } + fprintf(stderr, "issue304-phase5-multiturn: timed out waiting for route\n"); + return 0; +} + +static bool open_distributed_session(const phase5_cfg *cfg, + ds4_engine *engine, + ds4_session **session_out, + char *route_summary, + size_t route_summary_len, + uint32_t *route_hops, + bool *output_on_coordinator) { + *session_out = NULL; + if (ds4_session_create(session_out, engine, cfg->ctx_size) != 0 || !*session_out) { + fprintf(stderr, "issue304-phase5-multiturn: failed to create distributed session\n"); + return false; + } + if (wait_route(*session_out, 60.0) != 1) return false; + + char err[256] = {0}; + if (ds4_session_distributed_route_summary(*session_out, + route_summary, + route_summary_len, + route_hops, + output_on_coordinator, + err, + sizeof(err)) != 1) { + fprintf(stderr, "issue304-phase5-multiturn: route summary failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + return true; +} + +static void handoff_run_free(handoff_run *run) { + free(run->tokens); + memset(run, 0, sizeof(*run)); +} + +static bool run_handoff(ds4_session *session, int max_tokens, handoff_run *out) { + char err[256] = {0}; + memset(out, 0, sizeof(*out)); + out->tokens = calloc((size_t)max_tokens, sizeof(out->tokens[0])); + if (!out->tokens) { + fprintf(stderr, "issue304-phase5-multiturn: out of memory allocating handoff tokens\n"); + return false; + } + + const int rc = ds4_session_distributed_handoff_argmax(session, + max_tokens, + out->tokens, + max_tokens, + &out->shard_load_sec, + &out->decode_sec, + err, + sizeof(err)); + if (rc < 0) { + fprintf(stderr, "issue304-phase5-multiturn: handoff failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + out->token_count = rc; + return true; +} + +static bool tokens_equal(const int *a, int na, const int *b, int nb) { + if (na != nb) return false; + for (int i = 0; i < na; i++) { + if (a[i] != b[i]) return false; + } + return true; +} + +static void logits_topk(const float *logits, int n, int *out, int k) { + for (int i = 0; i < k; i++) out[i] = -1; + for (int i = 0; i < n; i++) { + const float v = logits[i]; + for (int j = 0; j < k; j++) { + if (out[j] < 0 || v > logits[out[j]]) { + for (int t = k - 1; t > j; t--) out[t] = out[t - 1]; + out[j] = i; + break; + } + } + } +} + +static bool topk_contains(const int *top, int k, int id) { + for (int i = 0; i < k; i++) { + if (top[i] == id) return true; + } + return false; +} + +static parity_metrics compare_logits(const float *ref, const float *cand, int vocab) { + int ref_top[64]; + int cand_top[64]; + logits_topk(ref, vocab, ref_top, 64); + logits_topk(cand, vocab, cand_top, 64); + + int top5_overlap = 0; + int top10_overlap = 0; + int top20_overlap = 0; + for (int i = 0; i < 20; i++) { + if (ref_top[i] < 0) continue; + if (i < 5 && topk_contains(cand_top, 5, ref_top[i])) top5_overlap++; + if (i < 10 && topk_contains(cand_top, 10, ref_top[i])) top10_overlap++; + if (topk_contains(cand_top, 20, ref_top[i])) top20_overlap++; + } + + int nonfinite = 0; + double sumsq = 0.0; + float max_abs = 0.0f; + float top20_max_abs = 0.0f; + for (int i = 0; i < vocab; i++) { + if (!isfinite(ref[i]) || !isfinite(cand[i])) { + nonfinite++; + continue; + } + const float delta = cand[i] - ref[i]; + const float abs_delta = fabsf(delta); + if (abs_delta > max_abs) max_abs = abs_delta; + sumsq += (double)delta * (double)delta; + } + for (int i = 0; i < 20; i++) { + const int id = ref_top[i]; + if (id < 0) continue; + const float abs_delta = fabsf(cand[id] - ref[id]); + if (abs_delta > top20_max_abs) top20_max_abs = abs_delta; + } + + parity_metrics out = { + .top1_ref = ref_top[0], + .top1_cand = cand_top[0], + .top5_overlap = top5_overlap, + .top10_overlap = top10_overlap, + .top20_overlap = top20_overlap, + .nonfinite = nonfinite, + .rms = (float)sqrt(sumsq / (double)vocab), + .max_abs = max_abs, + .top20_max_abs = top20_max_abs, + }; + return out; +} + +static char *token_piece_text(ds4_engine *engine, int token) { + size_t len = 0; + char *piece = ds4_token_text(engine, token, &len); + if (!piece) return strdup(""); + char *out = malloc(len + 1u); + if (!out) { + free(piece); + return NULL; + } + memcpy(out, piece, len); + out[len] = '\0'; + free(piece); + return out; +} + +static void print_json_string(const char *s) { + putchar('"'); + for (const unsigned char *p = (const unsigned char *)s; *p; p++) { + unsigned char c = *p; + switch (c) { + case '\\': fputs("\\\\", stdout); break; + case '"': fputs("\\\"", stdout); break; + case '\b': fputs("\\b", stdout); break; + case '\f': fputs("\\f", stdout); break; + case '\n': fputs("\\n", stdout); break; + case '\r': fputs("\\r", stdout); break; + case '\t': fputs("\\t", stdout); break; + default: + if (c < 0x20u) printf("\\u%04x", c); + else putchar((char)c); + break; + } + } + putchar('"'); +} + +static void print_topk_json(ds4_engine *engine, const float *logits, int vocab, int k) { + int top[16]; + if (k > (int)(sizeof(top) / sizeof(top[0]))) k = (int)(sizeof(top) / sizeof(top[0])); + logits_topk(logits, vocab, top, k); + putchar('['); + for (int i = 0; i < k; i++) { + char *piece = token_piece_text(engine, top[i]); + if (i != 0) putchar(','); + printf("{\"id\":%d,\"logit\":%.6f,\"text\":", top[i], logits[top[i]]); + print_json_string(piece ? piece : ""); + printf("}"); + free(piece); + } + putchar(']'); +} + +static char *tokens_render_text(ds4_engine *engine, const int *tokens, int n) { + size_t cap = 128; + size_t len = 0; + char *buf = malloc(cap); + if (!buf) return NULL; + buf[0] = '\0'; + for (int i = 0; i < n; i++) { + size_t piece_len = 0; + char *piece = ds4_token_text(engine, tokens[i], &piece_len); + if (!piece) continue; + if (len + piece_len + 1u > cap) { + size_t need = len + piece_len + 1u; + size_t next = cap; + while (next < need) next *= 2u; + char *grown = realloc(buf, next); + if (!grown) { + free(piece); + free(buf); + return NULL; + } + buf = grown; + cap = next; + } + memcpy(buf + len, piece, piece_len); + len += piece_len; + buf[len] = '\0'; + free(piece); + } + return buf; +} + +static void print_tokens(const int *tokens, int n) { + putchar('['); + for (int i = 0; i < n; i++) { + if (i != 0) putchar(','); + printf("%d", tokens[i]); + } + putchar(']'); +} + +static int visible_token_count(ds4_engine *engine, const int *tokens, int n) { + const int eos = ds4_token_eos(engine); + for (int i = 0; i < n; i++) { + if (tokens[i] == eos) return i; + } + return n; +} + +static void build_followup_prompt(ds4_engine *engine, + const ds4_tokens *base_prompt, + const int *assistant_tokens, + int assistant_count, + const char *followup_prompt, + ds4_tokens *out) { + ds4_tokens_copy(out, base_prompt); + for (int i = 0; i < assistant_count; i++) { + ds4_tokens_push(out, assistant_tokens[i]); + } + ds4_chat_append_message(engine, out, "user", followup_prompt); + ds4_chat_append_assistant_prefix(engine, out, DS4_THINK_NONE); +} + +static void parse_args(phase5_cfg *cfg, int argc, char **argv) { + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--model") && i + 1 < argc) { + cfg->model_path = argv[++i]; + } else if (!strcmp(argv[i], "--prompt-file") && i + 1 < argc) { + cfg->prompt_file = argv[++i]; + } else if (!strcmp(argv[i], "--system") && i + 1 < argc) { + cfg->system_prompt = argv[++i]; + } else if (!strcmp(argv[i], "--followup") && i + 1 < argc) { + cfg->followup_prompt = argv[++i]; + } else if (!strcmp(argv[i], "--listen-host") && i + 1 < argc) { + cfg->listen_host = argv[++i]; + } else if (!strcmp(argv[i], "--listen-port") && i + 1 < argc) { + cfg->listen_port = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--ctx") && i + 1 < argc) { + cfg->ctx_size = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--gen-tokens") && i + 1 < argc) { + cfg->gen_tokens = atoi(argv[++i]); + } else if (!strcmp(argv[i], "--prefill-chunk") && i + 1 < argc) { + cfg->prefill_chunk = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--prefill-window") && i + 1 < argc) { + cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { + cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { + cfg->coordinator_layers = argv[++i]; + } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { + cfg->worker_layers = argv[++i]; + } else if (!strcmp(argv[i], "--lock-file") && i + 1 < argc) { + cfg->lock_file = argv[++i]; + } else if (!strcmp(argv[i], "--no-debug")) { + cfg->debug = false; + } else { + die_usage(argv[0]); + } + } + + if (!cfg->model_path || !cfg->listen_host || cfg->listen_port <= 0) { + die_usage(argv[0]); + } +} + +int main(int argc, char **argv) { + phase5_cfg cfg = { + .system_prompt = "You are a concise assistant.", + .followup_prompt = "Continue with one more short sentence that depends on your previous answer.", + .ctx_size = 16384, + .gen_tokens = 8, + .prefill_chunk = 0, + .prefill_window = 0, + .activation_bits = 0, + .debug = true, + .coordinator_layers = "0:21", + .worker_layers = "22:output", + .lock_file = "/tmp/ds4-phase5-multiturn-coordinator.lock", + }; + parse_args(&cfg, argc, argv); + + char *prompt_text = cfg.prompt_file ? read_file(cfg.prompt_file) : + strdup("Write one short sentence about distributed systems."); + if (!prompt_text) die("failed to read prompt"); + + ds4_distributed_layers coordinator_layers = {0}; + ds4_distributed_layers worker_layers = {0}; + if (!parse_layer_spec(cfg.coordinator_layers, &coordinator_layers) || + !parse_layer_spec(cfg.worker_layers, &worker_layers)) { + die("invalid layer range"); + } + + char err[256] = {0}; + if (!set_process_lock_file(cfg.lock_file, err, sizeof(err))) { + fprintf(stderr, "issue304-phase5-multiturn: %s\n", err); + free(prompt_text); + return 1; + } + + ds4_engine_options opt = { + .model_path = cfg.model_path, +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + .quality = false, + .distributed = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = coordinator_layers, + .listen_host = cfg.listen_host, + .listen_port = cfg.listen_port, + .prefill_chunk = cfg.prefill_chunk, + .prefill_window = cfg.prefill_window, + .activation_bits = cfg.activation_bits, + .debug = cfg.debug, + }, + }; + + if (ds4_dist_prepare_engine_options(&opt.distributed, &opt, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase5-multiturn: distributed options failed: %s\n", + err[0] ? err : "unknown error"); + free(prompt_text); + return 1; + } + + ds4_engine *engine = NULL; + ds4_session *reused = NULL; + ds4_session *fresh = NULL; + ds4_tokens prompt1 = {0}; + ds4_tokens prompt2 = {0}; + handoff_run turn1 = {0}; + handoff_run turn2_reused = {0}; + handoff_run turn2_fresh = {0}; + float *reused_seed_logits = NULL; + float *fresh_seed_logits = NULL; + int rc = 1; + + if (ds4_engine_open(&engine, &opt) != 0 || !engine) { + fprintf(stderr, "issue304-phase5-multiturn: failed to open engine\n"); + goto cleanup; + } + + char route_summary[256] = {0}; + uint32_t route_hops = 0; + bool output_on_coordinator = false; + if (!open_distributed_session(&cfg, + engine, + &reused, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator)) { + goto cleanup; + } + if (output_on_coordinator) { + fprintf(stderr, "issue304-phase5-multiturn: expected worker-owned output head\n"); + goto cleanup; + } + + ds4_encode_chat_prompt(engine, cfg.system_prompt, prompt_text, DS4_THINK_NONE, &prompt1); + if (prompt1.len <= 0) { + fprintf(stderr, "issue304-phase5-multiturn: prompt tokenization failed\n"); + goto cleanup; + } + + printf("PHASE5_MULTITURN_ROUTE summary=%s hops=%u prompt1_tokens=%d\n", + route_summary, route_hops, prompt1.len); + + if (ds4_session_sync(reused, &prompt1, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase5-multiturn: first sync failed: %s\n", + err[0] ? err : "unknown error"); + goto cleanup; + } + + if (!run_handoff(reused, cfg.gen_tokens, &turn1)) goto cleanup; + const int turn1_visible = visible_token_count(engine, turn1.tokens, turn1.token_count); + if (turn1_visible <= 0) { + fprintf(stderr, "issue304-phase5-multiturn: first handoff returned no reusable tokens\n"); + goto cleanup; + } + printf("PHASE5_MULTITURN_TURN1 tokens="); + print_tokens(turn1.tokens, turn1_visible); + printf(" shard_sec=%.6f decode_sec=%.6f checkpoint_pos=%d\n", + turn1.shard_load_sec, + turn1.decode_sec, + ds4_session_pos(reused)); + + build_followup_prompt(engine, + &prompt1, + turn1.tokens, + turn1_visible, + cfg.followup_prompt, + &prompt2); + + const int expected_after_turn1 = prompt1.len + turn1_visible; + if (ds4_session_pos(reused) != expected_after_turn1) { + fprintf(stderr, + "issue304-phase5-multiturn: catch-up checkpoint mismatch after turn1: have %d want %d\n", + ds4_session_pos(reused), + expected_after_turn1); + goto cleanup; + } + + if (ds4_session_sync(reused, &prompt2, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase5-multiturn: reused-session followup sync failed: %s\n", + err[0] ? err : "unknown error"); + goto cleanup; + } + const int vocab = ds4_engine_vocab_size(engine); + reused_seed_logits = malloc((size_t)vocab * sizeof(reused_seed_logits[0])); + fresh_seed_logits = malloc((size_t)vocab * sizeof(fresh_seed_logits[0])); + if (!reused_seed_logits || !fresh_seed_logits) { + fprintf(stderr, "issue304-phase5-multiturn: out of memory for seed logits\n"); + goto cleanup; + } + if (ds4_session_copy_logits(reused, reused_seed_logits, vocab) != vocab) { + fprintf(stderr, "issue304-phase5-multiturn: failed to copy reused seed logits\n"); + goto cleanup; + } + const int reused_argmax = ds4_session_argmax(reused); + + if (!run_handoff(reused, cfg.gen_tokens, &turn2_reused)) { + goto cleanup; + } + printf("PHASE5_MULTITURN_SYNC reused_pos=%d prompt2_tokens=%d\n", + ds4_session_pos(reused), + prompt2.len); + if (ds4_session_pos(reused) != prompt2.len + turn2_reused.token_count) { + fprintf(stderr, "issue304-phase5-multiturn: reused session did not advance through turn2\n"); + goto cleanup; + } + + ds4_session_free(reused); + reused = NULL; + ds4_engine_close(engine); + engine = NULL; + + if (ds4_engine_open(&engine, &opt) != 0 || !engine) { + fprintf(stderr, "issue304-phase5-multiturn: failed to reopen engine for fresh session\n"); + goto cleanup; + } + if (!open_distributed_session(&cfg, + engine, + &fresh, + route_summary, + sizeof(route_summary), + &route_hops, + &output_on_coordinator)) { + goto cleanup; + } + if (ds4_session_sync(fresh, &prompt2, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase5-multiturn: fresh-session followup sync failed: %s\n", + err[0] ? err : "unknown error"); + goto cleanup; + } + if (ds4_session_pos(fresh) != prompt2.len) { + fprintf(stderr, "issue304-phase5-multiturn: fresh session did not reach full followup prompt\n"); + goto cleanup; + } + if (ds4_session_copy_logits(fresh, fresh_seed_logits, vocab) != vocab) { + fprintf(stderr, "issue304-phase5-multiturn: failed to copy fresh seed logits\n"); + goto cleanup; + } + const int fresh_argmax = ds4_session_argmax(fresh); + parity_metrics seed_cmp = compare_logits(fresh_seed_logits, reused_seed_logits, vocab); + int fresh_top5[5]; + int reused_top5[5]; + logits_topk(fresh_seed_logits, vocab, fresh_top5, 5); + logits_topk(reused_seed_logits, vocab, reused_top5, 5); + printf("PHASE5_MULTITURN_ARGMAX reused=%d fresh=%d reused_in_fresh_top5=%s fresh_in_reused_top5=%s\n", + reused_argmax, + fresh_argmax, + topk_contains(fresh_top5, 5, reused_argmax) ? "true" : "false", + topk_contains(reused_top5, 5, fresh_argmax) ? "true" : "false"); + printf("PHASE5_MULTITURN_LOGITS top5=%d top10=%d top20=%d rms=%.8f max_abs=%.8f top20_max_abs=%.8f nonfinite=%d\n", + seed_cmp.top5_overlap, + seed_cmp.top10_overlap, + seed_cmp.top20_overlap, + seed_cmp.rms, + seed_cmp.max_abs, + seed_cmp.top20_max_abs, + seed_cmp.nonfinite); + printf("PHASE5_MULTITURN_TOP5 fresh="); + print_topk_json(engine, fresh_seed_logits, vocab, 5); + printf(" reused="); + print_topk_json(engine, reused_seed_logits, vocab, 5); + printf("\n"); + if (!run_handoff(fresh, cfg.gen_tokens, &turn2_fresh)) { + goto cleanup; + } + + printf("PHASE5_MULTITURN_TURN2 reused="); + print_tokens(turn2_reused.tokens, turn2_reused.token_count); + printf(" fresh="); + print_tokens(turn2_fresh.tokens, turn2_fresh.token_count); + printf("\n"); + + if (!tokens_equal(turn2_reused.tokens, + turn2_reused.token_count, + turn2_fresh.tokens, + turn2_fresh.token_count)) { + char *reused_text = tokens_render_text(engine, turn2_reused.tokens, turn2_reused.token_count); + char *fresh_text = tokens_render_text(engine, turn2_fresh.tokens, turn2_fresh.token_count); + printf("PHASE5_MULTITURN_TEXT reused="); + print_json_string(reused_text ? reused_text : ""); + printf(" fresh="); + print_json_string(fresh_text ? fresh_text : ""); + printf("\n"); + free(reused_text); + free(fresh_text); + fprintf(stderr, "issue304-phase5-multiturn: turn2 mismatch after catch-up reuse\n"); + goto cleanup; + } + + printf("PHASE5_MULTITURN_RESULT pass turn1_visible=%d turn2_tokens=%d\n", + turn1_visible, turn2_reused.token_count); + rc = 0; + +cleanup: + free(fresh_seed_logits); + free(reused_seed_logits); + handoff_run_free(&turn2_fresh); + handoff_run_free(&turn2_reused); + handoff_run_free(&turn1); + ds4_tokens_free(&prompt2); + ds4_tokens_free(&prompt1); + ds4_session_free(fresh); + ds4_session_free(reused); + ds4_engine_close(engine); + free(prompt_text); + return rc; +} From b7ed1ec3d7a8e055f24566a7ec0e4d4ee98296a6 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 17:41:31 +0100 Subject: [PATCH 12/17] phase 5 local decode with sampling --- ds4.c | 36 ++++++++++++ ds4.h | 13 +++++ ds4_cli.c | 23 +++++--- ds4_distributed.c | 144 +++++++++++++++++++++++++++++++++++++--------- ds4_distributed.h | 14 +++++ 5 files changed, 195 insertions(+), 35 deletions(-) diff --git a/ds4.c b/ds4.c index 2b92c7542..5ea16309c 100644 --- a/ds4.c +++ b/ds4.c @@ -20731,6 +20731,42 @@ int ds4_session_distributed_handoff_argmax( errlen); } +int ds4_session_distributed_handoff_generate( + ds4_session *s, + int n_predict, + float temperature, + float top_p, + float min_p, + uint64_t seed, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen) { + if (!s || !s->distributed) { + if (errlen) snprintf(err, errlen, "session is not a distributed coordinator"); + return -1; + } + if (!s->checkpoint_valid) { + if (errlen) snprintf(err, errlen, "distributed handoff requires a valid checkpoint"); + return -1; + } + return ds4_dist_session_handoff_generate(s->distributed, + s, + n_predict, + temperature, + top_p, + min_p, + seed, + tokens_out, + token_cap, + shard_load_sec_out, + decode_sec_out, + err, + errlen); +} + int ds4_session_distributed_handoff_argmax_trace( ds4_session *s, int n_predict, diff --git a/ds4.h b/ds4.h index 6ed355c58..3db0034d4 100644 --- a/ds4.h +++ b/ds4.h @@ -236,6 +236,19 @@ int ds4_session_distributed_handoff_argmax( double *decode_sec_out, char *err, size_t errlen); +int ds4_session_distributed_handoff_generate( + ds4_session *s, + int n_predict, + float temperature, + float top_p, + float min_p, + uint64_t seed, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen); int ds4_session_distributed_handoff_argmax_trace( ds4_session *s, int n_predict, diff --git a/ds4_cli.c b/ds4_cli.c index 0fc32433c..0cddcdeaa 100644 --- a/ds4_cli.c +++ b/ds4_cli.c @@ -457,7 +457,6 @@ static int run_sampled_generation(ds4_engine *engine, const cli_config *cfg, con else if (max_tokens > room - 1) max_tokens = room - 1; if (cli_distributed_coordinator(cfg) && - cfg->gen.temperature <= 0.0f && max_tokens > 0) { int *handoff_tokens = calloc((size_t)max_tokens, sizeof(handoff_tokens[0])); if (!handoff_tokens) { @@ -467,15 +466,21 @@ static int run_sampled_generation(ds4_engine *engine, const cli_config *cfg, con } double shard_load_s = 0.0; double worker_decode_s = 0.0; + uint64_t handoff_rng = cfg->gen.seed ? cfg->gen.seed : + ((uint64_t)time(NULL) ^ ((uint64_t)getpid() << 32) ^ (uint64_t)clock()); cli_dist_busy_set(cfg, true); - const int handoff_rc = ds4_session_distributed_handoff_argmax(session, - max_tokens, - handoff_tokens, - max_tokens, - &shard_load_s, - &worker_decode_s, - err, - sizeof(err)); + const int handoff_rc = ds4_session_distributed_handoff_generate(session, + max_tokens, + cfg->gen.temperature, + cfg->gen.top_p, + cfg->gen.min_p, + handoff_rng, + handoff_tokens, + max_tokens, + &shard_load_s, + &worker_decode_s, + err, + sizeof(err)); cli_dist_busy_set(cfg, false); if (handoff_rc >= 0) { for (int i = 0; i < handoff_rc; i++) { diff --git a/ds4_distributed.c b/ds4_distributed.c index f8c56a10e..662534e5f 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -211,6 +211,11 @@ typedef struct { uint32_t token_hash_hi; uint32_t token_hash_lo; uint32_t n_predict; + uint32_t seed_hi; + uint32_t seed_lo; + uint32_t temperature_bits; + uint32_t top_p_bits; + uint32_t min_p_bits; uint32_t logits_bytes; } ds4_dist_local_generate_req_fixed; @@ -626,6 +631,18 @@ static double dist_now_sec(void) { return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; } +static uint32_t dist_f32_bits(float v) { + uint32_t bits = 0; + memcpy(&bits, &v, sizeof(bits)); + return bits; +} + +static float dist_f32_from_bits(uint32_t bits) { + float v = 0.0f; + memcpy(&v, &bits, sizeof(v)); + return v; +} + /* ========================================================================= * Local File And Size Helpers * ========================================================================= */ @@ -1794,6 +1811,11 @@ static void dist_local_generate_req_to_wire(ds4_dist_local_generate_req_fixed *r r->token_hash_hi = htonl(r->token_hash_hi); r->token_hash_lo = htonl(r->token_hash_lo); r->n_predict = htonl(r->n_predict); + r->seed_hi = htonl(r->seed_hi); + r->seed_lo = htonl(r->seed_lo); + r->temperature_bits = htonl(r->temperature_bits); + r->top_p_bits = htonl(r->top_p_bits); + r->min_p_bits = htonl(r->min_p_bits); r->logits_bytes = htonl(r->logits_bytes); } @@ -1806,6 +1828,11 @@ static void dist_local_generate_req_from_wire(ds4_dist_local_generate_req_fixed r->token_hash_hi = ntohl(r->token_hash_hi); r->token_hash_lo = ntohl(r->token_hash_lo); r->n_predict = ntohl(r->n_predict); + r->seed_hi = ntohl(r->seed_hi); + r->seed_lo = ntohl(r->seed_lo); + r->temperature_bits = ntohl(r->temperature_bits); + r->top_p_bits = ntohl(r->top_p_bits); + r->min_p_bits = ntohl(r->min_p_bits); r->logits_bytes = ntohl(r->logits_bytes); } @@ -4729,6 +4756,10 @@ static int dist_local_generate_remote( uint64_t token_hash, const float *logits, int n_predict, + float temperature, + float top_p, + float min_p, + uint64_t seed, int *tokens_out, int token_cap, float *logits_trace_out, @@ -4764,6 +4795,10 @@ static int dist_local_generate_remote( dist_u64_to_halves(request_id, &req.request_hi, &req.request_lo); dist_u64_to_halves(token_hash, &req.token_hash_hi, &req.token_hash_lo); req.n_predict = (uint32_t)n_predict; + dist_u64_to_halves(seed, &req.seed_hi, &req.seed_lo); + req.temperature_bits = dist_f32_bits(temperature); + req.top_p_bits = dist_f32_bits(top_p); + req.min_p_bits = dist_f32_bits(min_p); req.logits_bytes = logits_bytes; ds4_dist_local_generate_req_fixed wire = req; dist_local_generate_req_to_wire(&wire); @@ -5825,10 +5860,14 @@ int ds4_dist_session_load_payload( return rc; } -static int dist_session_handoff_argmax_trace( +static int dist_session_handoff_generate_trace( ds4_dist_session *d, ds4_session *owner, int n_predict, + float temperature, + float top_p, + float min_p, + uint64_t seed, int *tokens_out, int token_cap, float *logits_trace_out, @@ -5914,6 +5953,10 @@ static int dist_session_handoff_argmax_trace( token_hash, logits, n_predict, + temperature, + top_p, + min_p, + seed, tokens_out, token_cap, logits_trace_out, @@ -5957,18 +6000,54 @@ int ds4_dist_session_handoff_argmax( double *decode_sec_out, char *err, size_t errlen) { - return dist_session_handoff_argmax_trace(d, - owner, - n_predict, - tokens_out, - token_cap, - NULL, - 0, - NULL, - shard_load_sec_out, - decode_sec_out, - err, - errlen); + return dist_session_handoff_generate_trace(d, + owner, + n_predict, + 0.0f, + 1.0f, + 0.0f, + 0u, + tokens_out, + token_cap, + NULL, + 0, + NULL, + shard_load_sec_out, + decode_sec_out, + err, + errlen); +} + +int ds4_dist_session_handoff_generate( + ds4_dist_session *d, + ds4_session *owner, + int n_predict, + float temperature, + float top_p, + float min_p, + uint64_t seed, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen) { + return dist_session_handoff_generate_trace(d, + owner, + n_predict, + temperature, + top_p, + min_p, + seed, + tokens_out, + token_cap, + NULL, + 0, + NULL, + shard_load_sec_out, + decode_sec_out, + err, + errlen); } int ds4_dist_session_handoff_argmax_trace( @@ -5984,18 +6063,22 @@ int ds4_dist_session_handoff_argmax_trace( double *decode_sec_out, char *err, size_t errlen) { - return dist_session_handoff_argmax_trace(d, - owner, - n_predict, - tokens_out, - token_cap, - logits_trace_out, - logits_trace_cap, - logits_trace_steps_out, - shard_load_sec_out, - decode_sec_out, - err, - errlen); + return dist_session_handoff_generate_trace(d, + owner, + n_predict, + 0.0f, + 1.0f, + 0.0f, + 0u, + tokens_out, + token_cap, + logits_trace_out, + logits_trace_cap, + logits_trace_steps_out, + shard_load_sec_out, + decode_sec_out, + err, + errlen); } /* ========================================================================= @@ -8129,6 +8212,10 @@ static int dist_worker_handle_local_generate( session_id = dist_u64_from_halves(req.session_hi, req.session_lo); const uint64_t token_hash = dist_u64_from_halves(req.token_hash_hi, req.token_hash_lo); + uint64_t rng = dist_u64_from_halves(req.seed_hi, req.seed_lo); + const float temperature = dist_f32_from_bits(req.temperature_bits); + const float top_p = dist_f32_from_bits(req.top_p_bits); + const float min_p = dist_f32_from_bits(req.min_p_bits); if (req.model_id != state->model_id || req.logits_bytes != logits_bytes) { dist_discard_bytes(upstream->fd, bytes - (uint32_t)sizeof(req)); snprintf(err, sizeof(err), "local generate request does not match worker state"); @@ -8180,7 +8267,12 @@ static int dist_worker_handle_local_generate( } else { const double t0 = dist_now_sec(); for (uint32_t i = 0; i < req.n_predict; i++) { - const int tok = ds4_session_argmax(session->session); + const int tok = ds4_session_sample(session->session, + temperature, + 0, + top_p, + min_p, + &rng); tokens[i] = tok; if (ds4_session_eval(session->session, tok, err, sizeof(err)) != 0) { session->token_hash_valid = false; diff --git a/ds4_distributed.h b/ds4_distributed.h index f37483591..8cf1ff012 100644 --- a/ds4_distributed.h +++ b/ds4_distributed.h @@ -97,6 +97,20 @@ int ds4_dist_session_handoff_argmax( double *decode_sec_out, char *err, size_t errlen); +int ds4_dist_session_handoff_generate( + ds4_dist_session *d, + ds4_session *owner, + int n_predict, + float temperature, + float top_p, + float min_p, + uint64_t seed, + int *tokens_out, + int token_cap, + double *shard_load_sec_out, + double *decode_sec_out, + char *err, + size_t errlen); int ds4_dist_session_handoff_argmax_trace( ds4_dist_session *d, ds4_session *owner, From a9d673be96cc8fb39f5e76f02896c7444ca54b45 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 17:45:00 +0100 Subject: [PATCH 13/17] fix: stale coordinator logits --- ds4_distributed.c | 36 +++++++++++---- tests/issue304_phase5_multiturn.c | 76 +++++++++++++++++++++++++++---- 2 files changed, 92 insertions(+), 20 deletions(-) diff --git a/ds4_distributed.c b/ds4_distributed.c index 662534e5f..1463a1f53 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -4764,6 +4764,7 @@ static int dist_local_generate_remote( int token_cap, float *logits_trace_out, int logits_trace_cap, + float *final_logits_out, int *logits_trace_steps_out, double *decode_sec_out, char *err, @@ -4903,13 +4904,33 @@ static int dist_local_generate_remote( if (res.logits_bytes != 0) { const int logits_trace_values = (int)((uint64_t)res.generated_count * (uint64_t)vocab); if (!logits_trace_out || logits_trace_cap < logits_trace_values) { - if (dist_discard_bytes(fd, res.logits_bytes) <= 0) { + uint32_t remaining_logits_bytes = res.logits_bytes; + if (final_logits_out && res.generated_count != 0) { + const uint32_t tail_bytes = logits_bytes; + const uint32_t prefix_bytes = res.logits_bytes - tail_bytes; + if (prefix_bytes != 0 && + dist_discard_bytes(fd, prefix_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to discard local generate logits"); + goto cleanup; + } + if (dist_read_full(fd, final_logits_out, tail_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to read final local generate logits"); + goto cleanup; + } + remaining_logits_bytes = 0; + } + if (remaining_logits_bytes != 0 && + dist_discard_bytes(fd, remaining_logits_bytes) <= 0) { if (errlen) snprintf(err, errlen, "failed to discard local generate logits"); goto cleanup; } } else if (dist_read_full(fd, logits_trace_out, res.logits_bytes) <= 0) { if (errlen) snprintf(err, errlen, "failed to read local generate logits"); goto cleanup; + } else if (final_logits_out && res.generated_count != 0) { + memcpy(final_logits_out, + logits_trace_out + (size_t)(res.generated_count - 1u) * (size_t)vocab, + (size_t)vocab * sizeof(final_logits_out[0])); } body -= res.logits_bytes; if (logits_trace_steps_out) *logits_trace_steps_out = (int)res.generated_count; @@ -5961,11 +5982,11 @@ static int dist_session_handoff_generate_trace( token_cap, logits_trace_out, logits_trace_cap, + logits, logits_trace_steps_out, decode_sec_out, err, errlen); - free(logits); if (rc > 0 && dist_coordinator_catch_up_generated_tokens(d, owner, @@ -5975,15 +5996,10 @@ static int dist_session_handoff_generate_trace( errlen) != 0) { return -1; } - if (rc > 0 && logits_trace_out) { - const int vocab = ds4_engine_vocab_size(d->state.engine); - const int trace_values = rc > INT_MAX / vocab ? 0 : rc * vocab; - if (trace_values != 0 && logits_trace_cap >= trace_values) { - (void)ds4_session_set_logits(owner, - logits_trace_out + (size_t)(rc - 1) * (size_t)vocab, - vocab); - } + if (rc > 0) { + (void)ds4_session_set_logits(owner, logits, vocab); } + free(logits); if (rc >= 0 && shard_load_sec_out) { *shard_load_sec_out = load_sec; } diff --git a/tests/issue304_phase5_multiturn.c b/tests/issue304_phase5_multiturn.c index 49786bbe6..f9613fe40 100644 --- a/tests/issue304_phase5_multiturn.c +++ b/tests/issue304_phase5_multiturn.c @@ -398,11 +398,13 @@ static void build_followup_prompt(ds4_engine *engine, const int *assistant_tokens, int assistant_count, const char *followup_prompt, + ds4_tokens *turn1_out, ds4_tokens *out) { - ds4_tokens_copy(out, base_prompt); + ds4_tokens_copy(turn1_out, base_prompt); for (int i = 0; i < assistant_count; i++) { - ds4_tokens_push(out, assistant_tokens[i]); + ds4_tokens_push(turn1_out, assistant_tokens[i]); } + ds4_tokens_copy(out, turn1_out); ds4_chat_append_message(engine, out, "user", followup_prompt); ds4_chat_append_assistant_prefix(engine, out, DS4_THINK_NONE); } @@ -514,12 +516,17 @@ int main(int argc, char **argv) { ds4_session *reused = NULL; ds4_session *fresh = NULL; ds4_tokens prompt1 = {0}; + ds4_tokens prompt1_turn1 = {0}; ds4_tokens prompt2 = {0}; handoff_run turn1 = {0}; handoff_run turn2_reused = {0}; handoff_run turn2_fresh = {0}; + float *reused_turn1_logits = NULL; + float *fresh_turn1_logits = NULL; float *reused_seed_logits = NULL; float *fresh_seed_logits = NULL; + int reused_turn1_argmax = -1; + int reused_argmax = -1; int rc = 1; if (ds4_engine_open(&engine, &opt) != 0 || !engine) { @@ -577,6 +584,7 @@ int main(int argc, char **argv) { turn1.tokens, turn1_visible, cfg.followup_prompt, + &prompt1_turn1, &prompt2); const int expected_after_turn1 = prompt1.len + turn1_visible; @@ -587,24 +595,32 @@ int main(int argc, char **argv) { expected_after_turn1); goto cleanup; } + const int vocab = ds4_engine_vocab_size(engine); + reused_turn1_logits = malloc((size_t)vocab * sizeof(reused_turn1_logits[0])); + fresh_turn1_logits = malloc((size_t)vocab * sizeof(fresh_turn1_logits[0])); + reused_seed_logits = malloc((size_t)vocab * sizeof(reused_seed_logits[0])); + fresh_seed_logits = malloc((size_t)vocab * sizeof(fresh_seed_logits[0])); + if (!reused_turn1_logits || !fresh_turn1_logits || + !reused_seed_logits || !fresh_seed_logits) { + fprintf(stderr, "issue304-phase5-multiturn: out of memory for logits snapshots\n"); + goto cleanup; + } + if (ds4_session_copy_logits(reused, reused_turn1_logits, vocab) != vocab) { + fprintf(stderr, "issue304-phase5-multiturn: failed to copy reused turn1 logits\n"); + goto cleanup; + } + reused_turn1_argmax = ds4_session_argmax(reused); if (ds4_session_sync(reused, &prompt2, err, sizeof(err)) != 0) { fprintf(stderr, "issue304-phase5-multiturn: reused-session followup sync failed: %s\n", err[0] ? err : "unknown error"); goto cleanup; } - const int vocab = ds4_engine_vocab_size(engine); - reused_seed_logits = malloc((size_t)vocab * sizeof(reused_seed_logits[0])); - fresh_seed_logits = malloc((size_t)vocab * sizeof(fresh_seed_logits[0])); - if (!reused_seed_logits || !fresh_seed_logits) { - fprintf(stderr, "issue304-phase5-multiturn: out of memory for seed logits\n"); - goto cleanup; - } if (ds4_session_copy_logits(reused, reused_seed_logits, vocab) != vocab) { fprintf(stderr, "issue304-phase5-multiturn: failed to copy reused seed logits\n"); goto cleanup; } - const int reused_argmax = ds4_session_argmax(reused); + reused_argmax = ds4_session_argmax(reused); if (!run_handoff(reused, cfg.gen_tokens, &turn2_reused)) { goto cleanup; @@ -635,6 +651,43 @@ int main(int argc, char **argv) { &output_on_coordinator)) { goto cleanup; } + if (ds4_session_sync(fresh, &prompt1_turn1, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase5-multiturn: fresh-session turn1 sync failed: %s\n", + err[0] ? err : "unknown error"); + goto cleanup; + } + if (ds4_session_pos(fresh) != prompt1_turn1.len) { + fprintf(stderr, "issue304-phase5-multiturn: fresh session did not reach turn1 transcript\n"); + goto cleanup; + } + if (ds4_session_copy_logits(fresh, fresh_turn1_logits, vocab) != vocab) { + fprintf(stderr, "issue304-phase5-multiturn: failed to copy fresh turn1 logits\n"); + goto cleanup; + } + const int fresh_turn1_argmax = ds4_session_argmax(fresh); + parity_metrics turn1_cmp = compare_logits(fresh_turn1_logits, reused_turn1_logits, vocab); + int fresh_turn1_top5[5]; + int reused_turn1_top5[5]; + logits_topk(fresh_turn1_logits, vocab, fresh_turn1_top5, 5); + logits_topk(reused_turn1_logits, vocab, reused_turn1_top5, 5); + printf("PHASE5_MULTITURN_TURN1_ARGMAX reused=%d fresh=%d reused_in_fresh_top5=%s fresh_in_reused_top5=%s\n", + reused_turn1_argmax, + fresh_turn1_argmax, + topk_contains(fresh_turn1_top5, 5, reused_turn1_argmax) ? "true" : "false", + topk_contains(reused_turn1_top5, 5, fresh_turn1_argmax) ? "true" : "false"); + printf("PHASE5_MULTITURN_TURN1_LOGITS top5=%d top10=%d top20=%d rms=%.8f max_abs=%.8f top20_max_abs=%.8f nonfinite=%d\n", + turn1_cmp.top5_overlap, + turn1_cmp.top10_overlap, + turn1_cmp.top20_overlap, + turn1_cmp.rms, + turn1_cmp.max_abs, + turn1_cmp.top20_max_abs, + turn1_cmp.nonfinite); + printf("PHASE5_MULTITURN_TURN1_TOP5 fresh="); + print_topk_json(engine, fresh_turn1_logits, vocab, 5); + printf(" reused="); + print_topk_json(engine, reused_turn1_logits, vocab, 5); + printf("\n"); if (ds4_session_sync(fresh, &prompt2, err, sizeof(err)) != 0) { fprintf(stderr, "issue304-phase5-multiturn: fresh-session followup sync failed: %s\n", err[0] ? err : "unknown error"); @@ -706,10 +759,13 @@ int main(int argc, char **argv) { cleanup: free(fresh_seed_logits); free(reused_seed_logits); + free(fresh_turn1_logits); + free(reused_turn1_logits); handoff_run_free(&turn2_fresh); handoff_run_free(&turn2_reused); handoff_run_free(&turn1); ds4_tokens_free(&prompt2); + ds4_tokens_free(&prompt1_turn1); ds4_tokens_free(&prompt1); ds4_session_free(fresh); ds4_session_free(reused); From 42f60218c03539fe4f79679ae3e6733184fb7485 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Fri, 5 Jun 2026 17:52:00 +0100 Subject: [PATCH 14/17] phase 5 frontend testing and fixes --- artifacts/issue-304/compatibility-matrix.md | 5 + artifacts/issue-304/decision-log.md | 73 +++++- artifacts/issue-304/perf-breakdown.md | 8 + artifacts/issue-304/phase5-plan.md | 24 +- artifacts/issue-304/research-notes.md | 49 ++++- artifacts/issue-304/runbook.md | 21 +- ds4_distributed.c | 232 ++++++++++++++++++++ tests/issue304_phase5_multiturn.c | 63 +++++- 8 files changed, 456 insertions(+), 19 deletions(-) diff --git a/artifacts/issue-304/compatibility-matrix.md b/artifacts/issue-304/compatibility-matrix.md index d1556a5d7..547bedae7 100644 --- a/artifacts/issue-304/compatibility-matrix.md +++ b/artifacts/issue-304/compatibility-matrix.md @@ -42,8 +42,13 @@ | Date | Commit | Model | Route | Validation path | Result | Notes | | --- | --- | --- | --- | --- | --- | --- | | 2026-06-05 | local working tree after `--local-decode` CLI and stream-handoff changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `Metal -> CUDA`, `0:21 -> 22:output` | plain `ds4` CLI, worker `--local-decode`, one-shot greedy coordinator `--temp 0 --debug`, full `README.md` | Pass | Route formed cleanly, worker advertised `local_decode=1`, distributed prefill reached `603.15 tok/s`, KV handoff moved `105,725,160` bytes in `0.345 s`, and worker local generation completed at `13.08 tok/s`. | +| 2026-06-05 | local working tree after sampled handoff changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `Metal -> CUDA`, `0:21 -> 22:output` | plain `ds4` CLI, worker `--local-decode`, one-shot sampled coordinator `--temp 0.7 --top-p 0.95 --min-p 0.05 --debug`, short prompt | Pass | Sampled worker-owned decode now works without a harness. Route formed, KV handoff logged, and the worker returned sampled output through the existing `LOCAL_GENERATE` response path. | +| 2026-06-05 | local working tree after normal-eval local-decode changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `Metal -> CUDA`, `0:21 -> 22:output` | plain `ds4` CLI, `--dump-logprobs`, normal token-by-token eval | Pass | The ordinary `ds4_session_eval()` loop now activates worker local decode after sync and continues through forced one-step worker evals. | | 2026-06-05 | local working tree after `--local-decode` CLI and stream-handoff changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `CUDA -> Metal`, `0:21 -> 22:output` | plain `ds4` CLI, fresh Metal worker `--local-decode`, DGX one-shot greedy coordinator `--temp 0 --debug`, full `README.md` | Pass | Fresh Metal worker run matched the authoritative validation rule. Distributed prefill reached `589.93 tok/s`, KV handoff moved `107,097,320` bytes in `0.350 s`, and worker local generation completed at `30.33 tok/s`. | +| 2026-06-05 | local working tree after normal-eval local-decode changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `CUDA -> Metal`, `0:21 -> 22:output` | plain `ds4` CLI on DGX, fresh Metal worker, `--dump-logprobs`, normal token-by-token eval | Pass | The symmetric ordinary eval path also activates worker local decode after sync and completes successfully on the Metal worker. | | 2026-06-05 | local working tree after `--local-decode` CLI and stream-handoff changes | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | pure local Metal baseline | plain `ds4` CLI, full `README.md` | Pass | Reference Mac-only baseline on the same prompt: prefill `413.44 tok/s`, generation `34.78 tok/s`. | +| 2026-06-05 | local working tree after sampled handoff and stale-logits fix | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `Metal -> CUDA`, reused-session multi-turn `0:21 -> 22:output` | `tests/issue304_phase5_multiturn`, DGX worker, compare reused caught-up session vs fresh full-transcript session | Investigating | Immediate post-turn1 boundary now matches closely (`top1 1116/1116`, `top5=5/5`, `top10=10/10`, `top20=20/20`, `rms=0.27032664`), but follow-up sync on the reused state still drifts before turn two (`8474` vs `267`, `top5=4/5`, `rms=0.99836105`). | +| 2026-06-05 | local working tree after normal-eval local-decode changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `CUDA -> Metal`, reused-session sampled normal-eval multi-turn `0:21 -> 22:output` | `tests/issue304_phase5_multiturn --normal-eval --temp 0.7 --top-p 0.95 --min-p 0.05 --seed 123`, DGX coordinator, fresh Metal worker | Mixed / Investigating | Follow-up-sync frontier still drifts (`top1 8474/8474`, `top5=4/5`, `top10=8/10`, `top20=15/20`, `rms=0.81043321`), but the tested second-turn sampled tokens still matched exactly, so this route is milder than the `Metal -> CUDA` sampled case. | ## Representative `DSVL` shard smoke diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index 4393fdec6..d16d65fa4 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -379,8 +379,79 @@ Why this changes the next steps: the handoff stayed near `0.35 s`, which is small relative to the `23-25 s` distributed prefill runs. - The next product-level gap is not transport but surface coverage: - the worker-owned path is currently wired into greedy one-shot coordinator + the worker-owned path was initially wired into greedy one-shot coordinator runs, not yet into the normal sampled distributed eval path. - That makes the most defensible next task explicit: extend the user-facing decode surfaces only after preserving the current simple worker protocol and measured handoff cost. + +## 2026-06-05: Sampled one-shot local-decode is enabled, and the remaining multi-turn variance starts after follow-up sync + +Decision: + +- Treat sampled one-shot coordinator handoff as implemented for Phase 5. +- Reclassify the main reusable-session issue from "catch-up is broken" to + "follow-up sync on reused handoff state still diverges from a fresh + full-transcript session". + +Evidence: + +- Plain CLI sampled one-shot on `Metal -> CUDA` now succeeds with: + - `--temp 0.7 --top-p 0.95 --min-p 0.05` + - route formation, + - KV handoff log emission, + - and sampled worker-owned output text. +- A coordinator bookkeeping bug was fixed: after worker-owned decode, the + coordinator now keeps the worker's final logits even when no full logits + trace buffer is requested. +- The DGX-backed multi-turn diagnostic now shows two distinct boundaries: + - immediately after turn-1 worker decode plus coordinator catch-up: + - reused top1 `1116`, fresh top1 `1116` + - `top5=5/5`, `top10=10/10`, `top20=20/20` + - `rms=0.27032664` + - after syncing the next user follow-up on top of that reused state: + - reused top1 `8474`, fresh top1 `267` + - `top5=4/5`, `top10=6/10`, `top20=16/20` + - `rms=0.99836105` + +Why this changes the next steps: + +- The broad "coordinator catch-up is wrong" diagnosis was too coarse. +- The remaining Phase 5 reusable-session problem is narrower and more + useful: something in the next distributed sync/reused-state path is + shifting the frontier before the second handoff. +- That means further investigation should focus on reused-session sync over + an already-caught-up state rather than on the basic worker-owned + generation or token replay mechanics. + +## 2026-06-05: Normal sampled eval/server delegation is now enabled through local decode + +Decision: + +- Treat the normal distributed `ds4_session_eval(token)` surface as in + Phase 5 scope and now implemented through worker-owned local decode. +- Keep the remaining Phase 5 blocker focused on reusable-session variance. + +Evidence: + +- After sync, the coordinator now lazily activates local decode by pushing + its KV shard and seeding the worker with the current logits. +- Subsequent `ds4_session_eval(token)` calls use the existing + `LOCAL_GENERATE` RPC with a forced-token one-step request, then catch up + the coordinator's local slice and install the returned next logits. +- Validation passed on: + - `Metal -> CUDA` CLI `--dump-logprobs` + - `CUDA -> Metal` CLI `--dump-logprobs` + - `Metal -> CUDA` `ds4_server` + - `CUDA -> Metal` `ds4_server` +- The symmetric sampled multi-turn result on `CUDA -> Metal` still shows + follow-up-sync frontier drift, but it is milder than the `Metal -> CUDA` + case because the second-turn sampled tokens still matched exactly for the + tested seed. + +Why this changes the next steps: + +- Phase 5 no longer has a major surface-coverage gap between one-shot and + ordinary sampled decode. +- The remaining work is now primarily about reusable-session parity under + follow-up sync, not about missing API wiring. diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md index a1f182da9..f69820fb7 100644 --- a/artifacts/issue-304/perf-breakdown.md +++ b/artifacts/issue-304/perf-breakdown.md @@ -12,6 +12,7 @@ user-visible path. | Route | Prompt | Prompt tokens | KV bytes | KV handoff sec | KV MiB/s | Prefill tok/s | Worker/local generation tok/s | Notes | | --- | --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | | `Metal -> CUDA` | `ping` | 10 | 6,564,072 | 0.025 | 248.27 | 14.27 | 14.88 | tiny prompt sanity check | +| `Metal -> CUDA` | sampled short prompt | 17 | 6,930,664 | 0.028 | 238.89 | 32.76 | 12.06 | one-shot sampled coordinator `--temp 0.7 --top-p 0.95 --min-p 0.05`; output: `A distributed system is a collection of independent` | | `Metal -> CUDA` | README 4 KiB slice | 958 | 18,091,240 | 0.055 | 313.91 | 314.80 | 14.13 | mid-sized prompt | | `Metal -> CUDA` | full `README.md` | 14,318 | 105,725,160 | 0.345 | 292.47 | 603.15 | 13.08 | reused CUDA worker | | `CUDA -> Metal` | `ping` | 10 | 6,564,072 | 0.019 | 335.60 | 10.87 | 38.69 | fresh Metal worker | @@ -29,6 +30,13 @@ Interpretation: `30.33 tok/s` against a pure local Mac baseline of `34.78 tok/s`, which is close enough that the main performance question is no longer decode throughput. +- Sampled one-shot handoff uses the same KV transfer and worker-owned + decode path as greedy one-shot runs; no separate protocol was needed to + get sampling through the Phase 5 CLI surface. +- Normal token-by-token eval now uses the same worker-owned local-decode + transport after a one-time activation push. CLI `--dump-logprobs` and + `ds4_server` both exercised that surface successfully in both route + directions on 2026-06-05. - For very short generations the one-time handoff can still matter to first-token latency, but the current data does not justify KV pipelining for throughput-oriented Phase 5 benchmarking. diff --git a/artifacts/issue-304/phase5-plan.md b/artifacts/issue-304/phase5-plan.md index cadb68ac3..6c3a8d680 100644 --- a/artifacts/issue-304/phase5-plan.md +++ b/artifacts/issue-304/phase5-plan.md @@ -8,7 +8,7 @@ a real frontend can call. ## 2026-06-05 implementation status -Phase 5 is now partially implemented in the main CLI/runtime path. +Phase 5 is now substantially implemented in the main CLI/runtime path. Implemented: @@ -21,8 +21,15 @@ Implemented: temp-file detour was removed from this handoff path. - Reusable coordinator sessions catch up their local slice from the generated token ids returned by worker local generation. -- One-shot greedy CLI coordinator runs (`--temp 0`) now attempt the - worker-owned handoff path directly. +- One-shot CLI coordinator runs now attempt the worker-owned handoff path + directly for both greedy and sampled generation. +- The coordinator now preserves the worker's final logits after handoff + even when the caller does not request a full logits trace. +- The normal distributed `ds4_session_eval(token)` path now lazily + activates worker local decode after sync and delegates subsequent token + eval through forced one-step worker `LOCAL_GENERATE` calls. +- `ds4_server` inherits that path automatically because it already samples + on the coordinator and advances through `ds4_session_eval()`. Measured on 2026-06-05 with the plain `ds4` CLI: @@ -40,10 +47,13 @@ Measured on 2026-06-05 with the plain `ds4` CLI: Current limitation: -- The worker-owned handoff is wired into the one-shot greedy coordinator - path. The normal sampled distributed `ds4_session_eval(token)` path is - still the old per-token distributed decode surface, so full sampled - coordinator/server delegation remains follow-on work. +- Reusable-session catch-up no longer looks broadly broken, but the next + follow-up sync on top of a caught-up reused state can still drift from a + fresh full-transcript session before turn two begins. +- The severity of that remaining reusable-session drift differs by route: + on the tested sampled normal-eval seed, `Metal -> CUDA` still diverged in + second-turn tokens while `CUDA -> Metal` preserved the same second-turn + token sequence despite frontier drift. ## Source documents diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index 9c23b6094..f3be18053 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -411,10 +411,51 @@ The remaining work should separate: decode throughput alone. 4. The remaining surface gap is protocol usage, not handoff mechanics. - - The current worker-owned path is wired into the greedy one-shot - coordinator flow. - - The normal sampled distributed eval/decode path is still the older - token-by-token coordinator-owned surface. + - The worker-owned path now supports sampled one-shot coordinator runs + through the existing `LOCAL_GENERATE` response path. + - The normal token-by-token distributed eval/decode path now also + delegates through worker-owned local decode by lazily activating the + worker on first `ds4_session_eval()` after sync and then using + forced-token one-step `LOCAL_GENERATE` calls for subsequent tokens. + - This was validated on the plain CLI `--dump-logprobs` path and on + `ds4_server` in both `Metal -> CUDA` and `CUDA -> Metal`. + +5. The first reusable-session variance diagnosis was partly a stale-logits + bookkeeping bug on the coordinator. + - After worker-owned decode, the coordinator transcript/KV advanced but + the coordinator often kept pre-handoff logits unless a full logits + trace was requested. + - Fixing that bug made the immediate post-catch-up frontier much closer + to a fresh full-transcript session. + +6. The remaining reusable-session drift now appears after follow-up sync, + not immediately after catch-up. + - On the DGX/Mac `0:21 -> 22:output` route, the post-turn1 reused-vs-fresh + frontier now matches on top1 (`1116` vs `1116`) with `top5=5/5`, + `top10=10/10`, `top20=20/20`, and `rms=0.27032664`. + - After syncing the next user follow-up on top of that reused state, the + frontier diverges again with a near-top1 flip: + - reused top1 `8474` (`"They"`) + - fresh top1 `267` (`"en"`) + - `top5=4/5`, `top10=6/10`, `top20=16/20` + - `rms=0.99836105` + - That means the remaining Phase 5 reusable-session variance is no + longer best described as "catch-up is broken". It is more narrowly a + reused-state follow-up sync variance that appears after the next + distributed prefill step. + +7. The symmetric `CUDA -> Metal` sampled normal-eval route is milder than + the `Metal -> CUDA` case. + - `Metal -> CUDA`, sampled normal-eval multi-turn: + - reused top1 `8474`, fresh top1 `267` + - `top5=4/5`, `top10=8/10`, `top20=18/20` + - turn-two tokens diverged + - `CUDA -> Metal`, sampled normal-eval multi-turn with the same seed: + - reused top1 `8474`, fresh top1 `8474` + - `top5=4/5`, `top10=8/10`, `top20=15/20` + - turn-two tokens still matched exactly + - So the remaining reused-session follow-up-sync variance is present in + both directions, but it is not equally severe on the sampled path. ### Implication diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md index d2d202f2b..a4884eaff 100644 --- a/artifacts/issue-304/runbook.md +++ b/artifacts/issue-304/runbook.md @@ -36,6 +36,12 @@ ssh dgx-direct 'pkill -9 ds4 >/dev/null 2>&1 || true; sh -c "cd ~/ds4; nohup ./d ./ds4 -m ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --temp 0 --nothink --role coordinator --layers 0:21 --listen 10.77.0.1 1234 --prompt-file README.md -n 8 --debug ``` +`Metal -> CUDA` sampled one-shot coordinator smoke on the Mac: + +```sh +./ds4 -m ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --temp 0.7 --top-p 0.95 --min-p 0.05 --nothink --role coordinator --layers 0:21 --listen 10.77.0.1 1234 -p 'Describe a distributed system in one sentence.' -n 8 --debug +``` + `CUDA -> Metal` fresh worker startup on the Mac: ```sh @@ -68,10 +74,17 @@ Reference local Mac baseline: Current limitation: -- the worker-owned handoff is wired into the greedy one-shot coordinator - path. Normal sampled distributed decode/server reuse still needs follow-on - work, even though reusable coordinators now have catch-up logic in the - session layer. +- sampled one-shot CLI coordinator runs now work through the worker-owned + handoff path as well as greedy ones. +- normal token-by-token distributed eval now also delegates through + worker-owned local decode after the first post-sync activation on both + CLI and `ds4_server`. +- reusable-session follow-up after catch-up is still under investigation: + the immediate post-handoff frontier is now close to fresh-session parity, + but a follow-up distributed sync on top of that reused state can still + produce a near-top1 logit flip and divergent turn-two tokens. +- the remaining open issue is reusable-session variance, not lack of + normal eval/server delegation. ## Phase 4 closeout rules diff --git a/ds4_distributed.c b/ds4_distributed.c index 1463a1f53..c91a83e0d 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -595,6 +595,10 @@ static int dist_coordinator_catch_up_generated_tokens( uint32_t token_count, char *err, size_t errlen); +static int dist_kv_route_validate( + const ds4_dist_session *d, + char *err, + size_t errlen); static int dist_validate_options(const ds4_dist_options *opt, char *err, size_t errlen); static uint32_t dist_resolved_layer_end(const ds4_dist_options *opt, uint32_t n_layers) { @@ -4947,6 +4951,187 @@ static int dist_local_generate_remote( return rc; } +static const ds4_dist_route_entry *dist_session_final_local_decode_entry( + const ds4_dist_session *d) { + if (!d || d->plan.count != 1u) return NULL; + const ds4_dist_route_entry *entry = &d->plan.entry[d->plan.count - 1u]; + if ((entry->flags & DS4_DIST_ROUTE_F_OUTPUT_LOGITS) == 0u) return NULL; + if ((entry->flags & DS4_DIST_ROUTE_F_LOCAL_DECODE) == 0u) return NULL; + return entry; +} + +static int dist_session_activate_local_decode( + ds4_dist_session *d, + ds4_session *owner, + char *err, + size_t errlen) { + if (!d || !owner) { + if (errlen) snprintf(err, errlen, "invalid local-decode activation request"); + return -1; + } + if (d->local_decode_active) return 0; + if (dist_session_ensure_route(d, err, errlen) != 0) return -1; + if (dist_kv_route_validate(d, err, errlen) != 0) return -1; + + const ds4_dist_route_entry *entry = dist_session_final_local_decode_entry(d); + if (!entry) { + if (errlen) snprintf(err, errlen, "distributed route does not support worker local decode"); + return -1; + } + + const ds4_tokens *timeline = ds4_session_tokens(owner); + if (!timeline || timeline->len < 0 || (uint64_t)timeline->len > UINT32_MAX) { + if (errlen) snprintf(err, errlen, "distributed local decode requires a valid token timeline"); + return -1; + } + const uint64_t token_hash = dist_token_hash_prefix(timeline->v, (uint32_t)timeline->len); + const uint64_t payload_bytes = ds4_session_layer_payload_bytes(owner, + d->state.local_start, + d->state.local_end); + const double load_t0 = dist_now_sec(); + if (dist_load_remote_shard_from_session(d, + entry, + owner, + timeline->v, + (uint32_t)timeline->len, + token_hash, + d->state.local_start, + d->state.local_end, + err, + errlen) != 0) { + return -1; + } + const double load_t1 = dist_now_sec(); + DIST_COORD_DEBUG(&d->state, + "ds4: distributed coordinator: local-decode begin tokens=%u layers=%u:%u bytes=%" PRIu64 " total=%.3fs %.2f MiB/s worker=%s:%u\n", + (uint32_t)timeline->len, + d->state.local_start, + d->state.local_end, + payload_bytes, + load_t1 - load_t0, + (load_t1 > load_t0) + ? (((double)payload_bytes / (1024.0 * 1024.0)) / (load_t1 - load_t0)) + : 0.0, + entry->host, + entry->port); + + const int vocab = ds4_engine_vocab_size(d->state.engine); + float *logits = malloc((size_t)vocab * sizeof(logits[0])); + if (!logits) { + if (errlen) snprintf(err, errlen, "out of memory copying activation logits"); + return -1; + } + if (ds4_session_copy_logits(owner, logits, vocab) != vocab) { + free(logits); + if (errlen) snprintf(err, errlen, "failed to copy activation logits"); + return -1; + } + int dummy_steps = 0; + double dummy_decode_sec = 0.0; + const int rc = dist_local_generate_remote(d, + entry, + token_hash, + logits, + 0, + 0.0f, + 1.0f, + 0.0f, + 0u, + NULL, + 0, + NULL, + 0, + NULL, + &dummy_steps, + &dummy_decode_sec, + err, + errlen); + free(logits); + if (rc < 0) return -1; + d->local_decode_active = true; + return 0; +} + +static int dist_session_eval_local_decode( + ds4_dist_session *d, + ds4_session *owner, + const ds4_tokens *checkpoint, + int token, + float *logits, + char *err, + size_t errlen) { + if (!d || !owner || !checkpoint || !logits) { + if (errlen) snprintf(err, errlen, "invalid local-decode eval request"); + return 1; + } + const ds4_dist_route_entry *entry = dist_session_final_local_decode_entry(d); + if (!entry || !d->local_decode_active) { + if (errlen) snprintf(err, errlen, "local-decode eval is not active"); + return 1; + } + + const int vocab = ds4_engine_vocab_size(d->state.engine); + if (token < 0 || token >= vocab) { + if (errlen) snprintf(err, errlen, "forced token is outside the model vocabulary"); + return 1; + } + float *forced_logits = malloc((size_t)vocab * sizeof(forced_logits[0])); + if (!forced_logits) { + if (errlen) snprintf(err, errlen, "out of memory allocating forced logits"); + return 1; + } + for (int i = 0; i < vocab; i++) forced_logits[i] = -1.0e30f; + forced_logits[token] = 0.0f; + + int echoed_token = -1; + int trace_steps = 0; + double decode_sec_unused = 0.0; + const uint64_t token_hash = dist_token_hash_prefix(checkpoint->v, (uint32_t)checkpoint->len); + const int rc = dist_local_generate_remote(d, + entry, + token_hash, + forced_logits, + 1, + 0.0f, + 1.0f, + 0.0f, + 0u, + &echoed_token, + 1, + NULL, + 0, + logits, + &trace_steps, + &decode_sec_unused, + err, + errlen); + free(forced_logits); + if (rc < 0) { + d->local_decode_active = false; + return 1; + } + if (rc != 1 || echoed_token != token || trace_steps != 1) { + d->local_decode_active = false; + if (errlen) snprintf(err, errlen, "worker local decode returned an unexpected eval result"); + return 1; + } + if (dist_coordinator_catch_up_generated_tokens(d, + owner, + &token, + 1u, + err, + errlen) != 0) { + d->local_decode_active = false; + return 1; + } + if (ds4_session_set_logits(owner, logits, vocab) != 0) { + d->local_decode_active = false; + if (errlen) snprintf(err, errlen, "failed to update coordinator logits after local decode eval"); + return 1; + } + return 0; +} + static int dist_receive_snapshot_chunks_to_file( int fd, uint64_t request_id, @@ -5999,6 +6184,7 @@ static int dist_session_handoff_generate_trace( if (rc > 0) { (void)ds4_session_set_logits(owner, logits, vocab); } + if (rc >= 0) d->local_decode_active = true; free(logits); if (rc >= 0 && shard_load_sec_out) { *shard_load_sec_out = load_sec; @@ -6262,6 +6448,7 @@ int ds4_dist_session_sync( if (errlen) snprintf(err, errlen, "invalid distributed sync request"); return 1; } + d->local_decode_active = false; if (dist_session_ensure_route(d, err, errlen) != 0) return 1; if (checkpoint && @@ -6397,6 +6584,51 @@ int ds4_dist_session_eval( } if (dist_session_ensure_route(d, err, errlen) != 0) return 1; + if (!d->local_decode_active && + dist_session_final_local_decode_entry(d) != NULL) { + char activate_err[256] = {0}; + if (dist_session_activate_local_decode(d, owner, activate_err, sizeof(activate_err)) != 0) { + DIST_COORD_DEBUG(&d->state, + "ds4: distributed coordinator: local-decode activation skipped: %s\n", + activate_err[0] ? activate_err : "unknown error"); + d->local_decode_active = false; + } + } + if (d->local_decode_active) { + ds4_tokens transcript = {0}; + ds4_tokens_copy(&transcript, checkpoint); + ds4_tokens_push(&transcript, token); + int eval_rc = dist_session_eval_local_decode(d, + owner, + checkpoint, + token, + logits, + err, + errlen); + if (eval_rc != 0) { + if (dist_coordinator_rebuild_from_transcript(&d->state, + owner, + &d->plan, + &transcript, + d->session_id, + &d->request_id, + logits, + &d->plan_generation, + true, + err, + errlen) != 0) { + d->plan_ready = false; + d->plan_generation = 0; + ds4_tokens_free(&transcript); + return 1; + } + d->plan_ready = true; + d->local_decode_active = false; + } + ds4_tokens_free(&transcript); + return 0; + } + ds4_tokens transcript = {0}; ds4_tokens_copy(&transcript, checkpoint); ds4_tokens_push(&transcript, token); diff --git a/tests/issue304_phase5_multiturn.c b/tests/issue304_phase5_multiturn.c index f9613fe40..b7180eeb7 100644 --- a/tests/issue304_phase5_multiturn.c +++ b/tests/issue304_phase5_multiturn.c @@ -26,6 +26,11 @@ typedef struct { uint32_t prefill_chunk; uint32_t prefill_window; uint32_t activation_bits; + float temperature; + float top_p; + float min_p; + uint64_t seed; + bool normal_eval; bool debug; } phase5_cfg; @@ -59,6 +64,7 @@ static void die_usage(const char *argv0) { "usage: %s --model FILE --listen-host IPV4 --listen-port N " "[--prompt-file FILE] [--system TEXT] [--followup TEXT] [--ctx N] " "[--gen-tokens N] [--prefill-chunk N] [--prefill-window N] " + "[--temp F] [--top-p F] [--min-p F] [--seed N] [--normal-eval] " "[--activation-bits N] [--coordinator-layers A:B|A:output] " "[--worker-layers A:B|A:output] [--lock-file FILE] [--no-debug]\n", argv0); @@ -213,6 +219,37 @@ static bool run_handoff(ds4_session *session, int max_tokens, handoff_run *out) return true; } +static bool run_normal_eval(ds4_engine *engine, + ds4_session *session, + const phase5_cfg *cfg, + handoff_run *out) { + char err[256] = {0}; + memset(out, 0, sizeof(*out)); + out->tokens = calloc((size_t)cfg->gen_tokens, sizeof(out->tokens[0])); + if (!out->tokens) { + fprintf(stderr, "issue304-phase5-multiturn: out of memory allocating eval tokens\n"); + return false; + } + uint64_t rng = cfg->seed; + for (int i = 0; i < cfg->gen_tokens; i++) { + int tok = ds4_session_sample(session, + cfg->temperature, + 0, + cfg->top_p, + cfg->min_p, + &rng); + out->tokens[i] = tok; + out->token_count = i + 1; + if (tok == ds4_token_eos(engine)) break; + if (ds4_session_eval(session, tok, err, sizeof(err)) != 0) { + fprintf(stderr, "issue304-phase5-multiturn: normal eval failed: %s\n", + err[0] ? err : "unknown error"); + return false; + } + } + return true; +} + static bool tokens_equal(const int *a, int na, const int *b, int nb) { if (na != nb) return false; for (int i = 0; i < na; i++) { @@ -433,6 +470,16 @@ static void parse_args(phase5_cfg *cfg, int argc, char **argv) { cfg->prefill_window = (uint32_t)strtoul(argv[++i], NULL, 10); } else if (!strcmp(argv[i], "--activation-bits") && i + 1 < argc) { cfg->activation_bits = (uint32_t)strtoul(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--temp") && i + 1 < argc) { + cfg->temperature = strtof(argv[++i], NULL); + } else if (!strcmp(argv[i], "--top-p") && i + 1 < argc) { + cfg->top_p = strtof(argv[++i], NULL); + } else if (!strcmp(argv[i], "--min-p") && i + 1 < argc) { + cfg->min_p = strtof(argv[++i], NULL); + } else if (!strcmp(argv[i], "--seed") && i + 1 < argc) { + cfg->seed = (uint64_t)strtoull(argv[++i], NULL, 10); + } else if (!strcmp(argv[i], "--normal-eval")) { + cfg->normal_eval = true; } else if (!strcmp(argv[i], "--coordinator-layers") && i + 1 < argc) { cfg->coordinator_layers = argv[++i]; } else if (!strcmp(argv[i], "--worker-layers") && i + 1 < argc) { @@ -460,6 +507,10 @@ int main(int argc, char **argv) { .prefill_chunk = 0, .prefill_window = 0, .activation_bits = 0, + .temperature = 0.0f, + .top_p = 1.0f, + .min_p = 0.0f, + .seed = 1u, .debug = true, .coordinator_layers = "0:21", .worker_layers = "22:output", @@ -566,7 +617,9 @@ int main(int argc, char **argv) { goto cleanup; } - if (!run_handoff(reused, cfg.gen_tokens, &turn1)) goto cleanup; + if (!(cfg.normal_eval + ? run_normal_eval(engine, reused, &cfg, &turn1) + : run_handoff(reused, cfg.gen_tokens, &turn1))) goto cleanup; const int turn1_visible = visible_token_count(engine, turn1.tokens, turn1.token_count); if (turn1_visible <= 0) { fprintf(stderr, "issue304-phase5-multiturn: first handoff returned no reusable tokens\n"); @@ -622,7 +675,9 @@ int main(int argc, char **argv) { } reused_argmax = ds4_session_argmax(reused); - if (!run_handoff(reused, cfg.gen_tokens, &turn2_reused)) { + if (!(cfg.normal_eval + ? run_normal_eval(engine, reused, &cfg, &turn2_reused) + : run_handoff(reused, cfg.gen_tokens, &turn2_reused))) { goto cleanup; } printf("PHASE5_MULTITURN_SYNC reused_pos=%d prompt2_tokens=%d\n", @@ -725,7 +780,9 @@ int main(int argc, char **argv) { printf(" reused="); print_topk_json(engine, reused_seed_logits, vocab, 5); printf("\n"); - if (!run_handoff(fresh, cfg.gen_tokens, &turn2_fresh)) { + if (!(cfg.normal_eval + ? run_normal_eval(engine, fresh, &cfg, &turn2_fresh) + : run_handoff(fresh, cfg.gen_tokens, &turn2_fresh))) { goto cleanup; } From 97d0688ec1de87a9e3494121f1924177ddd221f6 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Sat, 6 Jun 2026 16:46:26 +0100 Subject: [PATCH 15/17] phase 5 performance eval [WIP] --- artifacts/issue-304/decision-log.md | 43 + artifacts/issue-304/ds4-eval-matrix.md | 42 + .../ds4-eval/2026-06-06-ds4-eval-cuda.log | 103 ++ .../ds4-eval/2026-06-06-ds4-eval-metal.log | 106 ++ artifacts/issue-304/ds4-eval/raw/.gitignore | 2 + artifacts/issue-304/perf-breakdown.md | 25 + artifacts/issue-304/research-notes.md | 51 +- ds4.c | 19 + ds4.h | 14 + ds4_distributed.c | 58 +- ds4_distributed.h | 7 + ds4_eval.c | 354 +++++- ds4_help.c | 4 +- speed-bench/promessi_sposi_1k.txt | 1000 +++++++++++++++++ tests/issue304_phase5_eval_matrix.py | 652 +++++++++++ 15 files changed, 2453 insertions(+), 27 deletions(-) create mode 100644 artifacts/issue-304/ds4-eval-matrix.md create mode 100644 artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda.log create mode 100644 artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-metal.log create mode 100644 artifacts/issue-304/ds4-eval/raw/.gitignore create mode 100644 speed-bench/promessi_sposi_1k.txt create mode 100755 tests/issue304_phase5_eval_matrix.py diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index d16d65fa4..6d2ff67cb 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -455,3 +455,46 @@ Why this changes the next steps: ordinary sampled decode. - The remaining work is now primarily about reusable-session parity under follow-up sync, not about missing API wiring. + +## 2026-06-06: `ds4-eval` must use distributed handoff for `--nothink` local-decode matrices + +Decision: + +- Treat `ds4-eval` local-decode coordinator runs as invalid unless they use + the same worker-owned handoff workflow already exercised by the plain + `ds4` CLI. +- Restrict the first evaluator change to `--nothink` cases, where the + evaluator does not need token-by-token think-budget control. + +Evidence: + +- The first Phase 5 `ds4-eval` matrix runs used the ordinary + `ds4_session_sample()` + `ds4_session_eval()` loop even when the route + advertised worker local decode. +- That loop only exercised the already-existing lazy activation plus + one-token forced `LOCAL_GENERATE` eval path, not the worker-owned + one-shot handoff path used by: + - plain `ds4 --role coordinator ... --local-decode` benchmarks, + - the runbook validation commands, + - and the previously recorded `30.10` to `30.33 tok/s` + `CUDA -> Metal` local-decode results. +- After patching `ds4-eval` to use the distributed handoff API for eligible + `--nothink` routes and rebuilding on DGX, a fresh `Q1` + `CUDA -> Metal --local-decode` smoke passed through the intended path with: + - `local_decode_expected: yes` + - summary `local_decode_active_any_case: yes` + - `generated_tokens: 539` + - `decode_sec: 54.426` + - `generated_tps: 9.903` + +Why this changes the next steps: + +- The evaluator-path bug is fixed: `ds4-eval` is no longer measuring the + wrong local-decode workflow for eligible `--nothink` coordinator cases. +- The remaining throughput gap versus plain CLI (`~9.9 tok/s` in the smoke + versus `~30 tok/s` in the CLI benchmark) therefore moves to the protocol + level, not the evaluator loop. +- The next performance fix should target the worker local-generate RPC + payload shape, especially the current always-on per-token logits-trace + allocation/copy/return path, before drawing backend-level conclusions + from evaluator throughput. diff --git a/artifacts/issue-304/ds4-eval-matrix.md b/artifacts/issue-304/ds4-eval-matrix.md new file mode 100644 index 000000000..b9dfc6982 --- /dev/null +++ b/artifacts/issue-304/ds4-eval-matrix.md @@ -0,0 +1,42 @@ +# Phase 5 `ds4-eval` Matrix + +- Date: `2026-06-06` +- Questions: `4` +- Local model: `./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` +- Remote model: `/home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` +- Remote host: `dgx-direct` + +| Cell | Score | Runtime (s) | Prompt toks | Gen toks | Prefill (s) | Decode (s) | Backend | Route | Hops | Output | Local decode | Trace | +| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- | ---: | --- | --- | --- | +| `local-metal-nothink` | 4/4 | 28.492 | 744 | 901 | 4.872 | 23.620 | `metal` | `local` | 0 | `local` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-local-metal-nothink.trace) | +| `local-cuda-nothink` | 4/4 | 62.275 | 744 | 848 | 3.664 | 58.612 | `cuda` | `local` | 0 | `local` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-local-cuda-nothink.trace) | +| `metal-to-cuda-localdecode-nothink` | 4/4 | 86.553 | 744 | 859 | 5.439 | 81.113 | `metal` | `local 0:21 -> 10.77.0.2:41039 Q2 22:output` | 1 | `worker` | `expected=yes, active=yes` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-metal-to-cuda-localdecode-nothink.trace) | +| `cuda-to-metal-localdecode-nothink` | 3/4 fail=1 | 162.930 | 744 | 828 | 9.680 | 153.250 | `cuda` | `local 0:21 -> 192.168.1.218:49540 Q2 22:output` | 1 | `worker` | `expected=yes, active=yes` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-cuda-to-metal-localdecode-nothink.trace) | +| `metal-to-cuda-full-nothink` | 4/4 | 49.667 | 744 | 812 | 5.434 | 44.235 | `metal` | `local 0:21 -> 10.77.0.2:34989 Q2 22:output` | 1 | `worker` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-metal-to-cuda-full-nothink.trace) | +| `cuda-to-metal-full-nothink` | 4/4 | 85.975 | 744 | 817 | 8.690 | 77.287 | `cuda` | `local 0:21 -> 192.168.1.218:49923 Q2 22:output` | 1 | `worker` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-cuda-to-metal-full-nothink.trace) | + +## Status + +- Latest completed `6 x 4` `--nothink` smoke: `5/6` cells passed. +- Passing cells: local Metal, local CUDA, `Metal -> CUDA` local-decode, `Metal -> CUDA` full-distributed, `CUDA -> Metal` full-distributed. +- Remaining failing cell: `CUDA -> Metal` local-decode, failing `SuperGPQA/001b51d76b4d422988f2c11f104a2c6c` with picked `G` vs expected `C`. + +## Notes + +- `local_decode_expected: yes` with header `local_decode_active: no` is not treated as a routing failure here. The stronger summary field is `local_decode_active_any_case`, and for both `*-localdecode-*` cells it is `yes`, which shows local decode did engage during generation. +- The runner now includes the extra Phase 5 fully distributed cells: + - `metal-to-cuda-full-nothink` + - `cuda-to-metal-full-nothink` +- The runner was hardened during troubleshooting to: + - use stable SSH options for `dgx-direct` (`IPQoS=none`, no control master/path) + - restart workers per case in fresh-per-case mode + - wait for worker readiness before starting each case + - bypass the DGX startup memory guard for remote worker restarts + - clear stale per-case trace files before merge + - wait for remote worker shutdown before restart + +## Interpretation + +- Full-distributed mode is currently healthy in both directions on this `4`-question `--nothink` smoke. +- `Metal -> CUDA` local-decode also passes after the runner cleanup. +- The remaining issue is isolated to `CUDA -> Metal` local-decode under the smoke harness, not to full-distributed routing in general. diff --git a/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda.log b/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda.log new file mode 100644 index 000000000..246cbaff1 --- /dev/null +++ b/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda.log @@ -0,0 +1,103 @@ +$ ./ds4-eval -m /home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --nothink --tokens 4096 +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: CUDA host registration skipped: operation not supported +ds4: CUDA preparing model tensor mappings: 80.24 GiB +ds4: CUDA startup model preparation covered 80.76 GiB of tensor spans in 10.337s +ds4: cuda backend initialized for graph diagnostics +ds4-eval: context auto-sized to 4873 tokens (largest prompt=777 tokens, case=70, generation budget=4096) +ds4-eval: model shape DeepSeek V4 Flash +ds4-eval: context buffers 469.74 MiB (ctx=4873, backend=cuda, prefill_chunk=4096, raw_kv_rows=4352, compressed_kv_rows=1220) +ds4-eval: 69/92 passed, 23 failed, runtime 01h:39m +# state prompt gen total given correct test + 1 PASSED 201 336 537 B B GPQA Diamond/recNu3MXkvWUzHZr9 + 2 FAILED 149 79 228 G C SuperGPQA/001b51d76b4d422988f2c11f104a2c6c + 3 PASSED 81 252 333 70 70 AIME2025/aime2025-01 + 4 PASSED 313 170 483 C C GPQA Diamond/recoiTJPGUmzAkief + 5 PASSED 272 115 387 J J SuperGPQA/b7e20eac98764fb0bf30e8366d951daa + 6 PASSED 146 1062 1208 468 468 AIME2025/aime2025-16 + 7 PASSED 156 497 653 B B GPQA Diamond/rec4UqStf9WUVif1f + 8 PASSED 127 64 191 E E SuperGPQA/4a1d1780a93f4093b6fb7d3c314cbea8 + 9 PASSED 633 2331 2964 588 588 AIME2025/aime2025-02 + 10 PASSED 182 486 668 B B GPQA Diamond/recgI6tUQ7RLJRWGx + 11 PASSED 137 55 192 A A SuperGPQA/6082513c8dba4ec68aa68f1bf5854d09 + 12 PASSED 165 496 661 16 16 AIME2025/aime2025-03 + 13 PASSED 149 576 725 A A GPQA Diamond (modified)/recDytVnNYZe2HuUU + 14 PASSED 167 49 216 J J SuperGPQA/bebf1ed45ae14ad7b4f205f3909cb58a + 15 FAILED 305 4010 4315 78 82 AIME2025/aime2025-18 + 16 PASSED 131 400 531 D D GPQA Diamond/recNFJjE5PPTqVJGv + 17 PASSED 175 46 221 I I SuperGPQA/7ca71b86327744b78e93185a45bc5cef + 18 PASSED 102 696 798 117 117 AIME2025/aime2025-04 + 19 PASSED 187 371 558 B B GPQA Diamond/rec2UlKqC6RFHdcro + 20 PASSED 173 242 415 E E SuperGPQA/d44b94f7749345a39a65f6312bda8764 + 21 PASSED 229 840 1069 106 106 AIME2025/aime2025-19 + 22 PASSED 250 214 464 B B GPQA Diamond/recv7GsQg3f0fvB1f + 23 PASSED 232 63 295 B B SuperGPQA/febe406f44d74a40b50bb5b7c69d5dc1 + 24 PASSED 126 1460 1586 279 279 AIME2025/aime2025-05 + 25 FAILED 229 1299 1528 B C GPQA Diamond/recrHBEJJoDTV05JR + 26 PASSED 160 388 548 C C SuperGPQA/31950dc80ded400a9181f50626d1f75c + 27 PASSED 124 523 647 504 504 AIME2025/aime2025-06 + 28 FAILED 198 261 459 B D GPQA Diamond/recb80OwMgNnceA9t + 29 PASSED 602 594 1196 C C SuperGPQA/0f14cd17be174618af6d60227e7dca9f + 30 PASSED 753 1221 1974 293 293 AIME2025/aime2025-21 + 31 PASSED 254 299 553 C C GPQA Diamond/recA1i5ZAh0Uzclxp + 32 PASSED 394 349 743 J J SuperGPQA/cef9bcc087434cc2b4e354a9baef55eb + 33 PASSED 196 2794 2990 821 821 AIME2025/aime2025-07 + 34 FAILED 216 592 808 A B GPQA Diamond/recqGD3fxPCI59vPQ + 35 PASSED 159 75 234 I I SuperGPQA/9f93aa2cfdb547b5b3a4623f80f7fff6 + 36 PASSED 137 1358 1495 237 237 AIME2025/aime2025-22 + 37 FAILED 306 507 813 B A GPQA Diamond/rechKl68Uc6H7vU0N + 38 PASSED 157 45 202 E E SuperGPQA/97ad69dda7b2462c98638b79e78aea0b + 39 PASSED 156 853 1009 77 77 AIME2025/aime2025-08 + 40 PASSED 369 525 894 B B GPQA Diamond/rec1zl5LvaatzGhFt + 41 PASSED 128 67 195 H H SuperGPQA/e78e4e539d6f4e379ac140d923d7b1be + 42 FAILED 147 4096 4243 9595 62 AIME2025/aime2025-09 + 43 PASSED 585 111 696 A A GPQA Diamond/recTs7qzfJs6kfLUK + 44 PASSED 182 147 329 A A SuperGPQA/8483667a25e74fdfa3188de4ea734f03 + 45 FAILED 140 1256 1396 90 149 AIME2025/aime2025-24 + 46 PASSED 238 258 496 C C GPQA Diamond/rec32C1ZEapBnCC0E + 47 PASSED 153 451 604 A A SuperGPQA/e5ed76ef98144f06843125daf1bccd35 + 48 FAILED 335 4096 4431 3 81 AIME2025/aime2025-10 + 49 PASSED 225 332 557 B B GPQA Diamond/recZWeueB7lSPR6wN + 50 PASSED 127 88 215 H H SuperGPQA/fd7924876c4845cd83d95d61dfa0b236 + 51 PASSED 117 3585 3702 907 907 AIME2025/aime2025-25 + 52 PASSED 115 4096 4211 C C GPQA Diamond/recVvpD8miVjmmyfe + 53 PASSED 336 274 610 I I SuperGPQA/6bfe7d19299d4b3184636e1f51694306 + 54 FAILED 106 1490 1596 128 113 AIME2025/aime2025-26 + 55 PASSED 225 1572 1797 D D GPQA Diamond/recAAJoHMW45Lv5je + 56 PASSED 410 299 709 J J SuperGPQA/e1825d70c5844c22933087eafa89e39c + 57 PASSED 160 3271 3431 510 510 AIME2025/aime2025-12 + 58 FAILED 267 472 739 D C GPQA Diamond/reckEnrOPFT9Ru7tW + 59 PASSED 239 577 816 A A SuperGPQA/ab430ac3f18e4e02a2cb3f35498c6b30 + 60 PASSED 284 1468 1752 19 19 AIME2025/aime2025-27 + 61 PASSED 495 380 875 A A GPQA Diamond/rec8nshandHARTkrg + 62 PASSED 389 306 695 F F SuperGPQA/e8c5da5ca40647158b0c91dd695c6243 + 63 FAILED 129 3924 4053 106 204 AIME2025/aime2025-13 + 64 PASSED 449 696 1145 A A GPQA Diamond/recFaL6j8UMhutXrc + 65 PASSED 190 733 923 H H SuperGPQA/05efdc6fb2404ddc8dd5729bb68c74e5 + 66 FAILED 182 4096 4278 3 248 AIME2025/aime2025-28 + 67 FAILED 207 487 694 B C GPQA Diamond/reczQ4I0VpENdMtIj + 68 PASSED 470 505 975 H H SuperGPQA/ba52e06cbe1a4310a77a7d12cd1db943 + 69 FAILED 141 4096 4237 54 104 AIME2025/aime2025-29 + 70 FAILED 777 180 957 A C GPQA Diamond/recWxGU8Q4YReJ1tb + 71 FAILED 277 720 997 D F SuperGPQA/591a77df21324272914be82ac6583399 + 72 FAILED 127 4096 4223 1 735 AIME2025/aime2025-15 + 73 FAILED 220 221 441 A B GPQA Diamond/recMicVBcqy1xM1jq + 74 FAILED 202 110 312 J H SuperGPQA/e780f37a5baa4fe094cd9c157486664d + 75 FAILED 128 4096 4224 1 240 AIME2025/aime2025-30 + 76 PASSED 411 94 505 20 17-20 COMPSEC/compsec-076 + 77 PASSED 350 152 502 18,19,20 18-20 COMPSEC/compsec-077 + 78 PASSED 358 143 501 11 11 COMPSEC/compsec-078 + 79 FAILED 383 102 485 10 18-19 COMPSEC/compsec-079 + 80 FAILED 307 80 387 8 5-6 COMPSEC/compsec-080 + 81 PASSED 347 124 471 10 10-15 COMPSEC/compsec-081 + 82 PASSED 296 100 396 10 9-10 COMPSEC/compsec-082 + 83 PASSED 323 111 434 10 9-11 COMPSEC/compsec-083 + 84 PASSED 321 108 429 7 6-7 COMPSEC/compsec-084 + 85 PASSED 247 110 357 5 5 COMPSEC/compsec-085 + 86 PASSED 372 73 445 3 3,13-15 COMPSEC/compsec-086 + 87 PASSED 462 77 539 8 8,20-22 COMPSEC/compsec-087 + 88 PASSED 327 79 406 11 11 COMPSEC/compsec-088 + 89 PASSED 268 67 335 10 10 COMPSEC/compsec-089 + 90 PASSED 359 139 498 12 12-13 COMPSEC/compsec-090 + 91 PASSED 259 80 339 3 3 COMPSEC/compsec-091 + 92 PASSED 327 180 507 11 10-14 COMPSEC/compsec-092 \ No newline at end of file diff --git a/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-metal.log b/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-metal.log new file mode 100644 index 000000000..d06b0af17 --- /dev/null +++ b/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-metal.log @@ -0,0 +1,106 @@ +% ./ds4-eval --nothink --tokens 4096 +ds4: Metal device Apple M5 Max, 128.00 GiB RAM +ds4: Metal 4 tensor API enabled for Tensor kernels +ds4: drift-patch flags hc_stable=on norm_unify=on kv_raw_f32=off rope_exp2_log2=off math_safe=off tensor_matmul=on +ds4: requesting Metal residency (may take tens of seconds)... done +ds4: warming Metal model views... done +ds4: Metal model views created in 2.195 ms, residency requested in 397.073 ms, warmup 3.456 ms (mapped 82697.67 MiB from offset 5.09 MiB) +ds4: Metal mapped mmaped model as 2 overlapping shared buffers +ds4: metal backend initialized for graph diagnostics +ds4-eval: context auto-sized to 4873 tokens (largest prompt=777 tokens, case=70, generation budget=4096) +ds4-eval: model shape DeepSeek V4 Flash +ds4-eval: context buffers 443.94 MiB (ctx=4873, backend=metal, prefill_chunk=4096, raw_kv_rows=4352, compressed_kv_rows=1220) +ds4-eval: 67/92 passed, 25 failed, runtime 00h:47m +# state prompt gen total given correct test + 1 PASSED 201 385 586 B B GPQA Diamond/recNu3MXkvWUzHZr9 + 2 PASSED 149 60 209 C C SuperGPQA/001b51d76b4d422988f2c11f104a2c6c + 3 PASSED 81 288 369 70 70 AIME2025/aime2025-01 + 4 PASSED 313 168 481 C C GPQA Diamond/recoiTJPGUmzAkief + 5 PASSED 272 95 367 J J SuperGPQA/b7e20eac98764fb0bf30e8366d951daa + 6 FAILED 146 4096 4242 26 468 AIME2025/aime2025-16 + 7 PASSED 156 573 729 B B GPQA Diamond/rec4UqStf9WUVif1f + 8 PASSED 127 60 187 E E SuperGPQA/4a1d1780a93f4093b6fb7d3c314cbea8 + 9 PASSED 633 2691 3324 588 588 AIME2025/aime2025-02 + 10 PASSED 182 508 690 B B GPQA Diamond/recgI6tUQ7RLJRWGx + 11 PASSED 137 59 196 A A SuperGPQA/6082513c8dba4ec68aa68f1bf5854d09 + 12 PASSED 165 501 666 16 16 AIME2025/aime2025-03 + 13 PASSED 149 1887 2036 A A GPQA Diamond (modified)/recDytVnNYZe2HuUU + 14 PASSED 167 49 216 J J SuperGPQA/bebf1ed45ae14ad7b4f205f3909cb58a + 15 PASSED 305 2481 2786 82 82 AIME2025/aime2025-18 + 16 PASSED 131 389 520 D D GPQA Diamond/recNFJjE5PPTqVJGv + 17 PASSED 175 48 223 I I SuperGPQA/7ca71b86327744b78e93185a45bc5cef + 18 PASSED 102 686 788 117 117 AIME2025/aime2025-04 + 19 PASSED 187 293 480 B B GPQA Diamond/rec2UlKqC6RFHdcro + 20 PASSED 173 285 458 E E SuperGPQA/d44b94f7749345a39a65f6312bda8764 + 21 PASSED 229 916 1145 106 106 AIME2025/aime2025-19 + 22 PASSED 250 89 339 B B GPQA Diamond/recv7GsQg3f0fvB1f + 23 PASSED 232 63 295 B B SuperGPQA/febe406f44d74a40b50bb5b7c69d5dc1 + 24 FAILED 126 2263 2389 2583 279 AIME2025/aime2025-05 + 25 PASSED 229 4096 4325 C C GPQA Diamond/recrHBEJJoDTV05JR + 26 PASSED 160 388 548 C C SuperGPQA/31950dc80ded400a9181f50626d1f75c + 27 PASSED 124 555 679 504 504 AIME2025/aime2025-06 + 28 PASSED 198 268 466 D D GPQA Diamond/recb80OwMgNnceA9t + 29 PASSED 602 529 1131 C C SuperGPQA/0f14cd17be174618af6d60227e7dca9f + 30 PASSED 753 2823 3576 293 293 AIME2025/aime2025-21 + 31 PASSED 254 295 549 C C GPQA Diamond/recA1i5ZAh0Uzclxp + 32 PASSED 394 349 743 J J SuperGPQA/cef9bcc087434cc2b4e354a9baef55eb + 33 FAILED 196 611 807 12 821 AIME2025/aime2025-07 + 34 PASSED 216 602 818 B B GPQA Diamond/recqGD3fxPCI59vPQ + 35 PASSED 159 85 244 I I SuperGPQA/9f93aa2cfdb547b5b3a4623f80f7fff6 + 36 FAILED 137 1307 1444 60671 237 AIME2025/aime2025-22 + 37 FAILED 306 407 713 B A GPQA Diamond/rechKl68Uc6H7vU0N + 38 PASSED 157 45 202 E E SuperGPQA/97ad69dda7b2462c98638b79e78aea0b + 39 PASSED 156 1565 1721 77 77 AIME2025/aime2025-08 + 40 PASSED 369 525 894 B B GPQA Diamond/rec1zl5LvaatzGhFt + 41 FAILED 128 45 173 E H SuperGPQA/e78e4e539d6f4e379ac140d923d7b1be + 42 FAILED 147 4096 4243 53 62 AIME2025/aime2025-09 + 43 PASSED 585 150 735 A A GPQA Diamond/recTs7qzfJs6kfLUK + 44 PASSED 182 176 358 A A SuperGPQA/8483667a25e74fdfa3188de4ea734f03 + 45 FAILED 140 1039 1179 150 149 AIME2025/aime2025-24 + 46 PASSED 238 308 546 C C GPQA Diamond/rec32C1ZEapBnCC0E + 47 PASSED 153 444 597 A A SuperGPQA/e5ed76ef98144f06843125daf1bccd35 + 48 FAILED 335 1535 1870 77 81 AIME2025/aime2025-10 + 49 FAILED 225 4096 4321 C B GPQA Diamond/recZWeueB7lSPR6wN + 50 FAILED 127 87 214 E H SuperGPQA/fd7924876c4845cd83d95d61dfa0b236 + 51 PASSED 117 3573 3690 907 907 AIME2025/aime2025-25 + 52 PASSED 115 4096 4211 C C GPQA Diamond/recVvpD8miVjmmyfe + 53 PASSED 336 256 592 I I SuperGPQA/6bfe7d19299d4b3184636e1f51694306 + 54 FAILED 106 485 591 1 113 AIME2025/aime2025-26 + 55 PASSED 225 1398 1623 D D GPQA Diamond/recAAJoHMW45Lv5je + 56 PASSED 410 347 757 J J SuperGPQA/e1825d70c5844c22933087eafa89e39c + 57 FAILED 160 4096 4256 1 510 AIME2025/aime2025-12 + 58 FAILED 267 492 759 D C GPQA Diamond/reckEnrOPFT9Ru7tW + 59 PASSED 239 505 744 A A SuperGPQA/ab430ac3f18e4e02a2cb3f35498c6b30 + 60 PASSED 284 1592 1876 19 19 AIME2025/aime2025-27 + 61 PASSED 495 304 799 A A GPQA Diamond/rec8nshandHARTkrg + 62 PASSED 389 359 748 F F SuperGPQA/e8c5da5ca40647158b0c91dd695c6243 + 63 FAILED 129 4096 4225 287 204 AIME2025/aime2025-13 + 64 PASSED 449 768 1217 A A GPQA Diamond/recFaL6j8UMhutXrc + 65 PASSED 190 666 856 H H SuperGPQA/05efdc6fb2404ddc8dd5729bb68c74e5 + 66 FAILED 182 4096 4278 2 248 AIME2025/aime2025-28 + 67 FAILED 207 95 302 B C GPQA Diamond/reczQ4I0VpENdMtIj + 68 PASSED 470 1091 1561 H H SuperGPQA/ba52e06cbe1a4310a77a7d12cd1db943 + 69 PASSED 141 3459 3600 104 104 AIME2025/aime2025-29 + 70 FAILED 777 236 1013 A C GPQA Diamond/recWxGU8Q4YReJ1tb + 71 FAILED 277 529 806 D F SuperGPQA/591a77df21324272914be82ac6583399 + 72 FAILED 127 4096 4223 3 735 AIME2025/aime2025-15 + 73 FAILED 220 215 435 A B GPQA Diamond/recMicVBcqy1xM1jq + 74 FAILED 202 89 291 J H SuperGPQA/e780f37a5baa4fe094cd9c157486664d + 75 FAILED 128 4096 4224 18 240 AIME2025/aime2025-30 + 76 PASSED 411 112 523 20 17-20 COMPSEC/compsec-076 + 77 PASSED 350 126 476 18,19,20 18-20 COMPSEC/compsec-077 + 78 PASSED 358 129 487 11 11 COMPSEC/compsec-078 + 79 PASSED 383 78 461 18 18-19 COMPSEC/compsec-079 + 80 FAILED 307 78 385 8 5-6 COMPSEC/compsec-080 + 81 FAILED 347 159 506 8 10-15 COMPSEC/compsec-081 + 82 PASSED 296 123 419 10 9-10 COMPSEC/compsec-082 + 83 PASSED 323 104 427 11 9-11 COMPSEC/compsec-083 + 84 PASSED 321 108 429 7 6-7 COMPSEC/compsec-084 + 85 PASSED 247 104 351 5 5 COMPSEC/compsec-085 + 86 PASSED 372 63 435 3 3,13-15 COMPSEC/compsec-086 + 87 PASSED 462 77 539 8 8,20-22 COMPSEC/compsec-087 + 88 PASSED 327 79 406 11 11 COMPSEC/compsec-088 + 89 PASSED 268 72 340 10 10 COMPSEC/compsec-089 + 90 PASSED 359 70 429 12 12-13 COMPSEC/compsec-090 + 91 PASSED 259 70 329 3 3 COMPSEC/compsec-091 + 92 PASSED 327 203 530 11 10-14 COMPSEC/compsec-092 \ No newline at end of file diff --git a/artifacts/issue-304/ds4-eval/raw/.gitignore b/artifacts/issue-304/ds4-eval/raw/.gitignore new file mode 100644 index 000000000..d6b7ef32c --- /dev/null +++ b/artifacts/issue-304/ds4-eval/raw/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md index f69820fb7..f964405ca 100644 --- a/artifacts/issue-304/perf-breakdown.md +++ b/artifacts/issue-304/perf-breakdown.md @@ -41,6 +41,31 @@ Interpretation: first-token latency, but the current data does not justify KV pipelining for throughput-oriented Phase 5 benchmarking. +### 2026-06-06 `ds4-eval` local-decode handoff smoke + +After the evaluator was patched to use distributed handoff for eligible +`--nothink` local-decode coordinator cases, a fresh `Q1` +`CUDA -> Metal --local-decode` smoke produced: + +| Surface | Route | Prompt | Prompt tokens | Generated tokens | Prefill sec | Decode sec | Decode tok/s | Result | Notes | +| --- | --- | --- | ---: | ---: | ---: | ---: | ---: | --- | --- | +| `ds4-eval` | `CUDA -> Metal`, worker `--local-decode` | `GPQA Diamond/recNu3MXkvWUzHZr9` | 201 | 539 | 3.023 | 54.426 | 9.903 | Pass | evaluator now uses distributed handoff for eligible `--nothink` local-decode | + +Interpretation: + +- This is no longer the old per-token evaluator loop mistake. The evaluator + route now activates the worker-owned local-decode handoff path for the + tested `--nothink` case. +- Even after that fix, evaluator throughput is still well below the plain + CLI `CUDA -> Metal` local-decode benchmark (`30.10` to `30.33 tok/s`). +- Code inspection explains the remaining gap: the current worker + `LOCAL_GENERATE` RPC allocates, fills, and returns a full logits trace for + every generated token, and the reported `decode_usec` includes that extra + work. +- So the current evaluator-vs-CLI gap should be treated as protocol + overhead in the local-generate response path, not as proof that Metal + local decode itself only sustains `~10 tok/s`. + ## Phase 4 final-worker handoff timings Tool: diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index f3be18053..9af49ad79 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -455,12 +455,55 @@ The remaining work should separate: - `top5=4/5`, `top10=8/10`, `top20=15/20` - turn-two tokens still matched exactly - So the remaining reused-session follow-up-sync variance is present in - both directions, but it is not equally severe on the sampled path. + both directions, but it is not equally severe on the sampled path. + +8. The first `ds4-eval` local-decode matrix runs initially measured the + wrong workflow. + - The original Phase 5 `ds4-eval` matrix used the normal + `ds4_session_sample()` + `ds4_session_eval()` loop even when the route + advertised worker-owned local decode. + - That meant the evaluator was exercising the "forced one-token + `LOCAL_GENERATE`" path, not the worker-owned one-shot handoff path used + by the plain `ds4` CLI benchmarks. + - This explained the misleading early matrix result where + `CUDA -> Metal --local-decode` looked materially slower than the plain + CLI workflow. + +9. `ds4-eval` now uses the proper worker-owned handoff path for eligible + `--nothink` local-decode coordinator runs. + - The evaluator was updated to call the distributed handoff API instead of + always staying in the generic per-token decode loop. + - A fresh `Q1` smoke on `CUDA -> Metal --local-decode --nothink` then + passed through the intended handoff workflow: + - route summary: `local 0:21 -> 192.168.1.218:51924 Q2 22:output` + - `local_decode_expected: yes` + - summary `local_decode_active_any_case: yes` + - `generated_tokens: 539` + - `decode_sec: 54.426` + - `generated_tps: 9.903` + +10. After correcting the evaluator workflow, the remaining throughput gap is + in the current handoff RPC payload shape, not in evaluator control flow. + - Plain CLI `CUDA -> Metal --local-decode` on the long README prompt had + already shown `generation: 30.10 t/s` to `30.33 t/s`. + - The corrected `ds4-eval` handoff smoke was still only about + `9.9 t/s`. + - Code inspection showed why: the worker local-generate RPC currently + allocates, fills, and returns a full logits trace for every generated + token, and the reported `decode_usec` includes that extra work. + - So the remaining performance discrepancy is now best described as a + protocol-overhead issue in the current `LOCAL_GENERATE` response path, + not as evidence that the Mac local-decode backend is fundamentally + slower than the plain local-decode CLI benchmark. ### Implication Phase 5 has crossed the implementation threshold: the intended CLI workflow is real, benchmarkable, and no longer dependent on the issue harnesses. -The next work should focus on extending surface coverage and preserving -correctness for reusable/sample-driven flows, not on adding KV pipelining -prematurely. +The next work should focus on: + +- preserving correctness for reusable/sample-driven flows, +- making the evaluator and benchmark surfaces use the same worker-owned + local-decode workflow where intended, +- and reducing local-generate protocol overhead before interpreting + `ds4-eval` local-decode throughput as a backend limit. diff --git a/ds4.c b/ds4.c index 5ea16309c..5eae0929c 100644 --- a/ds4.c +++ b/ds4.c @@ -20703,6 +20703,25 @@ int ds4_session_distributed_route_summary( errlen); } +int ds4_session_distributed_route_info( + ds4_session *s, + ds4_distributed_route_info *info, + char *summary, + size_t summary_len, + char *err, + size_t errlen) { + if (!s || !s->distributed) { + if (errlen) snprintf(err, errlen, "session is not a distributed coordinator"); + return -1; + } + return ds4_dist_session_describe_route_info(s->distributed, + info, + summary, + summary_len, + err, + errlen); +} + int ds4_session_distributed_handoff_argmax( ds4_session *s, int n_predict, diff --git a/ds4.h b/ds4.h index 3db0034d4..b8e97bb60 100644 --- a/ds4.h +++ b/ds4.h @@ -57,6 +57,13 @@ typedef struct { typedef struct ds4_engine ds4_engine; typedef struct ds4_session ds4_session; +typedef struct { + uint32_t route_hops; + bool output_on_coordinator; + bool local_decode_expected; + bool local_decode_active; +} ds4_distributed_route_info; + typedef void (*ds4_session_progress_fn)(void *ud, const char *event, int current, int total); typedef enum { @@ -227,6 +234,13 @@ int ds4_session_distributed_route_summary( bool *output_on_coordinator, char *err, size_t errlen); +int ds4_session_distributed_route_info( + ds4_session *s, + ds4_distributed_route_info *info, + char *summary, + size_t summary_len, + char *err, + size_t errlen); int ds4_session_distributed_handoff_argmax( ds4_session *s, int n_predict, diff --git a/ds4_distributed.c b/ds4_distributed.c index c91a83e0d..903c439f5 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -2147,6 +2147,7 @@ static bool dist_coordinator_format_route_summary( size_t summary_len, uint32_t *route_hops, bool *output_on_coordinator, + bool *local_decode_expected, uint32_t *missing_layer, bool *ready, char *err, @@ -2154,6 +2155,7 @@ static bool dist_coordinator_format_route_summary( if (summary_len != 0 && summary) summary[0] = '\0'; if (route_hops) *route_hops = 0; if (output_on_coordinator) *output_on_coordinator = false; + if (local_decode_expected) *local_decode_expected = false; if (missing_layer) *missing_layer = 0; if (ready) *ready = false; if (!state) { @@ -2229,6 +2231,7 @@ static bool dist_coordinator_format_route_summary( end); } bool local_output = false; + bool route_local_decode = false; if (complete && path_len != 0 && !path[path_len - 1u]->has_output && state->local_can_output_head) { local_output = true; @@ -2246,6 +2249,10 @@ static bool dist_coordinator_format_route_summary( " -> local output"); } } + if (complete && path_len != 0) { + route_local_decode = path[path_len - 1u]->wants_local_decode && + path[path_len - 1u]->has_output; + } complete = complete && has_output && next == state->n_layers; pthread_mutex_unlock(&state->mu); @@ -2255,6 +2262,7 @@ static bool dist_coordinator_format_route_summary( if (missing_layer) *missing_layer = missing; if (ready) *ready = complete; if (output_on_coordinator) *output_on_coordinator = local_output || local_has_output; + if (local_decode_expected) *local_decode_expected = route_local_decode; free(path); free(workers); if (errlen) err[0] = '\0'; @@ -2272,6 +2280,7 @@ static void dist_coordinator_report_plan(ds4_dist_coordinator_state *state) { sizeof(plan), NULL, NULL, + NULL, &missing, &complete, err, @@ -6422,6 +6431,45 @@ int ds4_dist_session_describe_route( summary_len, route_hops, output_on_coordinator, + NULL, + &missing, + &ready, + err, + errlen)) { + return -1; + } + if (!ready) { + if (errlen) snprintf(err, errlen, "distributed route incomplete: missing layer %u", missing); + return 0; + } + if (errlen) err[0] = '\0'; + return 1; +} + +int ds4_dist_session_describe_route_info( + ds4_dist_session *d, + ds4_distributed_route_info *info, + char *summary, + size_t summary_len, + char *err, + size_t errlen) { + if (!d) { + if (errlen) snprintf(err, errlen, "missing distributed session"); + return -1; + } + if (info) memset(info, 0, sizeof(*info)); + + uint32_t missing = 0; + bool ready = false; + uint32_t route_hops = 0; + bool output_on_coordinator = false; + bool local_decode_expected = false; + if (!dist_coordinator_format_route_summary(&d->state, + summary, + summary_len, + &route_hops, + &output_on_coordinator, + &local_decode_expected, &missing, &ready, err, @@ -6432,6 +6480,12 @@ int ds4_dist_session_describe_route( if (errlen) snprintf(err, errlen, "distributed route incomplete: missing layer %u", missing); return 0; } + if (info) { + info->route_hops = route_hops; + info->output_on_coordinator = output_on_coordinator; + info->local_decode_expected = local_decode_expected; + info->local_decode_active = d->local_decode_active; + } if (errlen) err[0] = '\0'; return 1; } @@ -9182,9 +9236,7 @@ static int dist_worker_read_loop_prefetch(ds4_dist_worker_state *state, int fd, } int loop_rc = 0; - fprintf(stderr, - "ds4: distributed worker: receive prefetch depth %u enabled\n", - queue.depth); + DIST_DEBUG("worker receive prefetch depth %u enabled", queue.depth); for (;;) { uint32_t type = 0, bytes = 0; diff --git a/ds4_distributed.h b/ds4_distributed.h index 8cf1ff012..70ee612ed 100644 --- a/ds4_distributed.h +++ b/ds4_distributed.h @@ -87,6 +87,13 @@ int ds4_dist_session_describe_route( bool *output_on_coordinator, char *err, size_t errlen); +int ds4_dist_session_describe_route_info( + ds4_dist_session *d, + ds4_distributed_route_info *info, + char *summary, + size_t summary_len, + char *err, + size_t errlen); int ds4_dist_session_handoff_argmax( ds4_dist_session *d, ds4_session *owner, diff --git a/ds4_eval.c b/ds4_eval.c index ecb4881c5..0ab6d67bc 100644 --- a/ds4_eval.c +++ b/ds4_eval.c @@ -1225,6 +1225,23 @@ typedef struct { int rank; } eval_think_close_info; +typedef struct { + bool distributed; + char distributed_role[32]; + char route_summary[1024]; + char output_owner[32]; + char host_role_label[64]; + uint32_t route_hops; + bool local_decode_expected; + bool local_decode_active; + bool local_decode_active_any_case; +} eval_trace_metadata; + +static void eval_trace_metadata_init(eval_trace_metadata *meta, const eval_config *cfg); +static void eval_trace_metadata_update(eval_trace_metadata *meta, + ds4_session *session, + const eval_config *cfg); + typedef struct { int cols; int rows; @@ -2484,7 +2501,8 @@ static int token_rank_in_top(ds4_session *session, int token, int max_rank) { static void trace_write_header(FILE *trace, const eval_config *cfg, const char *model_name, int ncases, - int max_prompt_tokens) { + int max_prompt_tokens, + const eval_trace_metadata *meta) { if (!trace) return; fprintf(trace, "# ds4-eval trace\n" @@ -2504,6 +2522,14 @@ static void trace_write_header(FILE *trace, const eval_config *cfg, "soft_limit_reply_budget: %d\n" "hard_limit_reply_budget: %d\n" "soft_limit_think_close_rank: %d\n" + "distributed: %s\n" + "distributed_role: %s\n" + "route_summary: %s\n" + "route_hops: %u\n" + "output_owner: %s\n" + "local_decode_expected: %s\n" + "local_decode_active: %s\n" + "host_role_label: %s\n" "\n", (long long)time(NULL), cfg->model_path, @@ -2520,7 +2546,15 @@ static void trace_write_header(FILE *trace, const eval_config *cfg, ds4_think_mode_name(cfg->think_mode), cfg->soft_limit_reply_budget, cfg->hard_limit_reply_budget, - cfg->soft_limit_think_close_rank); + cfg->soft_limit_think_close_rank, + meta && meta->distributed ? "yes" : "no", + meta ? meta->distributed_role : "local", + meta ? meta->route_summary : "local", + meta ? meta->route_hops : 0u, + meta ? meta->output_owner : "local", + meta && meta->local_decode_expected ? "yes" : "no", + meta && meta->local_decode_active ? "yes" : "no", + meta ? meta->host_role_label : "local-reference"); fflush(trace); } @@ -2537,6 +2571,12 @@ static void trace_write_case(FILE *trace, ds4_think_mode effective_think_mode, int prompt_tokens, int generated_tokens, + int think_tokens, + int answer_tokens, + double prefill_sec, + double think_decode_sec, + double answer_decode_sec, + double decode_sec, double elapsed_sec, const char *picked, const eval_think_close_info *think_close) { @@ -2554,7 +2594,14 @@ static void trace_write_case(FILE *trace, "expected: %s\n" "prompt_tokens: %d\n" "generated_tokens: %d\n" + "think_tokens: %d\n" + "answer_tokens: %d\n" + "prefill_sec: %.3f\n" + "think_decode_sec: %.3f\n" + "answer_decode_sec: %.3f\n" + "decode_sec: %.3f\n" "elapsed_sec: %.3f\n" + "generated_tps: %.3f\n" "temperature: %.6g\n" "top_p: %.6g\n" "min_p: %.6g\n" @@ -2570,7 +2617,14 @@ static void trace_write_case(FILE *trace, tc->answer, prompt_tokens, generated_tokens, + think_tokens, + answer_tokens, + prefill_sec, + think_decode_sec, + answer_decode_sec, + decode_sec, elapsed_sec, + decode_sec > 0.001 ? (double)generated_tokens / decode_sec : 0.0, cfg->temperature, cfg->top_p, cfg->min_p, @@ -3318,6 +3372,35 @@ static double tui_wait_if_paused(eval_ui *ui, const char *phase) { return now_sec() - start; } +static bool eval_can_use_local_decode_handoff(ds4_session *session, + const eval_config *cfg, + const eval_ui *ui, + ds4_think_mode think_mode) { + if (!session || !cfg) return false; + if (ui && ui->enabled) return false; + if (ds4_think_mode_enabled(think_mode)) return false; + if (!ds4_session_is_distributed(session)) return false; + if (cfg->dist.role != DS4_DISTRIBUTED_COORDINATOR) return false; + + ds4_distributed_route_info info = {0}; + char summary[256] = {0}; + char err[256] = {0}; + int rc = ds4_session_distributed_route_info(session, + &info, + summary, + sizeof(summary), + err, + sizeof(err)); + if (rc <= 0) return false; + return info.local_decode_expected && !info.output_on_coordinator; +} + +static uint64_t eval_handoff_next_seed(uint64_t *rng, uint64_t fallback) { + uint64_t seed = (rng && *rng) ? *rng : fallback; + if (rng) *rng = seed * 6364136223846793005ull + 1ull; + return seed; +} + static void eval_prefill_progress(void *ud, const char *event, int current, int total) { eval_ui *ui = ud; if (!ui || !event) return; @@ -3336,7 +3419,8 @@ static void eval_prefill_progress(void *ud, const char *event, int current, int static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, const eval_config *cfg, eval_ui *ui, - FILE *trace, int idx, uint64_t *rng) { + FILE *trace, eval_trace_metadata *trace_meta, + int idx, uint64_t *rng) { const eval_case *tc = &eval_cases[idx]; const bool tty = ui->enabled; const bool use_plain_color = !tty && isatty(STDOUT_FILENO); @@ -3362,7 +3446,7 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, tui_refresh(ui, "idle"); trace_write_case(trace, cfg, tc, idx, ui->ncases, "SKIPPED", "prompt does not fit context", system, question, "", - think_mode, prompt.len, 0, 0.0, "?", NULL); + think_mode, prompt.len, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, "?", NULL); if (!tty) { printf("\n[%d/%d] SKIPPED %s/%s prompt=%d ctx=%d\n", idx + 1, ui->ncases, tc->source, tc->id, prompt.len, cfg->ctx_size); @@ -3383,7 +3467,7 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, tui_refresh(ui, "idle"); trace_write_case(trace, cfg, tc, idx, ui->ncases, "SKIPPED", "prompt leaves no generation room", system, question, "", - think_mode, prompt.len, 0, 0.0, "?", NULL); + think_mode, prompt.len, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, 0.0, "?", NULL); if (!tty) { printf("\n[%d/%d] SKIPPED %s/%s prompt=%d ctx=%d\n", idx + 1, ui->ncases, tc->source, tc->id, prompt.len, cfg->ctx_size); @@ -3420,17 +3504,21 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, char err[256]; ds4_session_set_progress(session, eval_prefill_progress, ui); ds4_session_set_display_progress(session, eval_prefill_progress, ui); + double prefill_t0 = now_sec(); if (ds4_session_sync(session, &prompt, err, sizeof(err)) != 0) { + double prefill_sec = now_sec() - prefill_t0; ds4_session_set_progress(session, NULL, NULL); ds4_session_set_display_progress(session, NULL, NULL); tui_run_clock_stop(ui); fprintf(stderr, "ds4-eval: prefill failed for %s: %s\n", tc->id, err); trace_write_case(trace, cfg, tc, idx, ui->ncases, "ERROR", err, - system, question, "", think_mode, prompt.len, 0, 0.0, "?", NULL); + system, question, "", think_mode, prompt.len, 0, + 0, 0, prefill_sec, 0.0, 0.0, 0.0, prefill_sec, "?", NULL); free(question); ds4_tokens_free(&prompt); return EVAL_RUN_ERROR; } + double prefill_sec = now_sec() - prefill_t0; ds4_session_set_progress(session, NULL, NULL); ds4_session_set_display_progress(session, NULL, NULL); int prompt_tokens = prompt.len; @@ -3445,7 +3533,8 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, tui_run_clock_stop(ui); tui_refresh(ui, "idle"); trace_write_case(trace, cfg, tc, idx, ui->ncases, "STOPPED", NULL, - system, question, "", think_mode, prompt_tokens, 0, 0.0, "?", NULL); + system, question, "", think_mode, prompt_tokens, 0, + 0, 0, prefill_sec, 0.0, 0.0, 0.0, prefill_sec, "?", NULL); free(question); return EVAL_RUN_QUIT; } @@ -3454,7 +3543,8 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, tui_run_clock_stop(ui); tui_refresh(ui, "idle"); trace_write_case(trace, cfg, tc, idx, ui->ncases, "SWITCHED", NULL, - system, question, "", think_mode, prompt_tokens, 0, 0.0, "?", NULL); + system, question, "", think_mode, prompt_tokens, 0, + 0, 0, prefill_sec, 0.0, 0.0, 0.0, prefill_sec, "?", NULL); free(question); return EVAL_RUN_SWITCH; } @@ -3468,6 +3558,9 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, bool generation_in_think = ds4_think_mode_enabled(think_mode); eval_think_close_info think_close = {0}; ds4_tokens think_close_tokens = {0}; + int think_tokens_generated = 0; + int answer_tokens_generated = 0; + double think_decode_sec = 0.0; if (generation_in_think) ds4_tokenize_text(engine, "", &think_close_tokens); if (!tty && plain_in_think) plain_set_thinking_color(use_plain_color); tui_refresh(ui, "thinking"); @@ -3475,6 +3568,115 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, const int eos = ds4_token_eos(engine); double t0 = ui->phase_start_sec; int forced_close_pos = -1; + if (eval_can_use_local_decode_handoff(session, cfg, ui, think_mode)) { + int *tokens = calloc((size_t)generation_limit, sizeof(*tokens)); + if (!tokens) { + fprintf(stderr, "ds4-eval: out of memory allocating handoff token buffer\n"); + free(question); + ds4_tokens_free(&think_close_tokens); + buf_free(&raw); + return EVAL_RUN_ERROR; + } + char handoff_err[256] = {0}; + double shard_load_sec = 0.0; + double decode_sec = 0.0; + int produced = -1; + if (cfg->temperature == 0.0f) { + produced = ds4_session_distributed_handoff_argmax(session, + generation_limit, + tokens, + generation_limit, + &shard_load_sec, + &decode_sec, + handoff_err, + sizeof(handoff_err)); + } else { + uint64_t handoff_seed = eval_handoff_next_seed(rng, cfg->seed); + produced = ds4_session_distributed_handoff_generate(session, + generation_limit, + cfg->temperature, + cfg->top_p, + cfg->min_p, + handoff_seed, + tokens, + generation_limit, + &shard_load_sec, + &decode_sec, + handoff_err, + sizeof(handoff_err)); + } + if (produced < 0) { + free(tokens); + plain_reset_color(use_plain_color); + ui->generated_tokens[idx] = ui->generated; + tui_run_clock_stop(ui); + fprintf(stderr, "ds4-eval: distributed local-decode handoff failed for %s: %s\n", + tc->id, handoff_err[0] ? handoff_err : "unknown error"); + trace_write_case(trace, cfg, tc, idx, ui->ncases, "ERROR", + handoff_err[0] ? handoff_err : "distributed local-decode handoff failed", + system, question, raw.v ? raw.v : "", think_mode, + prompt_tokens, ui->generated, + 0, 0, + prefill_sec + shard_load_sec, 0.0, 0.0, decode_sec, + prefill_sec + shard_load_sec + decode_sec, "?", + &think_close); + free(question); + ds4_tokens_free(&think_close_tokens); + buf_free(&raw); + return EVAL_RUN_ERROR; + } + + for (int i = 0; i < produced; i++) { + size_t len = 0; + char *text = ds4_token_text(engine, tokens[i], &len); + buf_append(&raw, text, len); + ui->generated++; + ui->generated_tokens[idx] = ui->generated; + answer_tokens_generated++; + if (!tty) { + fwrite(text, 1, len, stdout); + fflush(stdout); + } + free(text); + if (tokens[i] == eos) break; + } + free(tokens); + if (!tty) { + plain_reset_color(use_plain_color); + if (!raw.v || raw.len == 0 || raw.v[raw.len - 1] != '\n') fputc('\n', stdout); + } + + char got[EVAL_ANSWER_MAX]; + find_case_answer(tc, raw.v ? raw.v : "", got, sizeof(got)); + snprintf(ui->guess[idx], EVAL_ANSWER_MAX, "%s", got); + bool pass = answer_matches(tc, got); + ui->status[idx] = pass ? EVAL_PASSED : EVAL_FAILED; + ui->generated_tokens[idx] = ui->generated; + tui_run_clock_stop(ui); + prefill_sec += shard_load_sec; + double sec = prefill_sec + decode_sec; + tui_refresh(ui, pass ? "passed" : "failed"); + trace_write_case(trace, cfg, tc, idx, ui->ncases, pass ? "PASSED" : "FAILED", NULL, + system, question, raw.v ? raw.v : "", think_mode, prompt_tokens, + ui->generated, + 0, answer_tokens_generated, + prefill_sec, 0.0, decode_sec, decode_sec, sec, got, &think_close); + eval_trace_metadata_update(trace_meta, session, cfg); + + if (!tty) { + printf("%s%s%s got %s expected %s (%.1fs, %d tokens)\n", + use_plain_color ? (pass ? ANSI_GREEN : ANSI_RED) : "", + pass ? "PASSED" : "FAIL", + use_plain_color ? ANSI_RESET : "", + got, tc->answer, sec, ui->generated); + } + + if (tty && cfg->pause_ms > 0) usleep((useconds_t)cfg->pause_ms * 1000); + free(question); + ds4_tokens_free(&think_close_tokens); + buf_free(&raw); + return EVAL_RUN_OK; + } for (int i = 0; i < generation_limit; i++) { if (tty) { tui_consume_input(ui); @@ -3483,9 +3685,15 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, ui->generated_tokens[idx] = ui->generated; tui_run_clock_stop(ui); tui_refresh(ui, "idle"); + double decode_sec = now_sec() - t0; + double answer_decode_sec = decode_sec - think_decode_sec; + if (answer_decode_sec < 0.0) answer_decode_sec = 0.0; trace_write_case(trace, cfg, tc, idx, ui->ncases, "STOPPED", NULL, system, question, raw.v ? raw.v : "", think_mode, - prompt_tokens, ui->generated, now_sec() - t0, "?", + prompt_tokens, ui->generated, + think_tokens_generated, answer_tokens_generated, + prefill_sec, think_decode_sec, answer_decode_sec, decode_sec, + prefill_sec + decode_sec, "?", &think_close); free(question); ds4_tokens_free(&think_close_tokens); @@ -3497,9 +3705,15 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, ui->generated_tokens[idx] = ui->generated; tui_run_clock_stop(ui); tui_refresh(ui, "idle"); + double decode_sec = now_sec() - t0; + double answer_decode_sec = decode_sec - think_decode_sec; + if (answer_decode_sec < 0.0) answer_decode_sec = 0.0; trace_write_case(trace, cfg, tc, idx, ui->ncases, "SWITCHED", NULL, system, question, raw.v ? raw.v : "", think_mode, - prompt_tokens, ui->generated, now_sec() - t0, "?", + prompt_tokens, ui->generated, + think_tokens_generated, answer_tokens_generated, + prefill_sec, think_decode_sec, answer_decode_sec, decode_sec, + prefill_sec + decode_sec, "?", &think_close); free(question); ds4_tokens_free(&think_close_tokens); @@ -3516,9 +3730,15 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, ui->generated_tokens[idx] = ui->generated; tui_run_clock_stop(ui); tui_refresh(ui, "idle"); + double decode_sec = now_sec() - t0; + double answer_decode_sec = decode_sec - think_decode_sec; + if (answer_decode_sec < 0.0) answer_decode_sec = 0.0; trace_write_case(trace, cfg, tc, idx, ui->ncases, "STOPPED", NULL, system, question, raw.v ? raw.v : "", think_mode, - prompt_tokens, ui->generated, now_sec() - t0, "?", + prompt_tokens, ui->generated, + think_tokens_generated, answer_tokens_generated, + prefill_sec, think_decode_sec, answer_decode_sec, decode_sec, + prefill_sec + decode_sec, "?", &think_close); free(question); ds4_tokens_free(&think_close_tokens); @@ -3530,9 +3750,15 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, ui->generated_tokens[idx] = ui->generated; tui_run_clock_stop(ui); tui_refresh(ui, "idle"); + double decode_sec = now_sec() - t0; + double answer_decode_sec = decode_sec - think_decode_sec; + if (answer_decode_sec < 0.0) answer_decode_sec = 0.0; trace_write_case(trace, cfg, tc, idx, ui->ncases, "SWITCHED", NULL, system, question, raw.v ? raw.v : "", think_mode, - prompt_tokens, ui->generated, now_sec() - t0, "?", + prompt_tokens, ui->generated, + think_tokens_generated, answer_tokens_generated, + prefill_sec, think_decode_sec, answer_decode_sec, decode_sec, + prefill_sec + decode_sec, "?", &think_close); free(question); ds4_tokens_free(&think_close_tokens); @@ -3545,6 +3771,7 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, int close_rank = 0; int token = -1; eval_think_close_kind close_kind = EVAL_THINK_CLOSE_NONE; + bool was_in_think = generation_in_think; /* Benchmarks usually cap generation length, but DeepSeek can spend the * entire budget in . This controller only acts while the model is @@ -3587,9 +3814,15 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, ui->generated_tokens[idx] = ui->generated; tui_run_clock_stop(ui); fprintf(stderr, "ds4-eval: decode failed for %s: %s\n", tc->id, err); + double decode_sec = now_sec() - t0; + double answer_decode_sec = decode_sec - think_decode_sec; + if (answer_decode_sec < 0.0) answer_decode_sec = 0.0; trace_write_case(trace, cfg, tc, idx, ui->ncases, "ERROR", err, system, question, raw.v ? raw.v : "", think_mode, - prompt_tokens, ui->generated, now_sec() - t0, "?", + prompt_tokens, ui->generated, + think_tokens_generated, answer_tokens_generated, + prefill_sec, think_decode_sec, answer_decode_sec, decode_sec, + prefill_sec + decode_sec, "?", &think_close); free(question); ds4_tokens_free(&think_close_tokens); @@ -3602,9 +3835,12 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, buf_append(&raw, text, len); ui->generated++; ui->generated_tokens[idx] = ui->generated; + if (was_in_think) think_tokens_generated++; + else answer_tokens_generated++; tui_run_clock_tick(ui); if (generation_in_think && raw.v && strstr(raw.v, "")) { generation_in_think = false; + think_decode_sec = now_sec() - t0; if (think_close.kind == EVAL_THINK_CLOSE_NONE) { think_close.kind = EVAL_THINK_CLOSE_NATURAL; think_close.token_index = ui->generated; @@ -3643,11 +3879,19 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, ui->status[idx] = pass ? EVAL_PASSED : EVAL_FAILED; ui->generated_tokens[idx] = ui->generated; tui_run_clock_stop(ui); - double sec = now_sec() - t0; + double decode_sec = now_sec() - t0; + if (think_tokens_generated == 0) think_decode_sec = 0.0; + else if (think_decode_sec <= 0.0 || think_decode_sec > decode_sec) think_decode_sec = decode_sec; + double answer_decode_sec = decode_sec - think_decode_sec; + if (answer_decode_sec < 0.0) answer_decode_sec = 0.0; + double sec = prefill_sec + decode_sec; tui_refresh(ui, pass ? "passed" : "failed"); trace_write_case(trace, cfg, tc, idx, ui->ncases, pass ? "PASSED" : "FAILED", NULL, system, question, raw.v ? raw.v : "", think_mode, prompt_tokens, - ui->generated, sec, got, &think_close); + ui->generated, + think_tokens_generated, answer_tokens_generated, + prefill_sec, think_decode_sec, answer_decode_sec, decode_sec, sec, got, &think_close); + eval_trace_metadata_update(trace_meta, session, cfg); if (!tty) { printf("%s%s%s got %s expected %s (%.1fs, %d tokens)\n", @@ -3783,6 +4027,65 @@ static const char *report_status_name(eval_status st) { } } +static const char *eval_dist_role_name(const eval_config *cfg) { + if (!cfg) return "local"; + switch (cfg->dist.role) { + case DS4_DISTRIBUTED_COORDINATOR: return "coordinator"; + case DS4_DISTRIBUTED_WORKER: return "worker"; + case DS4_DISTRIBUTED_NONE: + default: return "local"; + } +} + +static const char *eval_host_role_label(const eval_config *cfg) { + if (!cfg || cfg->dist.role == DS4_DISTRIBUTED_NONE) return "local-reference"; + switch (cfg->backend) { + case DS4_BACKEND_METAL: return "metal-coordinator"; + case DS4_BACKEND_CUDA: return "cuda-coordinator"; + case DS4_BACKEND_CPU: return "cpu-coordinator"; + } + return "distributed-coordinator"; +} + +static void eval_trace_metadata_init(eval_trace_metadata *meta, const eval_config *cfg) { + if (!meta) return; + memset(meta, 0, sizeof(*meta)); + meta->distributed = cfg && cfg->dist.role != DS4_DISTRIBUTED_NONE; + snprintf(meta->distributed_role, sizeof(meta->distributed_role), "%s", + eval_dist_role_name(cfg)); + snprintf(meta->route_summary, sizeof(meta->route_summary), "%s", "local"); + snprintf(meta->output_owner, sizeof(meta->output_owner), "%s", "local"); + snprintf(meta->host_role_label, sizeof(meta->host_role_label), "%s", + eval_host_role_label(cfg)); +} + +static void eval_trace_metadata_update(eval_trace_metadata *meta, + ds4_session *session, + const eval_config *cfg) { + if (!meta || !session || !cfg || cfg->dist.role != DS4_DISTRIBUTED_COORDINATOR) return; + + ds4_distributed_route_info info = {0}; + char summary[sizeof(meta->route_summary)] = {0}; + char err[256] = {0}; + int rc = ds4_session_distributed_route_info(session, + &info, + summary, + sizeof(summary), + err, + sizeof(err)); + if (rc <= 0) return; + + meta->distributed = true; + meta->route_hops = info.route_hops; + meta->local_decode_expected = info.local_decode_expected; + meta->local_decode_active = info.local_decode_active; + if (info.local_decode_active) meta->local_decode_active_any_case = true; + snprintf(meta->route_summary, sizeof(meta->route_summary), "%s", + summary[0] ? summary : "distributed"); + snprintf(meta->output_owner, sizeof(meta->output_owner), "%s", + info.output_on_coordinator ? "coordinator" : "worker"); +} + static void print_eval_report(const eval_ui *ui, int ncases, int passed, int failed) { char elapsed[32]; format_run_elapsed(elapsed, sizeof(elapsed), tui_run_clock_visible_sec(ui)); @@ -3893,7 +4196,6 @@ int main(int argc, char **argv) { } fprintf(stderr, "ds4-eval: model shape %s\n", ds4_engine_model_name(engine)); eval_warn_think_max_downgraded(&cfg); - trace_write_header(trace, &cfg, ds4_engine_model_name(engine), ncases, max_prompt_tokens); log_context_memory(cfg.backend, cfg.ctx_size); ds4_session *session = NULL; @@ -3913,6 +4215,11 @@ int main(int argc, char **argv) { free(case_sequence); return 1; } + eval_trace_metadata trace_meta; + eval_trace_metadata_init(&trace_meta, &cfg); + eval_trace_metadata_update(&trace_meta, session, &cfg); + trace_write_header(trace, &cfg, ds4_engine_model_name(engine), ncases, max_prompt_tokens, + &trace_meta); eval_ui ui; bool split_ui = !cfg.plain && isatty(STDOUT_FILENO); @@ -3939,7 +4246,8 @@ int main(int argc, char **argv) { ui.selected_case = next; } - eval_run_result result = run_one_case(engine, session, &cfg, &ui, trace, next, &rng); + eval_run_result result = run_one_case(engine, session, &cfg, &ui, trace, &trace_meta, + next, &rng); if (result == EVAL_RUN_ERROR) { rc = 1; break; @@ -3967,9 +4275,11 @@ int main(int argc, char **argv) { int passed = 0; int failed = 0; + int skipped = 0; for (int i = 0; i < ncases; i++) { if (ui.status[i] == EVAL_PASSED) passed++; else if (ui.status[i] == EVAL_FAILED) failed++; + else if (ui.status[i] == EVAL_SKIPPED) skipped++; } if (ui.active) tui_restore(); @@ -3979,8 +4289,14 @@ int main(int argc, char **argv) { "===== SUMMARY =====\n" "passed: %d\n" "failed: %d\n" - "total: %d\n", - passed, failed, ncases); + "total: %d\n" + "skipped: %d\n" + "runtime_sec: %.3f\n" + "local_decode_active_any_case: %s\n", + passed, failed, ncases, + skipped, + tui_run_clock_visible_sec(&ui), + trace_meta.local_decode_active_any_case ? "yes" : "no"); fflush(trace); } diff --git a/ds4_help.c b/ds4_help.c index 2ca13df4b..f0dd11665 100644 --- a/ds4_help.c +++ b/ds4_help.c @@ -206,6 +206,7 @@ static void print_distributed(FILE *fp, const help_colors *c) { opt(fp, c, "--layers A:B", "Inclusive layer slice, e.g. 0:20 or 21:output."); opt(fp, c, "--listen HOST PORT", "Coordinator listen address; workers may use it for their data listener."); opt(fp, c, "--coordinator HOST PORT", "Coordinator address for --role worker."); + opt(fp, c, "--local-decode", "Worker-only: keep output ownership remote and run decode there."); opt(fp, c, "--dist-prefill-chunk N", "Coordinator prefill pipeline chunk size. Default: session cap."); opt(fp, c, "--dist-prefill-window N", "Max prefill chunks in flight. Default: workers+2, capped at 8."); opt(fp, c, "--dist-activation-bits N", "Hidden-state transport width: 32, 16, or 8. Default: 32"); @@ -419,7 +420,7 @@ static void print_more_info(FILE *fp, const help_colors *c, ds4_help_tool tool) static void print_examples(FILE *fp, const help_colors *c, ds4_help_tool tool, const char *topic) { title(fp, c, "Examples"); if (topic_is(topic, "distributed")) { - opt(fp, c, "worker", "./ds4 --role worker --layers 21:output --coordinator 192.168.0.181 9000 -m ds4flash.gguf"); + opt(fp, c, "worker", "./ds4 --role worker --layers 21:output --local-decode --coordinator 192.168.0.181 9000 -m ds4flash.gguf"); opt(fp, c, "coordinator", "./ds4 --role coordinator --layers 0:20 --listen 0.0.0.0 9000 -p \"Hello\" -m ds4flash.gguf"); } else if (topic_is(topic, "runtime")) { if (tool == DS4_HELP_SERVER) { @@ -451,6 +452,7 @@ static void print_examples(FILE *fp, const help_colors *c, ds4_help_tool tool, c opt(fp, c, "prefill only", "./ds4-bench --prompt-file long.txt --gen-tokens 0"); } else if (tool == DS4_HELP_EVAL || topic_is(topic, "evaluation")) { opt(fp, c, "first 10", "./ds4-eval --questions 10 --trace eval.trace"); + opt(fp, c, "distributed", "./ds4-eval --role coordinator --layers 0:21 --listen 10.77.0.1 1234 --nothink --temp 0 --trace eval.trace"); opt(fp, c, "plain", "./ds4-eval --plain --nothink --tokens 512"); } else { opt(fp, c, "chat", "./ds4"); diff --git a/speed-bench/promessi_sposi_1k.txt b/speed-bench/promessi_sposi_1k.txt new file mode 100644 index 000000000..88bfeae5a --- /dev/null +++ b/speed-bench/promessi_sposi_1k.txt @@ -0,0 +1,1000 @@ + I PROMESSI SPOSI + + + + + INTRODUZIONE + + +_L'historia si può veramente deffinire una guerra illustre contro il +Tempo, perchè togliendoli di mano gl'anni suoi prigionieri, anzi già +fatti cadaueri, li richiama in vita, li passa in rassegna, e li schiera +di nuovo in battaglia. Ma gl'illustri Campioni che in tal Arringo fanno +messe di Palme e d'Allori, rapiscono solo che le sole spoglie più +sfarzose e brillanti, imbalsamando co' loro inchiostri le Imprese de +Prencipi e Potentati, e qualificati Personaggi, e trapuntando coll'ago +finissimo dell'ingegno i fili d'oro e di seta, che formano un perpetuo +ricamo di Attioni gloriose. Però alla mia debolezza non è lecito +solleuarsi a tal'argomenti, e sublimità pericolose, con aggirarsi tra +Labirinti de' Politici maneggj, et il rimbombo de' bellici Oricalchi: +solo che hauendo hauuto notitia di fatti memorabili, se ben capitorno a +gente meccaniche, e di piccol affare, mi accingo di lasciarne memoria +a Posteri, con far di tutto schietta e genuinamente il Racconto, +ouuero sia Relatione. Nella quale si vedrà in angusto Teatro luttuose +Traggedie d'horrori, e Scene di malvaggità grandiosa, con intermezzi +d'Imprese virtuose e buontà angeliche, opposte alle operationi +diaboliche. E veramente, considerando che questi nostri climi sijno +sotto l'amparo del Re Cattolico nostro Signore, che è quel Sole che mai +tramonta, e che, sopra di essi, con riflesso Lume, qual Luna giamai +calante, risplenda l'Heroe di nobil Prosapia che_ pro tempore _ne tiene +le sue parti, e gl'Amplissimi Senatori quali Stelle fisse, e gl'altri +Spettabili Magistrati qual'erranti Pianeti spandino la luce per ogni +doue, venendo così a formare un nobilissimo Cielo, altra causale +trouar non si può del vederlo tramutato in inferno d'atti tenebrosi, +malvaggità e sevitie che dagl'huomini temerarij si vanno moltiplicando, +se non se arte e fattura diabolica, attesochè l'humana malitia per sè +sola bastar non dourebbe a resistere a tanti Heroi, che con occhij +d'Argo e braccj di Briareo, si vanno trafficando per li pubblici +emolumenti. Per locchè descriuendo questo Racconto auuenuto ne' tempi +di mia verde staggione, abbenchè la più parte delle persone che vi +rappresentano le loro parti, sijno sparite dalla Scena del Mondo, con +rendersi tributarij delle Parche, pure per degni rispetti, si tacerà +li loro nomi, cioè la parentela, et il medemo si farà de' luochi, +solo indicando li Territorij_ generaliter. _Nè alcuno dirà questa sij +imperfettione del Racconto, e defformità di questo mio rozzo Parto, +a meno questo tale Critico non sij persona affatto diggiuna della +Filosofia: che quanto agl'huomini in essa versati, ben vederanno nulla +mancare alla sostanza di detta Narratione. Imperciocchè, essendo cosa +evidente, e da verun negata non essere i nomi se non puri purissimi +accidenti...._» + +--Ma, quando io avrò durata l'eroica fatica di trascriver questa storia +da questo dilavato e graffiato autografo, e l'avrò data, come si suol +dire, alla luce, si troverà poi chi duri la fatica di leggerla?-- + +Questa riflessione dubitativa, nata nel travaglio del decifrare uno +scarabocchio che veniva dopo _accidenti_, mi fece sospender la copia, +e pensar più seriamente a quello che convenisse di fare.--Ben è vero, +dicevo tra me, scartabellando il manoscritto, ben è vero che quella +grandine di concettini e di figure non continua così alla distesa per +tutta l'opera. Il buon secentista ha voluto sul principio mettere in +mostra la sua virtù; ma poi, nel corso della narrazione, e talvolta per +lunghi tratti, lo stile cammina ben più naturale e più piano. Sì; ma +com'è dozzinale! com'è sguaiato! com'è scorretto! Idiotismi lombardi a +iosa, frasi della lingua adoperate a sproposito, grammatica arbitraria, +periodi sgangherati. E poi, qualche eleganza spagnola seminata qua e +là; e poi, ch'è peggio, ne' luoghi più terribili o più pietosi della +storia, a ogni occasione d'eccitar maraviglia, o di far pensare, a +tutti que' passi insomma che richiedono bensì un po' di rettorica, +ma rettorica discreta, fine, di buon gusto, costui non manca mai di +metterci di quella sua così fatta del proemio. E allora, accozzando, +con un'abilità mirabile, le qualità più opposte, trova la maniera di +riuscir rozzo insieme e affettato, nella stessa pagina, nello stesso +periodo, nello stesso vocabolo. Ecco qui: declamazioni ampollose, +composte a forza di solecismi pedestri, e da per tutto quella +goffaggine ambiziosa, ch'è il proprio carattere degli scritti di quel +secolo, in questo paese. In vero, non è cosa da presentare a lettori +d'oggigiorno: son troppo ammaliziati, troppo disgustati di questo +genere di stravaganze. Meno male, che il buon pensiero m'è venuto sul +principio di questo sciagurato lavoro: e me ne lavo le mani.-- + +Nell'atto però di chiudere lo scartafaccio, per riporlo, mi sapeva +male che una storia così bella dovesse rimanersi tuttavia sconosciuta; +perchè, in quanto storia, può essere che al lettore ne paia altrimenti, +ma a me era parsa bella, come dico; molto bella.--Perchè non si +potrebbe, pensai, prender la serie de' fatti da questo manoscritto, +e rifarne la dicitura?--Non essendosi presentato alcuna obiezion +ragionevole, il partito fu subito abbracciato. Ed ecco l'origine del +presente libro, esposta con un'ingenuità pari all'importanza del libro +medesimo. + +Taluni però di que' fatti, certi costumi descritti dal nostro autore, +c'eran sembrati così nuovi, così strani, per non dir peggio, che, +prima di prestargli fede, abbiam voluto interrogare altri testimoni; e +ci siam messi a frugar nelle memorie di quel tempo, per chiarirci se +veramente il mondo camminasse allora a quel modo. Una tale indagine +dissipò tutti i nostri dubbi: a ogni passo ci abbattevamo in cose +consimili, e in cose più forti: e, quello che ci parve più decisivo, +abbiam perfino ritrovati alcuni personaggi, de' quali non avendo mai +avuto notizia fuor che dal nostro manoscritto, eravamo in dubbio se +fossero realmente esistiti. E, all'occorrenza, citeremo alcuna di +quelle testimonianze, per procacciar fede alle cose, alle quali, per la +loro stranezza, il lettore sarebbe più tentato di negarla. + +Ma, rifiutando come intollerabile la dicitura del nostro autore, che +dicitura vi abbiam noi sostituita? Qui sta il punto. + +Chiunque, senza esser pregato, s'intromette a rifar l'opera altrui, +s'espone a rendere uno stretto conto della sua, e ne contrae in certo +modo l'obbligazione: è questa una regola di fatto e di diritto, alla +quale non pretendiam punto di sottrarci. Anzi, per conformarci ad essa +di buon grado, avevam proposto di dar qui minutamente ragione del +modo di scrivere da noi tenuto; e, a questo fine, siamo andati, per +tutto il tempo del lavoro, cercando d'indovinare le critiche possibili +e contingenti, con intenzione di ribatterle tutte anticipatamente. +Nè in questo sarebbe stata la difficoltà; giacchè (dobbiam dirlo a +onor del vero) non ci si presentò alla mente una critica, che non le +venisse insieme una risposta trionfante, di quelle risposte che, non +dico risolvon le questioni, ma le mutano. Spesso anche, mettendo due +critiche alle mani tra loro, le facevam battere l'una dall'altra; o, +esaminandole ben a fondo, riscontrandole attentamente, riuscivamo +a scoprire e a mostrare che, così opposte in apparenza, eran però +d'uno stesso genere, nascevan tutt'e due dal non badare ai fatti e +ai princípi su cui il giudizio doveva esser fondato; e, messele, con +loro gran sorpresa, insieme, le mandavamo insieme a spasso. Non ci +sarebbe mai stato autore che provasse così ad evidenza d'aver fatto +bene. Ma che? quando siamo stati al punto di raccapezzar tutte le dette +obiezioni e risposte, per disporle con qualche ordine, misericordia! +venivano a fare un libro. Veduta la qual cosa, abbiam messo da parte il +pensiero, per due ragioni che il lettore troverà certamente buone: la +prima, che un libro impiegato a giustificarne un altro, anzi lo stile +d'un altro, potrebbe parer cosa ridicola: la seconda, che di libri +basta uno per volta, quando non è d'avanzo. + + + + + I PROMESSI SPOSI + + + + + CAPITOLO PRIMO. + + +Quel ramo del lago di Como, che volge a mezzogiorno, tra due catene +non interrotte di monti, tutte a seni e a golfi, a seconda dello +sporgere e del rientrare di quelli, vien, quasi a un tratto, a +ristringersi, e a prender corso e figura di fiume, tra un promontorio +a destra, e un'ampia costiera dall'altra parte; e il ponte, che ivi +congiunge le due rive, par che renda ancor più sensibile all'occhio +questa trasformazione, e segni il punto in cui il lago cessa, e +l'Adda rincomincia, per ripigliar poi nome di lago dove le rive, +allontanandosi di nuovo, lascian l'acqua distendersi e rallentarsi in +nuovi golfi e in nuovi seni. La costiera, formata dal deposito di tre +grossi torrenti, scende appoggiata a due monti contigui, l'uno detto di +san Martino, l'altro, con voce lombarda, il _Resegone_, dai molti suoi +cocuzzoli in fila, che in vero lo fanno somigliare a una sega: talchè +non è chi, al primo vederlo, purchè sia di fronte, come per esempio +di su le mura di Milano che guardano a settentrione, non lo discerna +tosto, a un tal contrassegno, in quella lunga e vasta giogaia, dagli +altri monti di nome più oscuro e di forma più comune. Per un buon +pezzo, la costa sale con un pendio lento e continuo; poi si rompe in +poggi e in valloncelli, in erte e in ispianate, secondo l'ossatura de' +due monti, e il lavoro dell'acque. Il lembo estremo, tagliato dalle +foci de' torrenti, è quasi tutto ghiaia e ciottoloni; il resto, campi +e vigne, sparse di terre, di ville, di casali; in qualche parte boschi, +che si prolungano su per la montagna. Lecco, la principale di quelle +terre, e che dà nome al territorio, giace poco discosto dal ponte, alla +riva del lago, anzi viene in parte a trovarsi nel lago stesso, quando +questo ingrossa: un gran borgo al giorno d'oggi, e che s'incammina +a diventar città. Ai tempi in cui accaddero i fatti che prendiamo a +raccontare, quel borgo, già considerabile, era anche un castello, e +aveva perciò l'onore d'alloggiare un comandante, e il vantaggio di +possedere una stabile guarnigione di soldati spagnoli, che insegnavan +la modestia alle fanciulle e alle donne del paese, accarezzavan di +tempo in tempo le spalle a qualche marito, a qualche padre; e, sul +finir dell'estate, non mancavan mai di spandersi nelle vigne, per +diradar l'uve, e alleggerire a' contadini le fatiche della vendemmia. +Dall'una all'altra di quelle terre, dall'alture alla riva, da un poggio +all'altro, correvano, e corrono tuttavia, strade e stradette, più o men +ripide, o piane; ogni tanto affondate, sepolte tra due muri, donde, +alzando lo sguardo, non iscoprite che un pezzo di cielo e qualche +vetta di monte; ogni tanto elevate su terrapieni aperti: e da qui +la vista spazia per prospetti più o meno estesi, ma ricchi sempre e +sempre qualcosa nuovi, secondo che i diversi punti piglian più o meno +della vasta scena circostante, e secondo che questa o quella parte +campeggia o si scorcia, spunta o sparisce a vicenda. Dove un pezzo, +dove un altro, dove una lunga distesa di quel vasto e variato specchio +dell'acqua; di qua lago, chiuso all'estremità o piuttosto smarrito +in un gruppo, in un andirivieni di montagne, e di mano in mano più +allargato tra altri monti che si spiegano, a uno a uno, allo sguardo, +e che l'acqua riflette capovolti, co' paesetti posti sulle rive; di +là braccio di fiume, poi lago, poi fiume ancora, che va a perdersi in +lucido serpeggiamento pur tra' monti che l'accompagnano, degradando +via via, e perdendosi quasi anch'essi nell'orizzonte. Il luogo stesso +da dove contemplate que' vari spettacoli, vi fa spettacolo da ogni +parte: il monte di cui passeggiate le falde, vi svolge, al di sopra, +d'intorno, le sue cime e le balze, distinte, rilevate, mutabili quasi a +ogni passo, aprendosi e contornandosi in gioghi ciò che v'era sembrato +prima un sol giogo, e comparendo in vetta ciò che poco innanzi vi si +rappresentava sulla costa: e l'ameno, il domestico di quelle falde +tempera gradevolmente il selvaggio, e orna vie più il magnifico +dell'altre vedute. + +Per una di queste stradicciole, tornava bel bello dalla passeggiata +verso casa, sulla sera del giorno 7 novembre dell'anno 1628, don +Abbondio, curato d'una delle terre accennate di sopra: il nome di +questa, nè il casato del personaggio, non si trovan nel manoscritto, +nè a questo luogo nè altrove. Diceva tranquillamente il suo ufizio, +e talvolta, tra un salmo e l'altro, chiudeva il breviario, tenendovi +dentro, per segno, l'indice della mano destra, e, messa poi questa +nell'altra dietro la schiena, proseguiva il suo cammino, guardando a +terra, e buttando con un piede verso il muro i ciottoli che facevano +inciampo nel sentiero: poi alzava il viso, e, girati oziosamente gli +occhi all'intorno, li fissava alla parte d'un monte, dove la luce +del sole già scomparso, scappando per i fessi del monte opposto, si +dipingeva qua e là sui massi sporgenti, come a larghe e inuguali +pezze di porpora. Aperto poi di nuovo il breviario, e recitato un +altro squarcio, giunse a una voltata della stradetta, dov'era solito +d'alzar sempre gli occhi dal libro, e di guardarsi dinanzi: e così fece +anche quel giorno. Dopo la voltata, la strada correva diritta, forse +un sessanta passi, e poi si divideva in due viottole, a foggia d'un +ipsilon: quella a destra saliva verso il monte, e menava alla cura: +l'altra scendeva nella valle fino a un torrente; e da questa parte +il muro non arrivava che all'anche del passeggiero. I muri interni +delle due viottole, in vece di riunirsi ad angolo, terminavano in un +tabernacolo, sul quale eran dipinte certe figure lunghe, serpeggianti, +che finivano in punta, e che, nell'intenzion dell'artista, e agli occhi +degli abitanti del vicinato, volevan dir fiamme; e, alternate con le +fiamme, cert'altre figure da non potersi descrivere, che volevan dire +anime del purgatorio: anime e fiamme a color di mattone, sur un fondo +bigiognolo, con qualche scalcinatura qua e là. Il curato, voltata la +stradetta, e dirizzando, com'era solito, lo sguardo al tabernacolo, +vide una cosa che non s'aspettava, e che non avrebbe voluto vedere. +Due uomini stavano, l'uno dirimpetto all'altro, al confluente, per dir +così, delle due viottole: un di costoro, a cavalcioni sul muricciolo +basso, con una gamba spenzolata al di fuori, e l'altro piede posato +sul terreno della strada; il compagno, in piedi, appoggiato al muro, +con le braccia incrociate sul petto. L'abito, il portamento, e +quello che, dal luogo ov'era giunto il curato, si poteva distinguer +dell'aspetto, non lasciavan dubbio intorno alla lor condizione. Avevano +entrambi intorno al capo una reticella verde, che cadeva sull'omero +sinistro, terminata in una gran nappa, e dalla quale usciva sulla +fronte un enorme ciuffo: due lunghi mustacchi arricciati in punta: una +cintura lucida di cuoio, e a quella attaccate due pistole: un piccol +corno ripieno di polvere, cascante sul petto, come una collana: un +manico di coltellaccio che spuntava fuori d'un taschino degli ampi e +gonfi calzoni, uno spadone, con una gran guardia traforata a lamine +d'ottone, congegnate come in cifra, forbite e lucenti: a prima vista si +davano a conoscere per individui della specie de' _bravi_. + +Questa specie, ora del tutto perduta, era allora floridissima in +Lombardia, e già molto antica. Chi non ne avesse idea, ecco alcuni +squarci autentici, che potranno darne una bastante de' suoi caratteri +principali, degli sforzi fatti per ispegnerla, e della sua dura e +rigogliosa vitalità. + +Fino dall'otto aprile dell'anno 1583, l'Illustrissimo ed +Eccellentissimo signor don Carlo d'Aragon, Principe di Castelvetrano, +Duca di Terranuova, Marchese d'Avola, Conte di Burgeto, grande +Ammiraglio, e gran Contestabile di Sicilia, Governatore di Milano +e Capitan Generale di Sua Maestà Cattolica in Italia, _pienamente +informato della intollerabile miseria in che è vivuta e vive questa +Città di Milano, per cagione dei bravi e vagabondi_, pubblica un +bando contro di essi. _Dichiara e diffinisce tutti coloro essere +compresi in questo bando, e doversi ritenere bravi e vagabondi_.... +_i quali, essendo forestieri o del paese, non hanno esercizio +alcuno, od avendolo, non lo fanno_.... _ma, senza salario, o pur con +esso, s'appoggiano a qualche cavaliere o gentiluomo, officiale o +mercante_.... _per fargli spalle e favore, o veramente, come si può +presumere, per tendere insidie ad altri_.... A tutti costoro ordina +che, nel termine di giorni sei, abbiano a sgomberare il paese, intima +la galera a' renitenti, e dà a tutti gli ufiziali della giustizia +le più stranamente ampie e indefinite facoltà, per l'esecuzione +dell'ordine. Ma, nell'anno seguente, il 12 aprile, scorgendo il detto +signore, _che questa Città è tuttavia piena di detti bravi_.... +_tornati a vivere come prima vivevano, non punto mutato il costume +loro, nè scemato il numero_, dà fuori un'altra grida, ancor più +vigorosa e notabile, nella quale, tra l'altre ordinazioni, prescrive: + +_Che qualsivoglia persona, così di questa Città, come forestiera, che +per due testimonj consterà esser tenuto, e comunemente riputato per +bravo, et aver tal nome, ancorchè non si verifichi aver fatto delitto +alcuno.... per questa sola riputazione di bravo, senza altri indizj, +possa dai detti giudici e da ognuno di loro esser posto alla corda et +al tormento, per processo informativo.... et ancorchè non confessi +delitto alcuno, tuttavia sia mandato alla galea, per detto triennio, +per la sola opinione e nome di bravo, come di sopra_. Tutto ciò, e il +di più che si tralascia, perchè _Sua Eccellenza è risoluta di voler +essere obbedita da ognuno_. + +[Illustrazione: Che i due descritti di sopra stessero ivi ad aspettar +qualcheduno, era cosa troppo evidente.... (pag. 11)] + +All'udir parole d'un tanto signore, così gagliarde e sicure, e +accompagnate da tali ordini, viene una gran voglia di credere che, al +solo rimbombo di esse, tutti i bravi siano scomparsi per sempre. Ma +la testimonianza d'un signore non meno autorevole, nè meno dotato di +nomi, ci obbliga a credere tutto il contrario. È questi l'Illustrissimo +ed Eccellentissimo Signor Juan Fernandez de Velasco, Contestabile di +Castiglia, Cameriero maggiore di Sua Maestà, Duca della Città di Frias, +Conte di Haro e Castelnovo, Signore della Casa di Velasco, e di quella +delli sette Infanti di Lara, Governatore dello Stato di Milano, etc. +Il 5 giugno dell'anno 1593, pienamente informato anche lui _di quanto +danno e rovine sieno_.... _i bravi e vagabondi, e del pessimo effetto +che tal sorta di gente fa contra il ben pubblico, et in delusione +della giustizia_, intima loro di nuovo che, nel termine di giorni sei, +abbiano a sbrattare il paese, ripetendo a un dipresso le prescrizioni +e le minacce medesime del suo predecessore. Il 23 maggio poi dell'anno +1598, _informato, con non poco dispiacere dell'animo suo, che_... _ogni +dì più in questa Città e Stato va crescendo il numero di questi tali_ +(bravi e vagabondi), _nè di loro, giorno e notte, altro si sente che +ferite appostatamente date, omicidii e ruberie et ogni altra qualità di +delitti, ai quali si rendono più facili, confidati essi bravi d'essere +aiutati dai capi e fautori loro_,.... prescrive di nuovo gli stessi +rimedi, accrescendo la dose, come s'usa nelle malattie ostinate. +_Ognuno dunque_, conchiude poi, _onninamente si guardi di contravvenire +in parte alcuna alla grida presente, perchè, in luogo di provare +la clemenza di Sua Eccellenza, proverà il rigore, e l'ira sua_.... +_essendo risoluta e determinata che questa sia l'ultima e perentoria +monizione_. + +Non fu però di questo parere l'Illustrissimo ed Eccellentissimo +Signore, il Signor Don Pietro Enriquez de Acevedo, Conte di Fuentes, +Capitano, e Governatore dello Stato di Milano; non fu di questo +parere, e per buone ragioni. _Pienamente informato della miseria in +che vive questa Città e Stato per cagione del gran numero di bravi +che in esso abbonda_.... _e risoluto di totalmente estirpare seme +tanto pernizioso_, dà fuori, il 5 decembre 1600, una nuova grida piena +anch'essa di severissime comminazioni, _con fermo proponimento che, +con ogni rigore, e senza speranza di remissione, siano onninamente +eseguite_. + +Convien credere però che non ci si mettesse con tutta quella buona +voglia che sapeva impiegare nell'ordir cabale, e nel suscitar nemici al +suo gran nemico Enrico IV; giacchè, per questa parte, la storia attesta +come riuscisse ad armare contro quel re il duca di Savoia, a cui fece +perder più d'una città; come riuscisse a far congiurare il duca di +Biron, a cui fece perder la testa; ma, per ciò che riguarda quel seme +tanto pernizioso de' bravi, certo è che esso continuava a germogliare, +il 22 settembre dell'anno 1612. In quel giorno l'Illustrissimo ed +Eccellentissimo Signore, Don Giovanni de Mendozza, Marchese de la +Hynojosa, Gentiluomo, etc. Governatore, etc., pensò seriamente ad +estirparlo. A quest'effetto, spedì a Pandolfo e Marco Tullio Malatesti, +stampatori regii camerali, la solita grida, corretta ed accresciuta, +perchè la stampassero ad esterminio de' bravi. Ma questi vissero +ancora per ricevere, il 24 decembre dell'anno 1618, gli stessi e più +forti colpi dall'Illustrissimo ed Eccellentissimo Signore, il Signor +don Gomez Suarez de Figueroa, Duca di Feria, etc. Governatore, etc. +Però, non essendo essi morti neppur di quelli, l'Illustrissimo ed +Eccellentissimo Signore, il Signor Gonzalo Fernandez di Cordova, sotto +il cui governo accadde la passeggiata di don Abbondio, s'era trovato +costretto a ricorreggere e ripubblicare la solita grida contro i bravi, +il giorno 5 ottobre del 1627, cioè un anno, un mese e due giorni prima +di quel memorabile avvenimento. + +Nè fu questa l'ultima pubblicazione; ma noi delle posteriori non +crediamo dover far menzione, come di cosa che esce dal periodo della +nostra storia. Ne accenneremo soltanto una del 13 febbraio dell anno +1632, nella quale l'Illustrissimo ed Eccellentissimo Signore, _el Duque +de Feria_, per la seconda volta governatore, ci avvisa che _le maggiori +sceleraggini procedono da quelli che chiamano bravi_. Questo basta +ad assicurarci che, nel tempo di cui noi trattiamo, c'era de' bravi +tuttavia. + +Che i due descritti di sopra stessero ivi ad aspettar qualcheduno, era +cosa troppo evidente; ma quel che più dispiacque a don Abbondio fu il +dover accorgersi, per certi atti, che l'aspettato era lui. Perchè, al +suo apparire, coloro s'eran guardati in viso, alzando la testa, con +un movimento dal quale si scorgeva che tutt'e due a un tratto avevan +detto: è lui; quello che stava a cavalcioni s'era alzato, tirando la +sua gamba sulla strada; l'altro s'era staccato dal muro; e tutt'e due +gli s'avviavano incontro. Egli, tenendosi sempre il breviario aperto +dinanzi, come se leggesse, spingeva lo sguardo in su, per ispiar le +mosse di coloro; e, vedendoseli venir proprio incontro, fu assalito +a un tratto da mille pensieri. Domandò subito in fretta a sè stesso, +se, tra i bravi e lui, ci fosse qualche uscita di strada, a destra +o a sinistra; e gli sovvenne subito di no. Fece un rapido esame, se +avesse peccato contro qualche potente, contro qualche vendicativo; ma, +anche in quel turbamento, il testimonio consolante della coscienza lo +rassicurava alquanto: i bravi però s'avvicinavano, guardandolo fisso. +Mise l'indice e il medio della mano sinistra nel collare, come per +raccomodarlo; e, girando le due dita intorno al collo, volgeva intanto +la faccia all'indietro, torcendo insieme la bocca, e guardando con la +coda dell'occhio, fin dove poteva, se qualcheduno arrivasse; ma non +vide nessuno. Diede un'occhiata, al di sopra del muricciolo, ne' campi: +nessuno; un'altra più modesta sulla strada dinanzi; nessuno, fuorchè +i bravi. Che fare? tornare indietro, non era a tempo: darla a gambe, +era lo stesso che dire, inseguitemi, o peggio. Non potendo schivare il +pericolo, vi corse incontro, perchè i momenti di quell'incertezza erano +allora così penosi per lui, che non desiderava altro che d'abbreviarli. +Affrettò il passo, recitò un versetto a voce più alta, compose la +faccia a tutta quella quiete e ilarità che potè, fece ogni sforzo per +preparare un sorriso; quando si trovò a fronte dei due galantuomini, +disse mentalmente: ci siamo; e si fermò su due piedi. «Signor curato,» +disse un di que' due, piantandogli gli occhi in faccia. + +«Cosa comanda?» rispose subito don Abbondio, alzando i suoi dal libro, +che gli restò spalancato nelle mani, come sur un leggio. + +«Lei ha intenzione,» proseguì l'altro, con l'atto minaccioso e iracondo +di chi coglie un suo inferiore sull'intraprendere una ribalderia, «lei +ha intenzione di maritar domani Renzo Tramaglino e Lucia Mondella!» + +«Cioè....» rispose, con voce tremolante, don Abbondio: «cioè. Lor +signori son uomini di mondo, e sanno benissimo come vanno queste +faccende. Il povero curato non c'entra: fanno i loro pasticci tra +loro, e poi.... e poi, vengon da noi, come s'anderebbe a un banco a +riscotere: e noi.... noi siamo i servitori del comune.» + +«Or bene,» gli disse il bravo, all'orecchio, ma in tono solenne di +comando, «questo matrimonio non s'ha da fare, nè domani, nè mai.» + +«Ma, signori miei,» replicò don Abbondio, con la voce mansueta e +gentile di chi vuoi persuadere un impaziente, «ma, signori miei, si +degnino di mettersi ne' miei panni. Se la cosa dipendesse da me,... +vedon bene che a me non me ne vien nulla in tasca....» + +«Orsù,» interruppe il bravo, «se la cosa avesse a decidersi a ciarle, +lei ci metterebbe in sacco. Noi non ne sappiamo, nè vogliam saperne di +più. Uomo avvertito.... lei c'intende.» + +«Ma lor signori son troppo giusti, troppo ragionevoli....» + +«Ma,» interruppe questa volta l'altro compagnone, che non aveva parlato +fin allora, «ma il matrimonio non si farà o....» e qui una buona +bestemmia, «o chi lo farà non se ne pentirà, perchè non ne avrà tempo, +e....» un'altra bestemmia. + +«Zitto, zitto,» riprese il primo oratore, «il signor curato è un uomo +che sa il viver del mondo; e noi siam galantuomini, che non vogliam +fargli del male, purchè abbia giudizio. Signor curato, l'illustrissimo +signor don Rodrigo nostro padrone la riverisce caramente.» + +Questo nome fu, nella mente di don Abbondio, come, nel forte d'un +temporale notturno, un lampo che illumina momentaneamente e in +confuso gli oggetti, e accresce il terrore. Fece, come per istinto, un +grand'inchino, e disse: «se mi sapessero suggerire....» + +«Oh! suggerire a lei che sa di latino!» interruppe ancora il bravo, con +un riso tra lo sguaiato e il feroce. «A lei tocca. E sopra tutto, non +si lasci uscir parola su questo avviso che le abbiam dato per suo bene; +altrimenti.... ehm.... sarebbe lo stesso che fare quel tal matrimonio. +Via, che vuoi che si dica in suo nome all'illustrissimo signor don +Rodrigo?» + +«Il mio rispetto....» + +«Si spieghi meglio!» + +«....Disposto.... disposto sempre all'ubbidienza.» E, proferendo queste +parole, non sapeva nemmen lui se faceva una promessa, o un complimento. +I bravi le presero, o mostraron di prenderle nel significato più serio. + +«Benissimo, e buona notte, messere,» disse l'un d'essi, in atto di +partir col compagno. Don Abbondio, che, pochi momenti prima, avrebbe +dato un occhio per iscansarli, allora avrebbe voluto prolungar la +conversazione e le trattative. «Signori....» cominciò, chiudendo il +libro con le due mani; ma quelli, senza più dargli udienza, presero la +strada dond'era lui venuto, e s'allontanarono, cantando una canzonaccia +che non voglio trascrivere. Il povero don Abbondio rimase un momento a +bocca aperta, come incantato; poi prese quella delle due stradette che +conduceva a casa sua, mettendo innanzi a stento una gamba dopo l'altra, +che parevano aggranchiate. Come stesse di dentro, s'intenderà meglio, +quando avrem detto qualche cosa del suo naturale, e de' tempi in cui +gli era toccato di vivere. + +Don Abbondio (il lettore se n'è già avveduto) non era nato con un +cuor di leone. Ma fin da' primi suoi anni, aveva dovuto comprendere +che la peggior condizione, a que' tempi, era quella d'un animale +senza artigli e senza zanne, e che pure non si sentisse inclinazione +d'esser divorato. La forza legale non proteggeva in alcun conto +l'uomo tranquillo, inoffensivo, e che non avesse altri mezzi di far +paura altrui. Non già che mancassero leggi e pene contro le violenze +private. Le leggi anzi diluviavano; i delitti erano enumerati, +e particolareggiati, con minuta prolissità; le pene, pazzamente +esorbitanti e, se non basta, aumentabili, quasi per ogni caso, ad +arbitrio del legislatore stesso e di cento esecutori; le procedure, +studiate soltanto a liberare il giudice da ogni cosa che potesse +essergli d'impedimento a proferire una condanna: gli squarci che +abbiam riportati delle gride contro i bravi, ne sono un piccolo, ma +fedel saggio. Con tutto ciò, anzi in gran parte a cagion di ciò, +quelle gride, ripubblicate e rinforzate di governo in governo, non +servivano ad altro che ad attestare ampollosamente l'impotenza +de' loro autori; o, se producevan qualche effetto immediato, era +principalmente d'aggiunger molte vessazioni a quelle che i pacifici e +i deboli già soffrivano da' perturbatori, e d'accrescer le violenze, +e l'astuzia di questi. L'impunità era organizzata, e aveva radici che +le gride non toccavano, o non potevano smovere. Tali eran gli asili, +tali i privilegi d'alcune classi, in parte riconosciuti dalla forza +legale, in parte tollerati con astioso silenzio, o impugnati con vane +proteste, ma sostenuti in fatto e difesi da quelle classi, con attività +d'interesse, e con gelosia di puntiglio. Ora, quest'impunità minacciata +e insultata, ma non distrutta dalle gride, doveva naturalmente, a ogni +minaccia, e a ogni insulto, adoperar nuovi sforzi e nuove invenzioni, +per conservarsi. Così accadeva in effetto; e, all'apparire delle gride +dirette a comprimere i violenti, questi cercavano nella loro forza +reale i nuovi mezzi più opportuni, per continuare a far ciò che le +gride venivano a proibire. Potevan ben esse inceppare a ogni passo, +e molestare l'uomo bonario, che fosse senza forza propria e senza +protezione; perchè, col fine d'aver sotto la mano ogni uomo, per +prevenire o per punire ogni delitto, assoggettavano ogni mossa del +privato al volere arbitrario d'esecutori d'ogni genere. Ma chi, prima +di commettere il delitto, aveva prese le sue misure per ricoverarsi +a tempo in un convento, in un palazzo, dove i birri non avrebber mai +osato metter piede; chi, senz'altre precauzioni, portava una livrea +che impegnasse a difenderlo la vanità e l'interesse d'una famiglia +potente, di tutto un ceto, era libero nelle sue operazioni, e poteva +ridersi di tutto quel fracasso delle gride. Di quegli stessi ch'eran +deputati a farle eseguire, alcuni appartenevano per nascita alla +parte privilegiata, alcuni ne dipendevano per clientela; gli uni +e gli altri, per educazione, per interesse, per consuetudine, per +imitazione, ne avevano abbracciate le massime, e si sarebbero ben +guardati dall'offenderle, per amor d'un pezzo di carta attaccato sulle +cantonate. Gli uomini poi incaricati dell'esecuzione immediata, quando +fossero stati intraprendenti come eroi, ubbidienti come monaci, e +pronti a sacrificarsi come martiri, non avrebber però potuto venirne +alla fine, inferiori com'eran di numero a quelli che si trattava di +sottomettere, e con una gran probabilità d'essere abbandonati da chi, +in astratto e, per così dire, in teoria, imponeva loro di operare. Ma, +oltre di ciò, costoro eran generalmente de' più abbietti e ribaldi +soggetti del loro tempo; l'incarico loro era tenuto a vile anche da +quelli che potevano averne terrore, e il loro titolo un improperio. Era +quindi ben naturale che costoro, in vece d'arrischiare, anzi di gettar +la vita in un'impresa disperata, vendessero la loro inazione, o anche +la loro connivenza ai potenti, e si riservassero a esercitare la loro +esecrata autorità e la forza che pure avevano, in quelle occasioni +dove non c'era pericolo; nell'opprimer cioè, e nel vessare gli uomini +pacifici e senza difesa. + +L'uomo che vuole offendere, o che teme, ogni momento, d'essere offeso, +cerca naturalmente alleati e compagni. Quindi era, in que' tempi, +portata al massimo punto la tendenza degl'individui a tenersi collegati +in classi, a formarne delle nuove, e a procurare ognuno la maggior +potenza di quella a cui apparteneva. Il clero vegliava a sostenere +e ad estendere le sue immunità, la nobiltà i suoi privilegi, il +militare le sue esenzioni. I mercanti, gli artigiani erano arrolati +in maestranze e in confraternite, i giurisperiti formavano una lega, +i medici stessi una corporazione. Ognuna di queste piccole oligarchie +aveva una sua forza speciale e propria; in ognuna l'individuo trovava +il vantaggio d'impiegar per sè, a proporzione della sua autorità e +della sua destrezza, le forze riunite di molti. I più onesti si valevan +di questo vantaggio a difesa soltanto; gli astuti e i facinorosi +ne approfittavano, per condurre a termine ribalderie, alle quali +i loro mezzi personali non sarebber bastati, e per assicurarsene +l'impunità. Le forze però di queste varie leghe eran molto disuguali; +e, nelle campagne principalmente, il nobile dovizioso e violento, con +intorno uno stuolo di bravi, e una popolazione di contadini avvezzi, +per tradizione famigliare, e interessati o forzati a riguardarsi +quasi come sudditi e soldati del padrone, esercitava un potere, a +cui difficilmente nessun'altra frazione di lega avrebbe ivi potuto +resistere. + +Il nostro Abbondio, non nobile, non ricco, coraggioso ancor meno, s'era +dunque accorto, prima quasi di toccar gli anni della discrezione, +d'essere, in quella società, come un vaso di terra cotta, costretto +a viaggiare in compagnia di molti vasi di ferro. Aveva quindi, assai +di buon grado, ubbidito ai parenti, che lo vollero prete. Per dir la +verità, non aveva gran fatto pensato agli obblighi e ai nobili fini +del ministero al quale si dedicava: procacciarsi di che vivere con +qualche agio, e mettersi in una classe riverita e forte, gli eran +sembrate due ragioni più che sufficienti per una tale scelta. Ma una +classe qualunque non protegge un individuo, non lo assicura, che +fino a un certo segno: nessuna lo dispensa dal farsi un suo sistema +particolare. Don Abbondio, assorbito continuamente ne' pensieri della +propria quiete, non si curava di que' vantaggi, per ottenere i quali +facesse bisogno d'adoperarsi molto, o d'arrischiarsi un poco. Il suo +sistema consisteva principalmente nello scansar tutti i contrasti, e +nel cedere, in quelli che non poteva scansare. Neutralità disarmata in +tutte le guerre che scoppiavano intorno a lui, dalle contese, allora +frequentissime, tra il clero e le podestà laiche, tra il militare e il +civile, tra nobili e nobili, fino alle questioni tra due contadini, +nate da una parola, e decise coi pugni, o con le coltellate. Se si +trovava assolutamente costretto a prender parte tra due contendenti, +stava col più forte, sempre però alla retroguardia, e procurando di far +vedere all'altro ch'egli non gli era volontariamente nemico: pareva che +gli dicesse: ma perchè non avete saputo esser voi il più forte? ch'io +mi sarei messo dalla vostra parte. Stando alla larga da' prepotenti, +dissimulando le loro soverchierie passeggiere e capricciose, +corrispondendo con sommissioni a quelle che venissero da un' intenzione +più seria e più meditata, costringendo, a forza d'inchini e di rispetto +gioviale, anche i più burberi e sdegnosi, a fargli un sorriso, quando +gl'incontrava per la strada, il pover'uomo era riuscito a passare i +sessant'anni, senza gran burrasche. + +Non è però che non avesse anche lui il suo po' di fiele in corpo; e +quel continuo esercitar la pazienza, quel dar così spesso ragione agli +altri, que' tanti bocconi amari inghiottiti in silenzio, glielo avevano +esacerbato a segno che, se non avesse, di tanto in tanto, potuto dargli +un po' di sfogo, la sua salute n'avrebbe certamente sofferto. Ma +siccome v'eran poi finalmente al mondo, e vicino a lui, persone ch'egli +conosceva ben bene per incapaci di far male, così poteva con quelle +sfogare qualche volta il mal umore lungamente represso, e cavarsi +anche lui la voglia d'essere un po' fantastico, e di gridare a torto. +Era poi un rigido censore degli uomini che non si regolavan come lui, +quando però la censura potesse esercitarsi senza alcuno, anche lontano, +pericolo. Il battuto era almeno almeno un imprudente; l'ammazzato era +sempre stato un uomo torbido. A chi, messosi a sostener le sue ragioni +contro un potente, rimaneva col capo rotto, don Abbondio sapeva trovar +sempre qualche torto; cosa non difficile, perchè la ragione e il torto +non si dividon mai con un taglio così netto, che ogni parte abbia +soltanto dell'una o dell'altro. Sopra tutto poi, declamava contro que' +suoi confratelli che, a loro rischio, prendevan le parti d'un debole +oppresso, contro un soverchiatore potente. Questo chiamava un comprarsi +gl'impicci a contanti, un voler raddirizzar le gambe ai cani; diceva +anche severamente, ch'era un mischiarsi nelle cose profane, a danno +della dignità del sacro ministero. E contro questi predicava, sempre +però a quattrocchi, o in un piccolissimo crocchio, con tanto più di +veemenza, quanto più essi eran conosciuti per alieni dal risentirsi, +in cosa che li toccasse personalmente. Aveva poi una sua sentenza +prediletta, con la quale sigillava sempre i discorsi su queste materie: +che a un galantuomo, il qual badi a sè, e stia ne' suoi panni, non +accadon mai brutti incontri. + +Pensino ora i miei venticinque lettori che impressione dovesse fare +sull'animo del poveretto, quello che s'è raccontato. Lo spavento +di que' visacci e di quelle parolacce, la minaccia d'un signore +noto per non minacciare invano, un sistema di quieto vivere, ch'era +costato tant'anni di studio e di pazienza, sconcertato in un punto, +e un passo dal quale non si poteva veder come uscirne: tutti questi +pensieri ronzavano tumultuariamente nel capo basso di don Abbondio.--Se +Renzo si potesse mandare in pace con un bel no, via; ma vorrà delle +ragioni; e cosa ho da rispondergli, per amor del cielo? E, e, e, +anche costui è una testa: un agnello se nessun lo tocca, ma se uno +vuol contraddirgli.... ih! E poi, e poi, perduto dietro a quella +Lucia, innamorato come.... Ragazzacci, che, per non saper che fare, +s'innamorano, voglion maritarsi, e non pensano ad altro; non si fanno +carico de' travagli in che mettono un povero galantuomo. Oh povero +me! vedete se quelle due figuracce dovevan proprio piantarsi sulla +mia strada, e prenderla con me! Che c'entro io? Son io che voglio +maritarmi? Perchè non son andati piuttosto a parlare.... Oh vedete un +poco: gran destino è il mio, che le cose a proposito mi vengan sempre +in mente un momento dopo l'occasione. Se avessi pensato di suggerir +loro che andassero a portar la loro ambasciata....--Ma, a questo punto, +s'accorse che il pentirsi di non essere stato consigliere e cooperatore +dell'iniquità era cosa troppo iniqua; e rivolse tutta la stizza de' +suoi pensieri contro quell'altro che veniva così a togliergli la sua +pace. Non conosceva don Rodrigo che di vista e di fama, nè aveva mai +avuto che far con lui, altro che di toccare il petto col mento, e la +terra con la punta del suo cappello, quelle poche volte che l'aveva +incontrato per la strada. Gli era occorso di difendere, in più +d'un'occasione, la riputazione di quel signore, contro coloro che, a +bassa voce, sospirando, e alzando gli occhi al cielo, maledicevano +qualche suo fatto: aveva detto cento volte ch'era un rispettabile +cavaliere. Ma, in quel momento, gli diede in cuor suo tutti que' titoli +che non aveva mai udito applicargli da altri, senza interrompere +in fretta con un oibò. Giunto, tra il tumulto di questi pensieri, +alla porta di casa sua, ch'era in fondo del paesello, mise in fretta +nella toppa la chiave, che già teneva in mano; aprì, entrò, richiuse +diligentemente; e, ansioso di trovarsi in una compagnia fidata, chiamò +subito: «Perpetua! Perpetua!», avviandosi pure verso il salotto, +dove questa doveva esser certamente ad apparecchiar la tavola per la +cena. Era Perpetua, come ognun se n'avvede, la serva di don Abbondio: +serva affezionata e fedele, che sapeva ubbidire e comandare, secondo +l'occasione, tollerare a tempo il brontolío e le fantasticaggini del +padrone, e fargli a tempo tollerar le proprie, che divenivan di giorno +in giorno più frequenti, da che aveva passata l'età sinodale dei +quaranta, rimanendo celibe, per aver rifiutati tutti i partiti che le +si erano offerti, come diceva lei, o per non aver mai trovato un cane +che la volesse, come dicevan le sue amiche. + +«Vengo,» rispose, mettendo sul tavolino, al luogo solito, il +fiaschetto del vino prediletto di don Abbondio, e si mosse lentamente; +ma non aveva ancor toccata la soglia del salotto, ch'egli v'entrò, con +un passo così legato, con uno sguardo così adombrato, con un viso così +stravolto, che non ci sarebbero nemmen bisognati gli occhi esperti di +Perpetua, per iscoprire a prima vista che gli era accaduto qualche cosa +di straordinario davvero. + +«Misericordia! cos'ha, signor padrone?» + +«Niente, niente,» rispose don Abbondio, lasciandosi andar tutto ansante +sul suo seggiolone. + +«Come, niente? La vuol dare ad intendere a me? così brutto com'è? +Qualche gran caso è avvenuto.» + +«Oh, per amor del cielo! Quando dico niente, o è niente, o è cosa che +non posso dire.» + +«Che non può dir neppure a me? Chi si prenderà cura della sua salute? +Chi le darà un parere?...» + +«Ohimè! tacete, e non apparecchiate altro: datemi un bicchiere del mio +vino.» + +«E lei mi vorrà sostenere che non ha niente!» disse Perpetua, empiendo +il bicchiere, e tenendolo poi in mano, come se non volesse darlo che in +premio della confidenza che si faceva tanto aspettare. + +«Date qui, date qui,» disse don Abbondio, prendendole il bicchiere, con +la mano non ben ferma, e votandolo poi in fretta, come se fosse una +medicina. + +«Vuol dunque ch'io sia costretta di domandar qua e là cosa sia accaduto +al mio padrone?» disse Perpetua, ritta dinanzi a lui, con le mani +arrovesciate sui fianchi, e le gomita appuntate davanti, guardandolo +fisso, quasi volesse succhiargli dagli occhi il segreto. + +«Per amor del cielo! non fate pettegolezzi, non fate schiamazzi: ne +va.... ne va la vita!» + +«La vita!» + +«La vita.» + +«Lei sa bene, che ogni volta che m'ha detto qualche cosa sinceramente, +in confidenza, io non ho mai....» + +«Brava! come quando....» + +Perpetua s'avvide d'aver toccato un tasto falso; onde, cambiando subito +il tono, «signor padrone,» disse, con voce commossa e da commovere, +«io le sono sempre stata affezionata; e, se ora voglio sapere, è per +premura, perchè vorrei poterla soccorrere, darle un buon parere, +sollevarle l'animo....» + +Il fatto sta che don Abbondio aveva forse tanta voglia di scaricarsi +del suo doloroso segreto, quanta ne avesse Perpetua di conoscerlo: +onde, dopo aver respinti sempre più debolmente i nuovi e più incalzanti +assalti di lei, dopo averle fatto più d'una volta giurare che non +fiaterebbe, finalmente, con molte sospensioni, con molti ohimè, le +raccontò il miserabile caso. Quando si venne al nome terribile del +mandante, bisognò che Perpetua proferisse un nuovo e più solenne +giuramento; e don Abbondio, pronunziato quel nome, si rovesciò sulla +spalliera della seggiola, con un gran sospiro, alzando le mani, in atto +insieme di comando e di supplica, e dicendo: «per amor del cielo!» + +«Delle sue!» esclamò Perpetua. «Oh che birbone! oh che soverchiatore! +oh che uomo senza timor di Dio!» + +«Volete tacere? o volete rovinarmi del tutto?» + +«Oh! siam qui soli che nessun ci sente. Ma come farà, povero signor +padrone?» + +«Oh vedete,» disse don Abbondio, con voce stizzosa: «vedete che bei +pareri mi sa dar costei! Viene a domandarmi come farò, come farò; quasi +fosse lei nell'impiccio, e toccasse a me di levarnela.» + +«Ma! io l'avrei bene il mio povero parere da darle; ma poi....» + +«Ma poi, sentiamo.» + +«Il mio parere sarebbe che, siccome tutti dicono che il nostro +arcivescovo è un sant'uomo, e un uomo di polso, e che non ha paura di +nessuno, e, quando può fare star a dovere un di questi prepotenti, per +sostenere un curato, ci gongola; io direi, e dico che lei gli scrivesse +una bella lettera, per informarlo come qualmente....» + +«Volete tacere? volete tacere? Son pareri cedesti da dare a un +pover'uomo? Quando mi fosse toccata una schioppettata nella schiena, +Dio liberi! l'arcivescovo me la leverebbe?» + +«Eh! le schioppettate non si danno via come confetti: e guai se questi +cani dovessero mordere tutte le volte che abbaiano! E io ho sempre +veduto che a chi sa mostrare i denti, e farsi stimare, gli si porta +rispetto; e, appunto perchè lei non vuol mai dir la sua ragione, siam +ridotti a segno che tutti vengono, con licenza, a....» + +«Volete tacere?» + +«Io taccio subito; ma è però certo che, quando il mondo s'accorge che +uno, sempre, in ogni incontro, è pronto a calar le....» + +«Volete tacere? È tempo ora di dir codeste baggianate?» + +«Basta: ci penserà questa notte; ma intanto non cominci a farsi male da +sè, a rovinarsi la salute; mangi un boccone.» + +«Ci penserò io,» rispose, brontolando, don Abbondio: «sicuro; io ci +penserò, io ci ho da pensare.» E s'alzò, continuando: «non voglio +prender niente; niente: ho altra voglia: lo so anch'io che tocca a +pensarci a me. Ma! la doveva accader per l'appunto a me.» + +«Mandi almen giù quest'altro gocciolo,» disse Perpetua, mescendo. «Lei +sa che questo le rimette sempre lo stomaco.» + +«Eh! ci vuoi altro, ci vuoi altro, ci vuoi altro.» + +Così dicendo, prese il lume, e, brontolando sempre: «una piccola +bagattella! a un galantuomo par mio! e domani com'andrà?» e altre +simili lamentazioni, s'avviò per salire in camera. Giunto su la soglia, +si voltò indietro verso Perpetua, mise il dito sulla bocca, disse, con +tono lento e solenne: «per amor del cielo!» e disparve. + + + + + CAPITOLO II. + + +Si racconta che il principe di Condé dormi profondamente la notte +avanti la giornata di Rocroi: ma, in primo luogo, era molto affaticato; +secondariamente aveva già date tutte le disposizioni necessarie, +e stabilito ciò che dovesse fare, la mattina. Don Abbondio invece +non sapeva altro ancora se non che l'indomani sarebbe giorno di +battaglia; quindi una gran parte della notte fu spesa in consulte +angosciose. Non far caso dell'intimazione ribalda, nè delle minacce, +e fare il matrimonio, era un partito, che non volle neppur mettere in +deliberazione. Confidare a Renzo l'occorrente, e cercar con lui qualche +mezzo.... Dio liberi! «Non si lasci scappar parola.... altrimenti.... +_ehm!_» aveva detto un di que' bravi; e, al sentirsi rimbombar +quell'_ehm!_ nella mente, don Abbondio, non che pensare a trasgredire +una tal legge, si pentiva anche dell'aver ciarlato con Perpetua. +Fuggire? Dove? E poi! Quant'impicci, e quanti conti da rendere! A +ogni partito che rifiutava, il pover'uomo si rivoltava nel letto. +Quello che, per ogni verso, gli parve il meglio o il men male, fu di +guadagnar tempo, menando Renzo per le lunghe. Si rammentò a proposito, +che mancavan pochi giorni al tempo proibito per le nozze;--e, se posso +tenere a bada, per questi pochi giorni, quel ragazzone, ho poi due +mesi di respiro; e, in due mesi, può nascer di gran cose.--Ruminò +pretesti da metter in campo; e, benchè gli paressero un po' leggieri, +pur s'andava rassicurando col pensiero che la sua autorità gli avrebbe +fatti parer di giusto peso, e che la sua antica esperienza gli darebbe +gran vantaggio sur un giovanotto ignorante.--Vedremo,--diceva tra +sè:--egli pensa alla morosa; ma io penso alla pelle: il più interessato +son io, lasciando stare che sono il più accorto. Figliuol caro, se tu +ti senti il bruciore addosso, non so che dire; ma io non voglio andarne +di mezzo.--Fermato così un poco l'animo a una deliberazione, potè +finalmente chiuder occhio: ma che sonno! che sogni! Bravi, don Rodrigo, +Renzo, viottole, rupi, fughe, inseguimenti, grida, schioppettate. + +Il primo svegliarsi, dopo una sciagura, e in un impiccio, è un momento +molto amaro. La mente, appena risentita, ricorre all'idee abituali +della vita tranquilla antecedente; ma il pensiero del nuovo stato di +cose le si affaccia subito sgarbatamente; e il dispiacere ne è più vivo +in quel paragone istantaneo. Assaporato dolorosamente questo momento, +don Abbondio ricapitolò subito i suoi disegni della notte, si confermò +in essi, gli ordinò meglio, s'alzò, e stette aspettando Renzo con +timore e, ad un tempo, con impazienza. + +Lorenzo o, come dicevan tutti, Renzo non si fece molto aspettare. +Appena gli parve ora di poter, senza indiscrezione, presentarsi al +curato, v'andò, con la lieta furia d'un uomo di vent'anni, che deve in +quel giorno sposare quella che ama. Era, fin dall'adolescenza, rimasto +privo de' parenti, ed esercitava la professione di filatore di seta, +ereditaria, per dir così, nella sua famiglia; professione, negli anni +indietro, assai lucrosa; allora già in decadenza, ma non però a segno +che un abile operaio non potesse cavarne di che vivere onestamente. Il +lavoro andava di giorno in giorno scemando; ma l'emigrazione continua +de' lavoranti, attirati negli stati vicini da promesse, da privilegi +e da grosse paghe, faceva sì che non ne mancasse ancora a quelli che +rimanevano in paese. Oltre di questo, possedeva Renzo un poderetto che +faceva lavorare e lavorava egli stesso, quando il filatoio stava fermo; +di modo che, per la sua condizione, poteva dirsi agiato. E quantunque +quell'annata fosse ancor più scarsa delle antecedenti, e già si +cominciasse a provare una vera carestia, pure il nostro giovine, che, +da quando aveva messi gli occhi addosso a Lucia, era divenuto massaio, +si trovava provvisto bastantemente, e non aveva a contrastar con la +fame. Comparve davanti a don Abbondio, in gran gala, con penne di vario +colore al cappello, col suo pugnale del manico bello, nel taschino de' +calzoni, con una cert'aria di festa e nello stesso tempo di bravería, +comune allora anche agli uomini più quieti. L'accoglimento incerto +e misterioso di don Abbondio fece un contrapposto singolare ai modi +gioviali e risoluti del giovinotto. + +--Che abbia qualche pensiero per la testa,--argomentò Renzo tra sè, poi +disse: «son venuto, signor curato, per sapere a che ora le comoda che +ci troviamo in chiesa.» + +«Di che giorno volete parlare?» + +«Come, di che giorno? non si ricorda che s'è fissato per oggi?» + +«Oggi?» replicò don Abbondio, come se ne sentisse parlare per la prima +volta. «Oggi, oggi.... abbiate pazienza, ma oggi non posso.» + +«Oggi non può! Cos'è nato?» + +«Prima di tutto, non mi sento bene, vedete.» + +«Mi dispiace; ma quello che ha da fare è cosa di così poco tempo, e di +così poca fatica....» + +«E poi, e poi, e poi....» + +«E poi che cosa?» + +«E poi c'è degli imbrogli.» + +«Degl'imbrogli? Che imbrogli ci può essere?» + +«Bisognerebbe trovarsi nei nostri piedi, per conoscer quanti impicci +nascono in queste materie, quanti conti s'ha da rendere. Io son +troppo dolce di cuore, non penso che a levar di mezzo gli ostacoli, a +facilitar tutto, a far le cose secondo il piacere altrui, e trascuro il +mio dovere; e poi mi toccan de' rimproveri, e peggio.» + +«Ma, col nome del cielo, non mi tenga così sulla corda, e mi dica +chiaro e netto cosa c'è.» + +«Sapete voi quante e quante formalità ci vogliono per fare un +matrimonio in regola?» + +«Bisogna ben ch'io ne sappia qualche cosa,» disse Renzo, cominciando ad +alterarsi, «poichè me ne ha già rotta bastantemente la testa, questi +giorni addietro. Ma ora non s'è sbrigato ogni cosa? non s'è fatto tutto +ciò che s'aveva a fare?» + +«Tutto, tutto, pare a voi: perchè, abbiate pazienza, la bestia son io, +che trascuro il mio dovere, per non far penare la gente. Ma ora.... +basta, so quel che dico. Noi poveri curati siamo tra l'ancudine e +il martello: voi impaziente; vi compatisco, povero giovine; e i +superiori.... basta, non si può dir tutto. E noi siam quelli che ne +andiam di mezzo.» + +«Ma mi spieghi una volta cos'è quest'altra formalità che s'ha a fare, +come dice; e sarà subito fatta.» + +«Sapete voi quanti siano gl'impedimenti dirimenti?» + +«Che vuol ch'io sappia d'impedimenti?» + +«_Error_, _conditio_, _votum_, _cognatio_, _crimen_, _Cultus +disparitas_, _vis_, _ordo_, _ligamen_, _honestas_, _Si sis affinis_,...» + +cominciava don Abbondio, contando sulla punta delle dita. + +«Si piglia gioco di me?» interruppe il giovine. «Che vuol ch'io faccia +del suo _latinorum_?» + +«Dunque, se non sapete le cose, abbiate pazienza, e rimettetevi a chi +le sa.» + +«Orsù!...» + +«Via, caro Renzo, non andate in collera, che son pronto a fare.... +tutto quello che dipende da me. Io, io vorrei vedervi contento; vi +voglio bene io. Eh!... quando penso che stavate così bene; cosa vi +mancava? V'è saltato il grillo di maritarvi....» + +«Che discorsi son questi, signor mio?» proruppe Renzo, con un volto tra +l'attonito e l'adirato. + +«Dico per dire, abbiate pazienza, dico per dire. Vorrei vedervi +contento.» + +[Illustrazione: RENZO (pag. 22)] + +«In somma....» + +«In somma, figliuol caro, io non ci ho colpa; la legge non l'ho fatta +io. E, prima di conchiudere un matrimonio, noi siam proprio obbligati +a far molte e molte ricerche, per assicurarci che non ci siano +impedimenti.» + +«Ma via, mi dica una volta che impedimento è sopravvenuto?» + +«Abbiate pazienza, non son cose da potersi decifrare così su due piedi. +Non ci sarà niente, così spero; ma, non ostante, queste ricerche noi +le dobbiam fare. Il testo è chiaro e lampante: _antequam matrimonium +denunciet_....» + +«Le ho detto che non voglio latino.» + +«Ma bisogna pur che vi spieghi....» + +«Ma non le ha già fatte queste ricerche?» + +«Non le ho fatte tutte, come avrei dovuto, vi dico.» + +«Perchè non le ha fatte a tempo? perchè dirmi che tutto era finito? +perchè aspettare....» + +«Ecco! mi rimproverate la mia troppa bontà. Ho facilitato ogni cosa per +servirvi più presto: ma.... ma ora mi son venute.... basta, so io.» + +«E che vorrebbe ch'io facessi?» + +«Che aveste pazienza per qualche giorno. Figliuol caro, qualche giorno +non è poi l'eternità: abbiate pazienza.» + +«Per quanto?» + +--Siamo a buon porto,--pensò tra sè don Abbondio; e, con un fare più +manieroso che mai, «via,» disse: «in quindici giorni cercherò,... +procurerò....» + +«Quindici giorni! oh questa sì ch'è nuova! S'è fatto tutto ciò che +ha voluto lei; s'è fissato il giorno; il giorno arriva; e ora lei mi +viene a dire che aspetti quindici giorni! Quindici....» riprese poi, +con voce più alta e stizzosa, stendendo il braccio e battendo il pugno +nell'aria; e chi sa qual diavoleria avrebbe attaccata a quel numero, se +don Abbondio non l'avesse interrotto, prendendogli l'altra mano, con +un'amorevolezza timida e premurosa: «via, via, non v'alterate, per amor +del cielo. Vedrò, cercherò se, in una settimana....» + +«E a Lucia che devo dire?» + +«Ch'è stato un mio sbaglio.» + +«E i discorsi del mondo?» + +«Dite pure a tutti, che ho sbagliato io, per troppa furia, per troppo +buon cuore: gettate tutta la colpa addosso a me. Posso parlar meglio? +via, per una settimana.» + +«E poi, non ci sarà più altri impedimenti?» + diff --git a/tests/issue304_phase5_eval_matrix.py b/tests/issue304_phase5_eval_matrix.py new file mode 100755 index 000000000..45d47c2e8 --- /dev/null +++ b/tests/issue304_phase5_eval_matrix.py @@ -0,0 +1,652 @@ +#!/usr/bin/env python3 + +import argparse +import os +import pathlib +import re +import shlex +import signal +import socket +import subprocess +import sys +import time + + +ROOT = pathlib.Path(__file__).resolve().parents[1] +RAW_DIR = ROOT / "artifacts" / "issue-304" / "ds4-eval" / "raw" +SUMMARY_PATH = ROOT / "artifacts" / "issue-304" / "ds4-eval-matrix.md" +DEFAULT_LOCAL_MODEL = "./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf" +DEFAULT_REMOTE_MODEL = "/home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf" +REMOTE_HOST = "dgx-direct" +REMOTE_DIR = "~/ds4" +SSH_OPTS = [ + "-o", "IPQoS=none", + "-o", "ControlMaster=no", + "-o", "ControlPath=none", +] + + +def run(cmd, *, cwd=ROOT, env=None, check=True): + proc = subprocess.run(cmd, cwd=cwd, env=env, text=True, capture_output=True) + if check and proc.returncode != 0: + raise RuntimeError(f"command failed ({proc.returncode}): {' '.join(cmd)}\n{proc.stderr}") + return proc + + +def run_shell(command, *, cwd=ROOT, check=True): + proc = subprocess.run( + command, + cwd=cwd, + text=True, + capture_output=True, + shell=True, + executable="/bin/bash", + ) + if check and proc.returncode != 0: + raise RuntimeError(f"command failed ({proc.returncode}): {command}\n{proc.stderr}") + return proc + + +def ssh(command, *, check=True): + ssh_prefix = shlex_join(["ssh", *SSH_OPTS, REMOTE_HOST]) + return run_shell(f"{ssh_prefix} {shlex.quote(command)}", check=check) + + +def scp(src, dst, *, check=True): + scp_prefix = shlex_join(["scp", *SSH_OPTS]) + return run_shell(f"{scp_prefix} {shlex.quote(src)} {shlex.quote(dst)}", check=check) + + +def shlex_join(parts): + return " ".join(shlex.quote(p) for p in parts) + + +def ensure_dirs(): + RAW_DIR.mkdir(parents=True, exist_ok=True) + + +def local_ip_for(remote_host): + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: + sock.connect((remote_host, 80)) + return sock.getsockname()[0] + + +def remote_ipv4(): + cmd = ( + "python3 -c \"import socket; " + "ips=[i[4][0] for i in socket.getaddrinfo(socket.gethostname(), None, socket.AF_INET, socket.SOCK_STREAM) " + "if not i[4][0].startswith('127.')]; " + "print(ips[0] if ips else '')\"" + ) + out = ssh(cmd).stdout.strip() + if not out: + raise RuntimeError("failed to determine dgx-direct IPv4") + return out.splitlines()[-1].strip() + + +def rsync_remote(): + cmd = [ + "rsync", "-az", "--delete", + "--exclude=.git/", + "--exclude=gguf/", + "--exclude=artifacts/issue-304/phase35/raw/", + "--exclude=artifacts/issue-304/ds4-eval/raw/", + "--exclude=*.o", + "--exclude=ds4", + "--exclude=ds4-*", + "./", f"{REMOTE_HOST}:{REMOTE_DIR}/", + ] + run(cmd) + + +def build_local(): + run(["make", "ds4", "ds4-eval"]) + + +def build_remote(): + ssh(f"cd {REMOTE_DIR} && make ds4 ds4-eval") + + +def stop_remote_worker(): + script = """ + pkill -9 ds4 >/dev/null 2>&1 || true + for i in $(seq 1 30); do + if ! pgrep -x ds4 >/dev/null 2>&1; then + exit 0 + fi + sleep 1 + done + pgrep -a -x ds4 >&2 || true + exit 1 + """ + ssh(f"bash -lc {shlex.quote(script)}", check=False) + + +def start_remote_worker(model_path, coordinator_ip, port, log_path, ctx, *, local_decode): + cmd = ( + "pkill -9 ds4 >/dev/null 2>&1 || true; " + f"sh -lc 'cd {REMOTE_DIR} && " + f"export DS4_DISABLE_STARTUP_MEMORY_GUARD=1; " + f"export DS4_LOCK_FILE=/tmp/ds4-phase5-worker-{port}.lock; " + f"nohup ./ds4 -m {shlex.quote(model_path)} --ctx {ctx} " + f"--role worker --layers 22:output " + f"{'--local-decode ' if local_decode else ''}" + f"--coordinator {shlex.quote(coordinator_ip)} {port} " + f">{shlex.quote(log_path)} 2>&1 < /dev/null &'" + ) + ssh(cmd) + + +def wait_remote_worker_ready(log_path, timeout_sec=600): + script = f""" + for i in $(seq 1 {timeout_sec}); do + if grep -q 'distributed worker: layers 22:output' {shlex.quote(log_path)}; then + exit 0 + fi + if grep -q 'startup memory guard rejected\\|refusing to start\\|failed to map\\|abort' {shlex.quote(log_path)}; then + tail -n 80 {shlex.quote(log_path)} + exit 1 + fi + sleep 1 + done + tail -n 80 {shlex.quote(log_path)} + exit 1 + """ + proc = ssh(f"bash -lc {shlex.quote(script)}", check=False) + if proc.returncode != 0: + raise RuntimeError(f"remote worker did not become ready:\n{proc.stdout}{proc.stderr}") + + +def start_local_worker(model_path, coordinator_ip, port, log_path, ctx, *, local_decode): + logf = open(log_path, "w", encoding="utf-8") + env = os.environ.copy() + env["DS4_LOCK_FILE"] = f"/tmp/ds4-phase5-worker-{port}.lock" + cmd = [ + "./ds4", + "-m", model_path, + "--ctx", str(ctx), + "--role", "worker", + "--layers", "22:output", + ] + if local_decode: + cmd.append("--local-decode") + cmd += ["--coordinator", coordinator_ip, str(port)] + proc = subprocess.Popen( + cmd, + cwd=ROOT, + env=env, + stdout=logf, + stderr=subprocess.STDOUT, + text=True, + start_new_session=True, + ) + return proc, logf + + +def wait_local_worker_ready(proc, log_path, timeout_sec=180): + deadline = time.time() + timeout_sec + needle = "distributed worker: layers 22:output" + while time.time() < deadline: + if proc.poll() is not None: + break + if os.path.exists(log_path): + with open(log_path, "r", encoding="utf-8", errors="replace") as fh: + text = fh.read() + if needle in text: + return + if ("refusing to start" in text or + "failed to map model views" in text or + "abort" in text): + raise RuntimeError(f"local worker failed to become ready:\n{text[-4000:]}") + time.sleep(1) + tail = "" + if os.path.exists(log_path): + with open(log_path, "r", encoding="utf-8", errors="replace") as fh: + tail = fh.read()[-4000:] + raise RuntimeError(f"local worker did not become ready:\n{tail}") + + +def stop_local_worker(proc, logf): + if proc is not None and proc.poll() is None: + try: + os.killpg(proc.pid, signal.SIGTERM) + proc.wait(timeout=5) + except Exception: + try: + os.killpg(proc.pid, signal.SIGKILL) + except Exception: + pass + if logf is not None: + logf.close() + + +def eval_args(model_path, mode_flag, questions, tokens, trace_path, *, quality): + args = [ + "env", + f"DS4_LOCK_FILE=/tmp/ds4-phase5-eval-{abs(hash(trace_path)) & 0xffffffff:x}.lock", + "./ds4-eval", + "-m", model_path, + "--ctx", "16384", + "--plain", + "--temp", "0", + "--seed", "1", + mode_flag, + "--trace", trace_path, + ] + if quality: + args.append("--quality") + if tokens and tokens > 0: + args += ["--tokens", str(tokens)] + if questions > 0: + args += ["--questions", str(questions)] + return args + + +def distributed_args(base_args, listen_host, port): + return base_args + [ + "--role", "coordinator", + "--layers", "0:21", + "--listen", listen_host, str(port), + ] + + +def parse_trace(path): + header = {} + summary = {} + prompt_total = 0 + gen_total = 0 + prefill_total = 0.0 + decode_total = 0.0 + case_count = 0 + in_summary = False + with open(path, "r", encoding="utf-8") as fh: + for raw_line in fh: + line = raw_line.rstrip("\n") + if line.startswith("===== SUMMARY ====="): + in_summary = True + continue + if line.startswith("===== CASE "): + case_count += 1 + continue + if not line or ":" not in line: + continue + key, value = line.split(":", 1) + value = value.strip() + if in_summary: + summary[key.strip()] = value + else: + if key == "prompt_tokens": + prompt_total += int(value) + elif key == "generated_tokens": + gen_total += int(value) + elif key == "prefill_sec": + prefill_total += float(value) + elif key == "decode_sec": + decode_total += float(value) + elif key not in header: + header[key.strip()] = value + return { + "header": header, + "summary": summary, + "prompt_total": prompt_total, + "gen_total": gen_total, + "prefill_total": prefill_total, + "decode_total": decode_total, + "case_count": case_count, + } + + +def read_trace_text(path): + with open(path, "r", encoding="utf-8") as fh: + return fh.read() + + +def extract_trace_header(text): + marker = "===== CASE " + idx = text.find(marker) + return text if idx < 0 else text[:idx] + + +def extract_trace_cases(text): + matches = list(re.finditer(r"^===== CASE .*?^MODEL_OUTPUT_END\n\n?", text, flags=re.M | re.S)) + return [m.group(0) for m in matches] + + +def case_sequence_list(questions): + if questions <= 0: + raise RuntimeError("fresh-per-case mode requires an explicit positive --questions value") + return list(range(1, questions + 1)) + + +def combine_trace_files(paths, out_path): + if not paths: + raise RuntimeError("no per-case traces to combine") + combined = [] + total_passed = 0 + total_failed = 0 + total_skipped = 0 + runtime_sec = 0.0 + local_decode_any = False + header_written = False + for path in paths: + text = read_trace_text(path) + parsed = parse_trace(path) + if not header_written: + combined.append(extract_trace_header(text)) + header_written = True + combined.extend(extract_trace_cases(text)) + summary = parsed["summary"] + total_passed += int(summary.get("passed", "0")) + total_failed += int(summary.get("failed", "0")) + total_skipped += int(summary.get("skipped", "0")) + runtime_sec += float(summary.get("runtime_sec", "0") or 0.0) + if summary.get("local_decode_active_any_case", "no") == "yes": + local_decode_any = True + total = total_passed + total_failed + total_skipped + combined.append( + "===== SUMMARY =====\n" + f"passed: {total_passed}\n" + f"failed: {total_failed}\n" + f"total: {total}\n" + f"skipped: {total_skipped}\n" + f"runtime_sec: {runtime_sec:.3f}\n" + f"local_decode_active_any_case: {'yes' if local_decode_any else 'no'}\n" + ) + out_path.write_text("".join(combined), encoding="utf-8") + + +def render_summary(date_str, local_model, remote_model, questions, results): + lines = [ + "# Phase 5 `ds4-eval` Matrix", + "", + f"- Date: `{date_str}`", + f"- Questions: `{questions if questions > 0 else 92}`", + f"- Local model: `{local_model}`", + f"- Remote model: `{remote_model}`", + f"- Remote host: `{REMOTE_HOST}`", + "", + "| Cell | Score | Runtime (s) | Prompt toks | Gen toks | Prefill (s) | Decode (s) | Backend | Route | Hops | Output | Local decode | Trace |", + "| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- | ---: | --- | --- | --- |", + ] + for name, trace_path, parsed in results: + header = parsed["header"] + summary = parsed["summary"] + score = f'{summary.get("passed", "?")}/{summary.get("total", "?")}' + if summary.get("failed", "0") != "0": + score += f' fail={summary.get("failed")}' + if summary.get("skipped", "0") != "0": + score += f' skip={summary.get("skipped")}' + local_decode = "expected=" + header.get("local_decode_expected", "no") + local_decode += ", active=" + summary.get("local_decode_active_any_case", + header.get("local_decode_active", "no")) + lines.append( + f"| `{name}` | {score} | {summary.get('runtime_sec', '?')} | " + f"{parsed['prompt_total']} | {parsed['gen_total']} | " + f"{parsed['prefill_total']:.3f} | {parsed['decode_total']:.3f} | " + f"`{header.get('backend', '?')}` | `{header.get('route_summary', '?')}` | " + f"{header.get('route_hops', '?')} | `{header.get('output_owner', '?')}` | " + f"`{local_decode}` | [trace]({trace_path}) |" + ) + return "\n".join(lines) + "\n" + + +def run_local_eval(args): + return run(args, check=False) + + +def run_remote_eval(args): + cmd = f"cd {REMOTE_DIR} && {shlex_join(args)}" + return ssh(cmd, check=False) + + +def run_cell_local(args, *, trace_path, fresh_per_case, questions): + if not fresh_per_case: + return run_local_eval(args) + case_traces = [] + rc = 0 + for case_id in case_sequence_list(questions): + case_trace = pathlib.Path(f"{trace_path}.case{case_id}") + case_trace.unlink(missing_ok=True) + case_args = list(args) + case_args += ["--case-sequence", str(case_id), "--questions", str(questions)] + case_args[case_args.index("--trace") + 1] = str(case_trace) + proc = run_local_eval(case_args) + if proc.returncode not in (0, 1): + return proc + if proc.returncode != 0: + rc = proc.returncode + case_traces.append(case_trace) + combine_trace_files(case_traces, pathlib.Path(trace_path)) + for case_trace in case_traces: + case_trace.unlink(missing_ok=True) + return subprocess.CompletedProcess(args, rc, "", "") + + +def run_cell_remote(args, *, trace_path, remote_trace, fresh_per_case, questions): + if not fresh_per_case: + proc = run_remote_eval(args) + if proc.returncode in (0, 1): + scp(f"{REMOTE_HOST}:{remote_trace}", str(trace_path)) + return proc + case_traces = [] + rc = 0 + for case_id in case_sequence_list(questions): + local_case_trace = pathlib.Path(f"{trace_path}.case{case_id}") + remote_case_trace = f"{remote_trace}.case{case_id}" + local_case_trace.unlink(missing_ok=True) + ssh(f"rm -f {shlex.quote(remote_case_trace)}", check=False) + case_args = list(args) + case_args += ["--case-sequence", str(case_id), "--questions", str(questions)] + case_args[case_args.index("--trace") + 1] = remote_case_trace + proc = run_remote_eval(case_args) + if proc.returncode not in (0, 1): + return proc + if proc.returncode != 0: + rc = proc.returncode + scp(f"{REMOTE_HOST}:{remote_case_trace}", str(local_case_trace)) + case_traces.append(local_case_trace) + combine_trace_files(case_traces, pathlib.Path(trace_path)) + for case_trace in case_traces: + case_trace.unlink(missing_ok=True) + return subprocess.CompletedProcess(args, rc, "", "") + + +def case_args(args, *, case_id, questions, trace_path): + one = list(args) + one += ["--case-sequence", str(case_id), "--questions", str(questions)] + one[one.index("--trace") + 1] = str(trace_path) + return one + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--local-model", default=DEFAULT_LOCAL_MODEL) + parser.add_argument("--remote-model", default=DEFAULT_REMOTE_MODEL) + parser.add_argument("--questions", type=int, default=92) + parser.add_argument("--tokens", type=int, default=0, + help="Override ds4-eval --tokens. 0 keeps the evaluator default.") + parser.add_argument("--modes", choices=["think", "nothink", "both"], default="both") + parser.add_argument("--quality", action="store_true") + parser.add_argument("--fresh-per-case", action="store_true") + parser.add_argument("--skip-sync", action="store_true") + parser.add_argument("--skip-build", action="store_true") + parser.add_argument("--port-base", type=int, default=1234) + args = parser.parse_args() + + ensure_dirs() + date_str = time.strftime("%Y-%m-%d") + + if not args.skip_sync: + rsync_remote() + if not args.skip_build: + build_local() + build_remote() + + local_ip = local_ip_for("10.77.0.2") + remote_ip = remote_ipv4() + + results = [] + + mode_specs = [] + if args.modes in ("think", "both"): + mode_specs.append(("think", "--think")) + if args.modes in ("nothink", "both"): + mode_specs.append(("nothink", "--nothink")) + + cells = [] + route_specs = [ + ("local-metal", "local_metal", "local"), + ("local-cuda", "local_cuda", "remote_local"), + ("metal-to-cuda-localdecode", "metal_to_cuda_localdecode", "distributed_local_localdecode"), + ("cuda-to-metal-localdecode", "cuda_to_metal_localdecode", "distributed_remote_localdecode"), + ("metal-to-cuda-full", "metal_to_cuda_full", "distributed_local_full"), + ("cuda-to-metal-full", "cuda_to_metal_full", "distributed_remote_full"), + ] + for route_name, route_label, kind in route_specs: + for mode_name, mode_flag in mode_specs: + cells.append((f"{route_name}-{mode_name}", route_label, mode_flag, kind)) + + remote_log = "/tmp/ds4-eval-phase5-worker.log" + for index, (name, _route_label, mode_flag, kind) in enumerate(cells): + port = args.port_base + index + trace_path = RAW_DIR / f"{date_str}-{name}.trace" + remote_trace = f"/tmp/{date_str}-{name}.trace" + local_worker = None + local_worker_log = None + try: + trace_path.unlink(missing_ok=True) + if kind == "local": + proc = run_cell_local( + eval_args(args.local_model, mode_flag, args.questions, + args.tokens, str(trace_path), quality=args.quality), + trace_path=str(trace_path), + fresh_per_case=args.fresh_per_case, + questions=args.questions, + ) + elif kind == "remote_local": + proc = run_cell_remote( + eval_args(args.remote_model, mode_flag, args.questions, + args.tokens, remote_trace, quality=args.quality), + trace_path=str(trace_path), + remote_trace=remote_trace, + fresh_per_case=args.fresh_per_case, + questions=args.questions, + ) + elif kind in ("distributed_local_localdecode", "distributed_local_full"): + base_args = distributed_args( + eval_args(args.local_model, mode_flag, args.questions, args.tokens, + str(trace_path), quality=args.quality), + local_ip, + port, + ) + if args.fresh_per_case: + case_traces = [] + rc = 0 + for case_id in case_sequence_list(args.questions): + case_trace = pathlib.Path(f"{trace_path}.case{case_id}") + case_trace.unlink(missing_ok=True) + start_remote_worker(args.remote_model, local_ip, port, remote_log, 16384, + local_decode=(kind == "distributed_local_localdecode")) + try: + wait_remote_worker_ready(remote_log) + proc = run_local_eval( + case_args(base_args, + case_id=case_id, + questions=args.questions, + trace_path=case_trace) + ) + finally: + stop_remote_worker() + if proc.returncode not in (0, 1): + raise RuntimeError(proc.stderr or proc.stdout or f"{name} failed") + if proc.returncode != 0: + rc = proc.returncode + case_traces.append(case_trace) + combine_trace_files(case_traces, pathlib.Path(trace_path)) + for case_trace in case_traces: + case_trace.unlink(missing_ok=True) + proc = subprocess.CompletedProcess(base_args, rc, "", "") + else: + start_remote_worker(args.remote_model, local_ip, port, remote_log, 16384, + local_decode=(kind == "distributed_local_localdecode")) + proc = run_cell_local( + base_args, + trace_path=str(trace_path), + fresh_per_case=False, + questions=args.questions, + ) + else: + base_args = distributed_args( + eval_args(args.remote_model, mode_flag, args.questions, args.tokens, + remote_trace, quality=args.quality), + remote_ip, + port, + ) + local_worker_log_path = RAW_DIR / f"{date_str}-{name}.worker.log" + if args.fresh_per_case: + case_traces = [] + rc = 0 + for case_id in case_sequence_list(args.questions): + local_case_trace = pathlib.Path(f"{trace_path}.case{case_id}") + remote_case_trace = f"{remote_trace}.case{case_id}" + local_case_trace.unlink(missing_ok=True) + ssh(f"rm -f {shlex.quote(remote_case_trace)}", check=False) + local_worker, local_worker_log = start_local_worker( + args.local_model, remote_ip, port, + str(local_worker_log_path), 16384, + local_decode=(kind == "distributed_remote_localdecode") + ) + try: + wait_local_worker_ready(local_worker, str(local_worker_log_path)) + proc = run_remote_eval( + case_args(base_args, + case_id=case_id, + questions=args.questions, + trace_path=remote_case_trace) + ) + finally: + stop_local_worker(local_worker, local_worker_log) + local_worker = None + local_worker_log = None + if proc.returncode not in (0, 1): + raise RuntimeError(proc.stderr or proc.stdout or f"{name} failed") + if proc.returncode != 0: + rc = proc.returncode + scp(f"{REMOTE_HOST}:{remote_case_trace}", str(local_case_trace)) + case_traces.append(local_case_trace) + combine_trace_files(case_traces, pathlib.Path(trace_path)) + for case_trace in case_traces: + case_trace.unlink(missing_ok=True) + proc = subprocess.CompletedProcess(base_args, rc, "", "") + else: + local_worker, local_worker_log = start_local_worker( + args.local_model, remote_ip, port, str(local_worker_log_path), 16384, + local_decode=(kind == "distributed_remote_localdecode") + ) + proc = run_cell_remote( + base_args, + trace_path=str(trace_path), + remote_trace=remote_trace, + fresh_per_case=False, + questions=args.questions, + ) + + if proc.returncode not in (0, 1): + raise RuntimeError(proc.stderr or proc.stdout or f"{name} failed") + parsed = parse_trace(trace_path) + results.append((name, trace_path.relative_to(ROOT).as_posix(), parsed)) + finally: + stop_remote_worker() + stop_local_worker(local_worker, local_worker_log) + + summary = render_summary(date_str, args.local_model, args.remote_model, args.questions, results) + SUMMARY_PATH.write_text(summary, encoding="utf-8") + print(summary, end="") + + +if __name__ == "__main__": + try: + main() + except Exception as exc: + print(f"phase5-eval-matrix: {exc}", file=sys.stderr) + sys.exit(1) From 132d31a49de46efec2325d6e8adb130a727ba201 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Sun, 7 Jun 2026 16:21:56 +0100 Subject: [PATCH 16/17] add localdecode benchmark log --- ...-06-ds4-eval-cuda-to-metal-localdecode.log | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda-to-metal-localdecode.log diff --git a/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda-to-metal-localdecode.log b/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda-to-metal-localdecode.log new file mode 100644 index 000000000..9f84f953d --- /dev/null +++ b/artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda-to-metal-localdecode.log @@ -0,0 +1,105 @@ +$ ./ds4-eval -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --role coordinator --listen 0.0.0.0 1234 --layers 0:21 --nothink --tokens 4096 --trace /tmp/ds4-eval.trace +ds4: CUDA backend initialized on NVIDIA GB10 (sm_121) +ds4: restricting cuda model map to layers 0:21+output (48 spans, 42.03 GiB tensor span) +ds4: CUDA preparing model tensor mappings: 42.03 GiB +ds4: CUDA startup model preparation covered 42.03 GiB of tensor spans in 5.399s +ds4: cuda backend initialized for graph diagnostics +ds4-eval: context auto-sized to 4873 tokens (largest prompt=777 tokens, case=70, generation budget=4096) +ds4-eval: model shape DeepSeek V4 Flash +ds4-eval: context buffers 469.74 MiB (ctx=4873, backend=cuda, prefill_chunk=4096, raw_kv_rows=4352, compressed_kv_rows=1220) +ds4-eval: waiting for distributed route: distributed route incomplete: missing layer 22 +ds4-eval: distributed route ready +ds4-eval: 65/92 passed, 27 failed, runtime 03h:01m +# state prompt gen total given correct test + 1 PASSED 201 339 540 B B GPQA Diamond/recNu3MXkvWUzHZr9 + 2 FAILED 149 68 217 G C SuperGPQA/001b51d76b4d422988f2c11f104a2c6c + 3 PASSED 81 240 321 70 70 AIME2025/aime2025-01 + 4 PASSED 313 143 456 C C GPQA Diamond/recoiTJPGUmzAkief + 5 PASSED 272 105 377 J J SuperGPQA/b7e20eac98764fb0bf30e8366d951daa + 6 PASSED 146 939 1085 468 468 AIME2025/aime2025-16 + 7 PASSED 156 540 696 B B GPQA Diamond/rec4UqStf9WUVif1f + 8 PASSED 127 61 188 E E SuperGPQA/4a1d1780a93f4093b6fb7d3c314cbea8 + 9 PASSED 633 1597 2230 588 588 AIME2025/aime2025-02 + 10 PASSED 182 486 668 B B GPQA Diamond/recgI6tUQ7RLJRWGx + 11 PASSED 137 56 193 A A SuperGPQA/6082513c8dba4ec68aa68f1bf5854d09 + 12 PASSED 165 479 644 16 16 AIME2025/aime2025-03 + 13 PASSED 149 456 605 A A GPQA Diamond (modified)/recDytVnNYZe2HuUU + 14 PASSED 167 48 215 J J SuperGPQA/bebf1ed45ae14ad7b4f205f3909cb58a + 15 FAILED 305 1419 1724 96 82 AIME2025/aime2025-18 + 16 PASSED 131 388 519 D D GPQA Diamond/recNFJjE5PPTqVJGv + 17 PASSED 175 48 223 I I SuperGPQA/7ca71b86327744b78e93185a45bc5cef + 18 PASSED 102 1074 1176 117 117 AIME2025/aime2025-04 + 19 PASSED 187 293 480 B B GPQA Diamond/rec2UlKqC6RFHdcro + 20 PASSED 173 302 475 E E SuperGPQA/d44b94f7749345a39a65f6312bda8764 + 21 PASSED 229 1467 1696 106 106 AIME2025/aime2025-19 + 22 PASSED 250 87 337 B B GPQA Diamond/recv7GsQg3f0fvB1f + 23 PASSED 232 73 305 B B SuperGPQA/febe406f44d74a40b50bb5b7c69d5dc1 + 24 PASSED 126 1211 1337 279 279 AIME2025/aime2025-05 + 25 FAILED 229 4096 4325 D C GPQA Diamond/recrHBEJJoDTV05JR + 26 PASSED 160 389 549 C C SuperGPQA/31950dc80ded400a9181f50626d1f75c + 27 PASSED 124 471 595 504 504 AIME2025/aime2025-06 + 28 FAILED 198 181 379 C D GPQA Diamond/recb80OwMgNnceA9t + 29 PASSED 602 537 1139 C C SuperGPQA/0f14cd17be174618af6d60227e7dca9f + 30 PASSED 753 1702 2455 293 293 AIME2025/aime2025-21 + 31 PASSED 254 314 568 C C GPQA Diamond/recA1i5ZAh0Uzclxp + 32 PASSED 394 350 744 J J SuperGPQA/cef9bcc087434cc2b4e354a9baef55eb + 33 PASSED 196 2131 2327 821 821 AIME2025/aime2025-07 + 34 FAILED 216 679 895 A B GPQA Diamond/recqGD3fxPCI59vPQ + 35 PASSED 159 72 231 I I SuperGPQA/9f93aa2cfdb547b5b3a4623f80f7fff6 + 36 PASSED 137 1733 1870 237 237 AIME2025/aime2025-22 + 37 PASSED 306 674 980 A A GPQA Diamond/rechKl68Uc6H7vU0N + 38 PASSED 157 46 203 E E SuperGPQA/97ad69dda7b2462c98638b79e78aea0b + 39 PASSED 156 1620 1776 77 77 AIME2025/aime2025-08 + 40 PASSED 369 533 902 B B GPQA Diamond/rec1zl5LvaatzGhFt + 41 FAILED 128 68 196 E H SuperGPQA/e78e4e539d6f4e379ac140d923d7b1be + 42 FAILED 147 4096 4243 539 62 AIME2025/aime2025-09 + 43 PASSED 585 2352 2937 A A GPQA Diamond/recTs7qzfJs6kfLUK + 44 PASSED 182 170 352 A A SuperGPQA/8483667a25e74fdfa3188de4ea734f03 + 45 FAILED 140 1031 1171 150 149 AIME2025/aime2025-24 + 46 PASSED 238 309 547 C C GPQA Diamond/rec32C1ZEapBnCC0E + 47 PASSED 153 468 621 A A SuperGPQA/e5ed76ef98144f06843125daf1bccd35 + 48 FAILED 335 758 1093 68 81 AIME2025/aime2025-10 + 49 PASSED 225 304 529 B B GPQA Diamond/recZWeueB7lSPR6wN + 50 PASSED 127 86 213 H H SuperGPQA/fd7924876c4845cd83d95d61dfa0b236 + 51 FAILED 117 4096 4213 880 907 AIME2025/aime2025-25 + 52 PASSED 115 4096 4211 C C GPQA Diamond/recVvpD8miVjmmyfe + 53 PASSED 336 428 764 I I SuperGPQA/6bfe7d19299d4b3184636e1f51694306 + 54 FAILED 106 612 718 10395 113 AIME2025/aime2025-26 + 55 PASSED 225 2264 2489 D D GPQA Diamond/recAAJoHMW45Lv5je + 56 FAILED 410 309 719 C J SuperGPQA/e1825d70c5844c22933087eafa89e39c + 57 FAILED 160 3000 3160 1522 510 AIME2025/aime2025-12 + 58 FAILED 267 659 926 D C GPQA Diamond/reckEnrOPFT9Ru7tW + 59 PASSED 239 458 697 A A SuperGPQA/ab430ac3f18e4e02a2cb3f35498c6b30 + 60 PASSED 284 1598 1882 19 19 AIME2025/aime2025-27 + 61 PASSED 495 337 832 A A GPQA Diamond/rec8nshandHARTkrg + 62 PASSED 389 360 749 F F SuperGPQA/e8c5da5ca40647158b0c91dd695c6243 + 63 FAILED 129 1241 1370 154 204 AIME2025/aime2025-13 + 64 PASSED 449 326 775 A A GPQA Diamond/recFaL6j8UMhutXrc + 65 PASSED 190 667 857 H H SuperGPQA/05efdc6fb2404ddc8dd5729bb68c74e5 + 66 FAILED 182 4096 4278 43175 248 AIME2025/aime2025-28 + 67 FAILED 207 74 281 B C GPQA Diamond/reczQ4I0VpENdMtIj + 68 PASSED 470 909 1379 H H SuperGPQA/ba52e06cbe1a4310a77a7d12cd1db943 + 69 FAILED 141 4096 4237 28 104 AIME2025/aime2025-29 + 70 FAILED 777 204 981 A C GPQA Diamond/recWxGU8Q4YReJ1tb + 71 FAILED 277 737 1014 D F SuperGPQA/591a77df21324272914be82ac6583399 + 72 FAILED 127 4096 4223 243 735 AIME2025/aime2025-15 + 73 FAILED 220 193 413 A B GPQA Diamond/recMicVBcqy1xM1jq + 74 FAILED 202 81 283 J H SuperGPQA/e780f37a5baa4fe094cd9c157486664d + 75 FAILED 128 4096 4224 2 240 AIME2025/aime2025-30 + 76 PASSED 411 101 512 20 17-20 COMPSEC/compsec-076 + 77 PASSED 350 147 497 18 18-20 COMPSEC/compsec-077 + 78 PASSED 358 113 471 11 11 COMPSEC/compsec-078 + 79 FAILED 383 101 484 9 18-19 COMPSEC/compsec-079 + 80 FAILED 307 84 391 8 5-6 COMPSEC/compsec-080 + 81 FAILED 347 182 529 8 10-15 COMPSEC/compsec-081 + 82 PASSED 296 97 393 10 9-10 COMPSEC/compsec-082 + 83 PASSED 323 131 454 11 9-11 COMPSEC/compsec-083 + 84 PASSED 321 93 414 6,7 6-7 COMPSEC/compsec-084 + 85 PASSED 247 97 344 5 5 COMPSEC/compsec-085 + 86 PASSED 372 64 436 3 3,13-15 COMPSEC/compsec-086 + 87 PASSED 462 74 536 8 8,20-22 COMPSEC/compsec-087 + 88 PASSED 327 103 430 11 11 COMPSEC/compsec-088 + 89 PASSED 268 75 343 10 10 COMPSEC/compsec-089 + 90 PASSED 359 127 486 12 12-13 COMPSEC/compsec-090 + 91 PASSED 259 71 330 3 3 COMPSEC/compsec-091 + 92 PASSED 327 88 415 11 10-14 COMPSEC/compsec-092 \ No newline at end of file From 51ecda67e1dfaed327e0522feb656745da4c2279 Mon Sep 17 00:00:00 2001 From: Igor Lobanov Date: Sun, 7 Jun 2026 22:59:52 +0100 Subject: [PATCH 17/17] phase 5 closeout --- README.md | 8 + artifacts/issue-304/compatibility-matrix.md | 2 + artifacts/issue-304/decision-log.md | 92 +++++++++ artifacts/issue-304/ds4-eval-matrix.md | 55 +++--- artifacts/issue-304/failure-cases.md | 53 ++++++ artifacts/issue-304/logit-comparisons.md | 30 +++ artifacts/issue-304/perf-breakdown.md | 30 +++ artifacts/issue-304/research-notes.md | 45 +++++ artifacts/issue-304/runbook.md | 68 +++++++ ds4_distributed.c | 88 ++++++--- ds4_eval.c | 11 +- tests/ds4_test.c | 198 ++++++++++++++++++++ 12 files changed, 617 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 97edf0fa5..8bd09f5e0 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,14 @@ distributed options are also wired into `ds4-agent`, `ds4-eval`, and `ds4-bench`. For benchmarks, workers should already be running; `ds4-bench` waits until a complete route is available. +When the final worker owns `N:output`, you can also start that worker with +`--local-decode`. In that mode the route still does distributed prefill, but +after prefill the coordinator pushes its KV shard to the final worker and the +worker finishes generation locally using full model residency. This is the +Phase 5 handoff workflow: it keeps the distributed prefill speedup while moving +decode back onto one machine. See `artifacts/issue-304/runbook.md` for the +authoritative commands and current caveats. + Useful tuning and diagnostics: ```sh diff --git a/artifacts/issue-304/compatibility-matrix.md b/artifacts/issue-304/compatibility-matrix.md index 547bedae7..478a6f37f 100644 --- a/artifacts/issue-304/compatibility-matrix.md +++ b/artifacts/issue-304/compatibility-matrix.md @@ -49,6 +49,8 @@ | 2026-06-05 | local working tree after `--local-decode` CLI and stream-handoff changes | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | pure local Metal baseline | plain `ds4` CLI, full `README.md` | Pass | Reference Mac-only baseline on the same prompt: prefill `413.44 tok/s`, generation `34.78 tok/s`. | | 2026-06-05 | local working tree after sampled handoff and stale-logits fix | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `Metal -> CUDA`, reused-session multi-turn `0:21 -> 22:output` | `tests/issue304_phase5_multiturn`, DGX worker, compare reused caught-up session vs fresh full-transcript session | Investigating | Immediate post-turn1 boundary now matches closely (`top1 1116/1116`, `top5=5/5`, `top10=10/10`, `top20=20/20`, `rms=0.27032664`), but follow-up sync on the reused state still drifts before turn two (`8474` vs `267`, `top5=4/5`, `rms=0.99836105`). | | 2026-06-05 | local working tree after normal-eval local-decode changes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `CUDA -> Metal`, reused-session sampled normal-eval multi-turn `0:21 -> 22:output` | `tests/issue304_phase5_multiturn --normal-eval --temp 0.7 --top-p 0.95 --min-p 0.05 --seed 123`, DGX coordinator, fresh Metal worker | Mixed / Investigating | Follow-up-sync frontier still drifts (`top1 8474/8474`, `top5=4/5`, `top10=8/10`, `top20=15/20`, `rms=0.81043321`), but the tested second-turn sampled tokens still matched exactly, so this route is milder than the `Metal -> CUDA` sampled case. | +| 2026-06-06 | local working tree after `ds4-eval` handoff/timeout fixes, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `CUDA -> Metal`, `0:21 -> 22:output` | full `ds4-eval --nothink` `92`-question run, worker `--local-decode` | Pass for Phase 5 closeout | The evaluator now uses the intended worker-owned handoff path, completes the full suite without coordinator disconnect, and scores `65/92` versus local baselines `67/92` (Metal) and `69/92` (CUDA). Treat the remaining delta as evaluation variance rather than a local-decode routing failure. | +| 2026-06-07 | local working tree after `LOCAL_GENERATE` forced-eval fix, DGX rebuilt from synced tree | `DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` | `CUDA -> Metal`, `0:21 -> 22:output` | `DS4_RUN_DISTRIBUTED_TEST=1 DS4_TEST_DISTRIBUTED_LISTEN_HOST=0.0.0.0 DS4_TEST_DISTRIBUTED_LISTEN_PORT=1234 DS4_TEST_DISTRIBUTED_ROUTE_WAIT_MS=60000 ./ds4_test --local-decode-push`, DGX coordinator + local Metal worker | Pass | The real two-node Phase 5 regression now passes through one-shot handoff, one forced-token reuse eval, and a second short handoff: `local_decode_active=yes`, `first_handoff=2`, `reuse_eval=1`, `second_handoff=1`, `kv=0.019s`, `decode=0.053s`, `decode2=0.026s`. | ## Representative `DSVL` shard smoke diff --git a/artifacts/issue-304/decision-log.md b/artifacts/issue-304/decision-log.md index 6d2ff67cb..f48adf4c2 100644 --- a/artifacts/issue-304/decision-log.md +++ b/artifacts/issue-304/decision-log.md @@ -498,3 +498,95 @@ Why this changes the next steps: payload shape, especially the current always-on per-token logits-trace allocation/copy/return path, before drawing backend-level conclusions from evaluator throughput. + +## 2026-06-06: Long `ds4-eval --nothink` local-decode runs were failing on the 60s distributed socket timeout + +Decision: + +- Treat the remaining `ds4-eval` `CUDA -> Metal --local-decode --nothink` + blocker as a distributed socket-timeout issue, not as a silent + coordinator crash or a broken handoff state. +- Raise the default distributed socket timeout from `60` to `600` seconds + while preserving `DS4_DIST_SOCKET_TIMEOUT_SEC` as an override. + +Evidence: + +- An explicit DGX coordinator run with the intended evaluator path: + - `./ds4-eval --ctx 16384 --plain --temp 0 --seed 1 --nothink` + - `--tokens 4096 --questions 6 --role coordinator --layers 0:21` + - `--listen 192.168.1.98 1241` + - local Metal worker on the Mac: + `./ds4 --ctx 16384 --role worker --layers 22:output --local-decode --coordinator 192.168.1.98 1241` + failed immediately on case 1 with: + - coordinator trace error: + `failed to read frame header: Resource temporarily unavailable` + - worker stderr: + `distributed worker: protocol error: failed to read frame header: Resource temporarily unavailable` +- The failure reproduced at about the 60-second mark, which matches the + existing default set in `dist_set_socket_low_latency()`. +- Re-running the exact same explicit commands with + `DS4_DIST_SOCKET_TIMEOUT_SEC=600` on both coordinator and worker cleared + the blocker: + - case 1 passed in `113.1 s` + - case 2 passed in `112.1 s` + - case 3 passed in `112.0 s` + - case 4 passed in `113.8 s` + - case 5 passed in `113.3 s` + - case 6 passed in `111.9 s` + - full result: `6/6 passed`, runtime `00h:11m` +- After changing the default timeout to `600`, the same explicit no-env + command line also passed a fresh one-question verification: + - `1/1 passed` + - case 1 runtime `113.8 s` + +Why this changes the next steps: + +- Phase 5 is no longer blocked on the evaluator dying in non-thinking + distributed-prefill/local-decode mode. +- The remaining work returns to performance and reusable-session parity: + - the evaluator path is now stable enough for longer local-decode runs, + - but one-shot local-decode decode time is still large enough that socket + policy must account for it, + - and the local-generate RPC payload still carries avoidable overhead. + +## 2026-06-07: Close Phase 5 on the fresh-worker worker-owned path + +Decision: + +- Close Phase 5 on the implemented worker-owned `--local-decode` workflow. +- Treat fresh-worker one-shot and evaluator evidence as the authoritative + acceptance surface. +- Carry forward reusable-session follow-up drift as a post-Phase-5 caveat + unless it turns into a concrete stale-KV, token-hash, or session-integrity + failure. + +Evidence: + +- Plain CLI worker-owned local decode already passed in both backend + directions with measured KV handoff timing. +- `ds4-eval --nothink` now uses the intended worker-owned handoff path and the + timeout fix lets long answers complete. +- The real DGX/Mac distributed regression now also passes: + - local worker: + `./ds4 --ctx 2048 --role worker --layers 22:output --coordinator dgx-direct 1234 --local-decode` + - DGX coordinator test: + `DS4_RUN_DISTRIBUTED_TEST=1 DS4_TEST_DISTRIBUTED_LISTEN_HOST=0.0.0.0 DS4_TEST_DISTRIBUTED_LISTEN_PORT=1234 DS4_TEST_DISTRIBUTED_ROUTE_WAIT_MS=60000 ./ds4_test --local-decode-push` + - observed pass line: + `local_decode_active=yes first_handoff=2 reuse_eval=1 second_handoff=1` +- The authoritative `92`-question evaluator runs on `2026-06-06` scored: + - local Metal: `67/92` + - local CUDA: `69/92` + - `CUDA -> Metal --local-decode`: `65/92` +- `make test` now passes locally with the default environment, and the new + distributed regression remains opt-in as intended. +- That gap is small enough to treat as evaluation variance for Phase 5 + closeout rather than as evidence that the worker-owned handoff path is still + routing incorrectly. + +Why this changes the next steps: + +- Phase 5 is now closed. +- Follow-on work moves out of closeout and into later phases: + - reusable-session follow-up parity, + - incremental/local-decode streaming UX, + - and `LOCAL_GENERATE` protocol overhead reduction. diff --git a/artifacts/issue-304/ds4-eval-matrix.md b/artifacts/issue-304/ds4-eval-matrix.md index b9dfc6982..9429a1888 100644 --- a/artifacts/issue-304/ds4-eval-matrix.md +++ b/artifacts/issue-304/ds4-eval-matrix.md @@ -1,42 +1,39 @@ # Phase 5 `ds4-eval` Matrix +These are the authoritative full `92`-question `--nothink` results collected +after the evaluator was switched onto the worker-owned local-decode handoff +path and after the distributed socket timeout fix landed. + - Date: `2026-06-06` -- Questions: `4` +- Questions: `92` - Local model: `./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` - Remote model: `/home/ilo037/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf` - Remote host: `dgx-direct` -| Cell | Score | Runtime (s) | Prompt toks | Gen toks | Prefill (s) | Decode (s) | Backend | Route | Hops | Output | Local decode | Trace | -| --- | ---: | ---: | ---: | ---: | ---: | ---: | --- | --- | ---: | --- | --- | --- | -| `local-metal-nothink` | 4/4 | 28.492 | 744 | 901 | 4.872 | 23.620 | `metal` | `local` | 0 | `local` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-local-metal-nothink.trace) | -| `local-cuda-nothink` | 4/4 | 62.275 | 744 | 848 | 3.664 | 58.612 | `cuda` | `local` | 0 | `local` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-local-cuda-nothink.trace) | -| `metal-to-cuda-localdecode-nothink` | 4/4 | 86.553 | 744 | 859 | 5.439 | 81.113 | `metal` | `local 0:21 -> 10.77.0.2:41039 Q2 22:output` | 1 | `worker` | `expected=yes, active=yes` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-metal-to-cuda-localdecode-nothink.trace) | -| `cuda-to-metal-localdecode-nothink` | 3/4 fail=1 | 162.930 | 744 | 828 | 9.680 | 153.250 | `cuda` | `local 0:21 -> 192.168.1.218:49540 Q2 22:output` | 1 | `worker` | `expected=yes, active=yes` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-cuda-to-metal-localdecode-nothink.trace) | -| `metal-to-cuda-full-nothink` | 4/4 | 49.667 | 744 | 812 | 5.434 | 44.235 | `metal` | `local 0:21 -> 10.77.0.2:34989 Q2 22:output` | 1 | `worker` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-metal-to-cuda-full-nothink.trace) | -| `cuda-to-metal-full-nothink` | 4/4 | 85.975 | 744 | 817 | 8.690 | 77.287 | `cuda` | `local 0:21 -> 192.168.1.218:49923 Q2 22:output` | 1 | `worker` | `expected=no, active=no` | [trace](artifacts/issue-304/ds4-eval/raw/2026-06-06-cuda-to-metal-full-nothink.trace) | +| Cell | Score | Runtime | Backend | Route | Output | Local decode | Artifact | +| --- | ---: | --- | --- | --- | --- | --- | --- | +| `local-metal-nothink` | `67/92` | `00h:47m` | `metal` | `local` | `local` | `expected=no, active=no` | [log](artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-metal.log) | +| `local-cuda-nothink` | `69/92` | `01h:39m` | `cuda` | `local` | `local` | `expected=no, active=no` | [log](artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda.log) | +| `cuda-to-metal-localdecode-nothink` | `65/92` | `03h:01m` | `cuda` | `local 0:21 -> Metal worker 22:output` | `worker` | `expected=yes, active=yes` | [log](artifacts/issue-304/ds4-eval/2026-06-06-ds4-eval-cuda-to-metal-localdecode.log) | ## Status -- Latest completed `6 x 4` `--nothink` smoke: `5/6` cells passed. -- Passing cells: local Metal, local CUDA, `Metal -> CUDA` local-decode, `Metal -> CUDA` full-distributed, `CUDA -> Metal` full-distributed. -- Remaining failing cell: `CUDA -> Metal` local-decode, failing `SuperGPQA/001b51d76b4d422988f2c11f104a2c6c` with picked `G` vs expected `C`. +- The current Phase 5 evaluator evidence is no longer the earlier `4`-question + smoke. The authoritative local-decode comparison is the full `92`-question + run above. +- `CUDA -> Metal --local-decode` is now considered operationally healthy: + the route stays up, the worker-owned handoff engages, and the evaluator + completes the full suite instead of timing out or disconnecting mid-run. +- The observed score gap versus the fully local baselines is small enough to + treat as evaluation variance for Phase 5 closeout rather than as a new + handoff-routing failure. ## Notes -- `local_decode_expected: yes` with header `local_decode_active: no` is not treated as a routing failure here. The stronger summary field is `local_decode_active_any_case`, and for both `*-localdecode-*` cells it is `yes`, which shows local decode did engage during generation. -- The runner now includes the extra Phase 5 fully distributed cells: - - `metal-to-cuda-full-nothink` - - `cuda-to-metal-full-nothink` -- The runner was hardened during troubleshooting to: - - use stable SSH options for `dgx-direct` (`IPQoS=none`, no control master/path) - - restart workers per case in fresh-per-case mode - - wait for worker readiness before starting each case - - bypass the DGX startup memory guard for remote worker restarts - - clear stale per-case trace files before merge - - wait for remote worker shutdown before restart - -## Interpretation - -- Full-distributed mode is currently healthy in both directions on this `4`-question `--nothink` smoke. -- `Metal -> CUDA` local-decode also passes after the runner cleanup. -- The remaining issue is isolated to `CUDA -> Metal` local-decode under the smoke harness, not to full-distributed routing in general. +- `local_decode_active_any_case: yes` remains the authoritative indication that + worker-owned local decode engaged during generation. +- The earlier `4`-question matrix was still useful for route bring-up and + timeout diagnosis, but it is no longer the acceptance surface for Phase 5. +- Current `ds4-eval` local-decode throughput is still lower than the plain CLI + benchmark because the handoff RPC path still pays extra response overhead. + That is a post-Phase-5 performance item, not a closeout blocker. diff --git a/artifacts/issue-304/failure-cases.md b/artifacts/issue-304/failure-cases.md index 642bd1cf3..f505a1fad 100644 --- a/artifacts/issue-304/failure-cases.md +++ b/artifacts/issue-304/failure-cases.md @@ -64,6 +64,48 @@ This artifact records mismatches that should remain rejected during distributed- - Immediate next rerun on the same worker: first mismatch at generated step `0`; `handoff_first_token=5`, reference `2337`. - Why rejected: the lifecycle fixes improved the original stale-worker symptom, but they did not make repeated reused-worker parity reliable enough to use as a strict acceptance surface. +- `phase5 ds4-eval CUDA -> Metal local-decode / old 60s socket timeout` + - Explicit DGX coordinator command: + `./ds4-eval --ctx 16384 --plain --temp 0 --seed 1 --nothink --tokens 4096 --questions 6 --role coordinator --layers 0:21 --listen 192.168.1.98 1241` + - Local Metal worker: + `./ds4 --ctx 16384 --role worker --layers 22:output --local-decode --coordinator 192.168.1.98 1241` + - Observed failure: + - coordinator trace error: + `failed to read frame header: Resource temporarily unavailable` + - worker stderr: + `distributed worker: protocol error: failed to read frame header: Resource temporarily unavailable` + - Why rejected: the old default distributed socket timeout (`60s`) was shorter than a healthy one-shot local-decode answer generation in `ds4-eval`. + - Current status: fixed by raising the default distributed socket timeout to `600s`; keep this recorded as the historical failure class that explained the reported “dies after 5-6 questions” blocker. + +## Phase 5 user-visible negative cases + +- `--local-decode` on a coordinator process + - Diagnostic: `--local-decode requires --role worker` + - Status: reject at distributed option validation before runtime. + +- `--local-decode` on a worker without `N:output` + - Diagnostic: `--local-decode requires --layers N:output` + - Status: reject before runtime because the worker would not own the output head. + +- local-decode handoff without an advertised local-decode worker + - Diagnostic: `distributed handoff requires worker local-decode capability` + - Status: reject at handoff time; the route exists, but the final worker did not advertise the needed capability. + +- local-decode handoff to a route whose final worker does not own output logits + - Diagnostic: `distributed handoff requires worker-owned output head` + - Status: reject at handoff time; the workflow only supports final-worker decode. + +- pushed-shard token timeline mismatch + - Diagnostics seen in protocol handlers: + - `worker snapshot token hash mismatch` + - `snapshot load token hash mismatch` + - `worker local generate token hash mismatch` + - Status: fail closed; stale or mismatched worker state must not be reused silently. + +- worker/coordinator payload layout mismatch + - Diagnostic class: snapshot layout validation rejects mismatched `prefill_cap`, layer range, or payload metadata before accepting the shard. + - Status: preserve as a hard rejection; this is an integrity boundary, not a tolerable drift case. + ## Phase 4 closeout classification - The two Phase 4 `CUDA -> Metal` reused-worker rerun failures remain recorded here because they fail strict token-parity expectations. @@ -73,6 +115,17 @@ This artifact records mismatches that should remain rejected during distributed- - and no evidence that the final-worker handoff workflow itself is invalid. - Treat them as the same practical class of backend-sensitive near-top1 variance already documented in Phase 3.5 unless a later phase proves a concrete stale-state or payload-integrity defect. +## Phase 5 closeout classification + +- The fresh-worker worker-owned `--local-decode` path is now considered valid for Phase 5 closeout. +- The remaining reusable-session follow-up drift does not stay in the Phase 5 + blocker set unless it reappears as: + - stale coordinator KV after catch-up, + - token-hash/session-integrity failure, + - or a broken subsequent prompt control-flow path. +- Treat score variance in the full `ds4-eval` runs as evaluation noise for + Phase 5 purposes, not as a new rejection case for the handoff workflow. + ## Phase 3 Rejection Criteria A drift case should be recorded here as rejected if it: diff --git a/artifacts/issue-304/logit-comparisons.md b/artifacts/issue-304/logit-comparisons.md index c1b237900..d7a2a58f6 100644 --- a/artifacts/issue-304/logit-comparisons.md +++ b/artifacts/issue-304/logit-comparisons.md @@ -244,3 +244,33 @@ The DGX worker and DGX-side helper were run with `--power 50`. - The official API gate is materially weaker than route parity. Three `short_code_completion` routes missed official acceptance, while the longer official cases still passed even when resumed-route parity had already drifted. - Resumed payload routes remain the weakest cells. They are the only routes that repeatedly combine nonzero official deltas with visibly looser top-k overlap and RMS on otherwise passing cases. - The local-golden fixture itself is also route-sensitive. Pure local Metal (`route 2`) missed the stored fixture while both distributed direct-generation routes (`3` and `4`) passed it exactly against their own references. + +## Phase 5 worker-owned local-decode acceptance surface + +Phase 5 does not add a new strict token-parity gate. The acceptance surface for +the worker-owned handoff path is narrower: + +- fresh-worker one-shot local-decode runs must complete through the intended + handoff path, +- the handoff frontier must remain valid enough for coordinator catch-up and + subsequent decode control flow, +- and the `ds4-eval --nothink` local-decode path must behave like the same + worker-owned handoff workflow rather than the old per-token loop. + +For the current Phase 5 closeout evidence: + +- plain CLI fresh-worker runs in both directions already establish the intended + handoff shape, +- the full `92`-question `CUDA -> Metal --local-decode` evaluator run completes + with `65/92` versus `67/92` local Metal and `69/92` local CUDA, +- and the remaining reusable-session drift is classified as a follow-up-sync + caveat rather than a fresh-worker handoff failure. + +Interpretation: + +- The authoritative Phase 5 question is now “does worker-owned local decode run + correctly as a user-visible workflow?” rather than “does every reused session + remain parity-identical to a fresh baseline?” +- Strict same-token parity on reused worker state remains a post-Phase-5 + classification item unless it turns into a concrete stale-KV, token-hash, or + session-integrity failure. diff --git a/artifacts/issue-304/perf-breakdown.md b/artifacts/issue-304/perf-breakdown.md index f964405ca..ba1d1d606 100644 --- a/artifacts/issue-304/perf-breakdown.md +++ b/artifacts/issue-304/perf-breakdown.md @@ -66,6 +66,36 @@ Interpretation: overhead in the local-generate response path, not as proof that Metal local decode itself only sustains `~10 tok/s`. +### 2026-06-06 explicit `ds4-eval` timeout diagnosis + +Explicit `CUDA -> Metal` evaluator repro: + +| Surface | Route | Questions | Timeout mode | Result | Key timing / error | Notes | +| --- | --- | ---: | --- | --- | --- | --- | +| `ds4-eval` | `CUDA -> Metal`, worker `--local-decode` | 6 | old default `60s` | Fail | case 1 failed after about `60s` with `failed to read frame header: Resource temporarily unavailable` | one-shot local decode had not returned its first response frame before the socket timeout | +| `ds4-eval` | `CUDA -> Metal`, worker `--local-decode` | 6 | `DS4_DIST_SOCKET_TIMEOUT_SEC=600` | Pass | case runtimes `111.9s` to `113.8s`, full run `6/6 passed` in `00h:11m` | proves the blocker was socket policy, not evaluator control flow | +| `ds4-eval` | `CUDA -> Metal`, worker `--local-decode` | 1 | new default `600s`, no env override | Pass | case 1 `113.8s`, `1/1 passed` | verifies the code-side timeout change removes the need for a manual env override | + +### 2026-06-06 authoritative `ds4-eval` full runs + +The authoritative Phase 5 evaluator comparison is now the full `92`-question +set, not the earlier `4`-question smoke. + +| Surface | Route | Score | Runtime | Notes | +| --- | --- | ---: | --- | --- | +| `ds4-eval` | local Metal | `67/92` | `00h:47m` | Mac baseline | +| `ds4-eval` | local CUDA | `69/92` | `01h:39m` | DGX/local CUDA baseline | +| `ds4-eval` | `CUDA -> Metal`, worker `--local-decode` | `65/92` | `03h:01m` | worker-owned local decode stayed active and completed the full suite | + +Interpretation: + +- The Phase 5 local-decode route is now stable enough to finish the full + evaluator suite instead of failing on timeout or disconnect. +- Score variance against the fully local baselines is small enough that Phase 5 + closeout should treat it as evaluator variance, not as a routing regression. +- The remaining performance gap versus the plain CLI benchmark is still a + protocol-overhead question in the current `LOCAL_GENERATE` response path. + ## Phase 4 final-worker handoff timings Tool: diff --git a/artifacts/issue-304/research-notes.md b/artifacts/issue-304/research-notes.md index 9af49ad79..5d4cf293e 100644 --- a/artifacts/issue-304/research-notes.md +++ b/artifacts/issue-304/research-notes.md @@ -496,6 +496,23 @@ The remaining work should separate: not as evidence that the Mac local-decode backend is fundamentally slower than the plain local-decode CLI benchmark. +11. The evaluator blocker on longer `--nothink` local-decode runs was the + default distributed socket timeout, not a silent coordinator crash. + - An explicit `CUDA -> Metal` evaluator repro using the intended + worker-owned handoff path failed on case 1 with: + `failed to read frame header: Resource temporarily unavailable`. + - The worker simultaneously logged: + `distributed worker: protocol error: failed to read frame header: Resource temporarily unavailable`. + - That failure landed at the old default `60s` socket timeout boundary, + while one-shot local-decode answers in this evaluator path were taking + about `112-114s` per case. + - Re-running the same explicit commands with + `DS4_DIST_SOCKET_TIMEOUT_SEC=600` on both ends cleared the blocker and + completed `6/6` questions on one long-lived session. + - After raising the default distributed socket timeout to `600s`, the + same no-env explicit command line also passed a fresh one-question + verification where case 1 took `113.8s`. + ### Implication Phase 5 has crossed the implementation threshold: the intended CLI workflow @@ -507,3 +524,31 @@ The next work should focus on: local-decode workflow where intended, - and reducing local-generate protocol overhead before interpreting `ds4-eval` local-decode throughput as a backend limit. + +### Closeout note + +The full `2026-06-06` `92`-question evaluator runs now move Phase 5 from +"implemented and still under smoke investigation" to "ready to close": + +- local Metal: `67/92` +- local CUDA: `69/92` +- `CUDA -> Metal --local-decode`: `65/92` + +That is close enough that the remaining difference is better treated as normal +evaluation variance plus known RPC overhead, not as a blocker on the +worker-owned handoff workflow itself. The remaining reusable-session follow-up +drift should be carried forward as a post-Phase-5 caveat unless it becomes a +clear stale-KV or session-integrity failure. + +On `2026-06-07`, the last missing closeout item also passed on the real +DGX/Mac topology: + +- `make test` passed locally with the default environment, +- the opt-in distributed regression passed on the actual two-node route, +- and the fixed `LOCAL_GENERATE` forced-eval path now survives: + - one-shot worker-owned handoff, + - one forced-token reuse eval, + - and a second short local-decode handoff. + +That is sufficient to treat Phase 5 as closed. Any remaining local-decode work +is now follow-on refinement, not part of the Phase 5 exit gate. diff --git a/artifacts/issue-304/runbook.md b/artifacts/issue-304/runbook.md index a4884eaff..3bb857b6f 100644 --- a/artifacts/issue-304/runbook.md +++ b/artifacts/issue-304/runbook.md @@ -86,6 +86,74 @@ Current limitation: - the remaining open issue is reusable-session variance, not lack of normal eval/server delegation. +### `ds4_test --local-decode-push` regression command + +The Phase 5 regression is now runnable on the real DGX/Mac topology. + +Local Metal worker: + +```sh +./ds4 --ctx 2048 --role worker --layers 22:output --coordinator dgx-direct 1234 --local-decode +``` + +DGX coordinator regression: + +```sh +ssh dgx-direct 'cd ~/ds4 && DS4_RUN_DISTRIBUTED_TEST=1 DS4_TEST_DISTRIBUTED_LISTEN_HOST=0.0.0.0 DS4_TEST_DISTRIBUTED_LISTEN_PORT=1234 DS4_TEST_DISTRIBUTED_ROUTE_WAIT_MS=60000 ./ds4_test --local-decode-push' +``` + +Good output now includes: + +```text +ds4-test: local-decode push pass listen=0.0.0.0:1234 route="local 0:21 -> ... Q2 22:output" hops=1 local_decode_active=yes first_handoff=2 reuse_eval=1 second_handoff=1 +``` + +### `ds4-eval` explicit local-decode commands + +Use explicit `ds4-eval` commands, not the matrix helper, when validating the +evaluator blocker directly. + +`CUDA -> Metal` local worker on the Mac: + +```sh +./ds4 -m ./gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --role worker --layers 22:output --local-decode --coordinator 192.168.1.98 1241 +``` + +`CUDA -> Metal` coordinator repro on DGX: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./ds4-eval -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --plain --temp 0 --seed 1 --nothink --tokens 4096 --questions 6 --trace /tmp/2026-06-06-cuda-to-metal-localdecode-q6.trace --role coordinator --layers 0:21 --listen 192.168.1.98 1241' +``` + +Historical failure before the timeout fix: + +- The command above failed on case 1 after about one minute with: + `failed to read frame header: Resource temporarily unavailable`. +- The root cause was the old default distributed socket timeout of `60s`, + which was shorter than a full one-shot local-decode answer generation. + +Current rule after the fix: + +- The distributed default socket timeout is now `600s`. +- `DS4_DIST_SOCKET_TIMEOUT_SEC` still overrides it for debugging. +- The same no-env explicit command line now completes long first-case + generations that take about `114s`. + +Fresh no-env verification command on DGX: + +```sh +ssh dgx-direct 'cd ~/ds4 && ./ds4-eval -m ~/ds4/gguf/DeepSeek-V4-Flash-IQ2XXS-w2Q2K-AProjQ8-SExpQ8-OutQ8-chat-v2-imatrix.gguf --ctx 16384 --plain --temp 0 --seed 1 --nothink --tokens 4096 --questions 1 --trace /tmp/2026-06-06-cuda-to-metal-localdecode-q1-noenv.trace --role coordinator --layers 0:21 --listen 192.168.1.98 1241' +``` + +Captured traces: + +- failure before the timeout fix: + [2026-06-06-cuda-to-metal-localdecode-q6-timeout-fail.trace](/Users/lobanov/Projects/ds4/artifacts/issue-304/ds4-eval/2026-06-06-cuda-to-metal-localdecode-q6-timeout-fail.trace) +- pass with `DS4_DIST_SOCKET_TIMEOUT_SEC=600` on both ends: + [2026-06-06-cuda-to-metal-localdecode-q6-timeout600-pass.trace](/Users/lobanov/Projects/ds4/artifacts/issue-304/ds4-eval/2026-06-06-cuda-to-metal-localdecode-q6-timeout600-pass.trace) +- pass after changing the default timeout, with no env override: + [2026-06-06-cuda-to-metal-localdecode-q1-noenv-pass.trace](/Users/lobanov/Projects/ds4/artifacts/issue-304/ds4-eval/2026-06-06-cuda-to-metal-localdecode-q1-noenv-pass.trace) + ## Phase 4 closeout rules Phase 4 is complete. Use these rules for ongoing validation and follow-on work: diff --git a/ds4_distributed.c b/ds4_distributed.c index 903c439f5..511c9bf9c 100644 --- a/ds4_distributed.c +++ b/ds4_distributed.c @@ -211,6 +211,7 @@ typedef struct { uint32_t token_hash_hi; uint32_t token_hash_lo; uint32_t n_predict; + uint32_t flags; uint32_t seed_hi; uint32_t seed_lo; uint32_t temperature_bits; @@ -235,6 +236,8 @@ typedef struct { uint32_t message_bytes; } ds4_dist_local_generate_res_fixed; +#define DS4_DIST_LOCAL_GENERATE_F_LOGITS_TRACE 0x00000001u + /* ========================================================================= * Runtime State * ========================================================================= @@ -1125,7 +1128,13 @@ static int dist_set_socket_low_latency(int fd) { int one = 1; int rc = 0; int buffer_bytes = dist_socket_buffer_bytes(); - int timeout_sec = 60; + /* One-shot worker local-decode replies are sent only after the whole + * generation finishes. In `ds4-eval --nothink` this can legitimately take + * well over a minute for a single case, so the old 60s default caused the + * coordinator data socket and the worker's idle control socket to time out + * during otherwise healthy runs. Keep the env override, but make the + * default long enough for benchmark-scale local-decode turns. */ + int timeout_sec = 600; const char *timeout_env = getenv("DS4_DIST_SOCKET_TIMEOUT_SEC"); if (timeout_env && timeout_env[0]) { char *end = NULL; @@ -1815,6 +1824,7 @@ static void dist_local_generate_req_to_wire(ds4_dist_local_generate_req_fixed *r r->token_hash_hi = htonl(r->token_hash_hi); r->token_hash_lo = htonl(r->token_hash_lo); r->n_predict = htonl(r->n_predict); + r->flags = htonl(r->flags); r->seed_hi = htonl(r->seed_hi); r->seed_lo = htonl(r->seed_lo); r->temperature_bits = htonl(r->temperature_bits); @@ -1832,6 +1842,7 @@ static void dist_local_generate_req_from_wire(ds4_dist_local_generate_req_fixed r->token_hash_hi = ntohl(r->token_hash_hi); r->token_hash_lo = ntohl(r->token_hash_lo); r->n_predict = ntohl(r->n_predict); + r->flags = ntohl(r->flags); r->seed_hi = ntohl(r->seed_hi); r->seed_lo = ntohl(r->seed_lo); r->temperature_bits = ntohl(r->temperature_bits); @@ -4788,6 +4799,8 @@ static int dist_local_generate_remote( if (errlen) snprintf(err, errlen, "invalid distributed local generate request"); return -1; } + const bool want_logits_trace = + logits_trace_out != NULL && logits_trace_cap > 0; const uint32_t vocab = (uint32_t)ds4_engine_vocab_size(d->state.engine); const uint32_t logits_bytes = (uint32_t)((uint64_t)vocab * sizeof(float)); @@ -4809,6 +4822,7 @@ static int dist_local_generate_remote( dist_u64_to_halves(request_id, &req.request_hi, &req.request_lo); dist_u64_to_halves(token_hash, &req.token_hash_hi, &req.token_hash_lo); req.n_predict = (uint32_t)n_predict; + req.flags = want_logits_trace ? DS4_DIST_LOCAL_GENERATE_F_LOGITS_TRACE : 0u; dist_u64_to_halves(seed, &req.seed_hi, &req.seed_lo); req.temperature_bits = dist_f32_bits(temperature); req.top_p_bits = dist_f32_bits(top_p); @@ -4898,9 +4912,15 @@ static int dist_local_generate_remote( if (errlen) snprintf(err, errlen, "distributed local generate returned invalid token payload"); goto cleanup; } - const uint32_t expect_logits_bytes = + const uint32_t final_logits_bytes = logits_bytes; + const uint32_t trace_logits_bytes = (uint32_t)((uint64_t)res.generated_count * (uint64_t)vocab * sizeof(float)); - if (res.logits_bytes != expect_logits_bytes) { + const bool wants_final_logits = final_logits_out && res.generated_count != 0; + const bool valid_logits_payload = + res.logits_bytes == 0 || + (want_logits_trace && res.logits_bytes == trace_logits_bytes) || + (!want_logits_trace && wants_final_logits && res.logits_bytes == final_logits_bytes); + if (!valid_logits_payload) { dist_discard_bytes(fd, body); if (errlen) snprintf(err, errlen, "distributed local generate returned invalid logits payload"); goto cleanup; @@ -4916,38 +4936,32 @@ static int dist_local_generate_remote( body -= res.token_bytes; if (res.logits_bytes != 0) { const int logits_trace_values = (int)((uint64_t)res.generated_count * (uint64_t)vocab); - if (!logits_trace_out || logits_trace_cap < logits_trace_values) { - uint32_t remaining_logits_bytes = res.logits_bytes; + if (want_logits_trace) { + if (logits_trace_cap < logits_trace_values) { + if (errlen) snprintf(err, errlen, "distributed local generate logits trace buffer is too small"); + goto cleanup; + } + if (dist_read_full(fd, logits_trace_out, res.logits_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to read local generate logits"); + goto cleanup; + } if (final_logits_out && res.generated_count != 0) { - const uint32_t tail_bytes = logits_bytes; - const uint32_t prefix_bytes = res.logits_bytes - tail_bytes; - if (prefix_bytes != 0 && - dist_discard_bytes(fd, prefix_bytes) <= 0) { - if (errlen) snprintf(err, errlen, "failed to discard local generate logits"); - goto cleanup; - } - if (dist_read_full(fd, final_logits_out, tail_bytes) <= 0) { - if (errlen) snprintf(err, errlen, "failed to read final local generate logits"); - goto cleanup; - } - remaining_logits_bytes = 0; + memcpy(final_logits_out, + logits_trace_out + (size_t)(res.generated_count - 1u) * (size_t)vocab, + (size_t)vocab * sizeof(final_logits_out[0])); } - if (remaining_logits_bytes != 0 && - dist_discard_bytes(fd, remaining_logits_bytes) <= 0) { - if (errlen) snprintf(err, errlen, "failed to discard local generate logits"); + } else if (final_logits_out && res.generated_count != 0) { + if (dist_read_full(fd, final_logits_out, res.logits_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to read final local generate logits"); goto cleanup; } - } else if (dist_read_full(fd, logits_trace_out, res.logits_bytes) <= 0) { - if (errlen) snprintf(err, errlen, "failed to read local generate logits"); + } else if (dist_discard_bytes(fd, res.logits_bytes) <= 0) { + if (errlen) snprintf(err, errlen, "failed to discard local generate logits"); goto cleanup; - } else if (final_logits_out && res.generated_count != 0) { - memcpy(final_logits_out, - logits_trace_out + (size_t)(res.generated_count - 1u) * (size_t)vocab, - (size_t)vocab * sizeof(final_logits_out[0])); } body -= res.logits_bytes; - if (logits_trace_steps_out) *logits_trace_steps_out = (int)res.generated_count; } + if (logits_trace_steps_out) *logits_trace_steps_out = (int)res.generated_count; if (body != 0 && dist_discard_bytes(fd, body) <= 0) { if (errlen) snprintf(err, errlen, "failed to discard trailing local generate bytes"); goto cleanup; @@ -8518,6 +8532,8 @@ static int dist_worker_handle_local_generate( const float temperature = dist_f32_from_bits(req.temperature_bits); const float top_p = dist_f32_from_bits(req.top_p_bits); const float min_p = dist_f32_from_bits(req.min_p_bits); + const bool want_logits_trace = + (req.flags & DS4_DIST_LOCAL_GENERATE_F_LOGITS_TRACE) != 0u; if (req.model_id != state->model_id || req.logits_bytes != logits_bytes) { dist_discard_bytes(upstream->fd, bytes - (uint32_t)sizeof(req)); snprintf(err, sizeof(err), "local generate request does not match worker state"); @@ -8544,7 +8560,7 @@ static int dist_worker_handle_local_generate( if (!err[0] && req.n_predict != 0) { tokens = malloc((size_t)req.n_predict * sizeof(tokens[0])); if (!tokens) snprintf(err, sizeof(err), "out of memory allocating generated tokens"); - if (!err[0]) { + if (!err[0] && want_logits_trace) { const uint64_t trace_values64 = (uint64_t)req.n_predict * (uint64_t)vocab; if (trace_values64 > SIZE_MAX / sizeof(float)) { snprintf(err, sizeof(err), "local generate logits trace is too large"); @@ -8596,6 +8612,14 @@ static int dist_worker_handle_local_generate( } const double t1 = dist_now_sec(); decode_usec = dist_usec_since(t0, t1); + if (!err[0]) { + if (!want_logits_trace && + generated != 0 && + ds4_session_copy_logits(session->session, logits, (int)vocab) != (int)vocab) { + snprintf(err, sizeof(err), "failed to copy final local generate logits"); + session->token_hash_valid = false; + } + } if (!err[0]) { session->token_hash = final_hash; session->token_hash_valid = true; @@ -8612,9 +8636,11 @@ static int dist_worker_handle_local_generate( err[0] ? token_hash : final_hash, tokens, generated, - logits_trace, - (uint32_t)((uint64_t)generated * (uint64_t)vocab * - sizeof(float)), + want_logits_trace ? logits_trace : logits, + want_logits_trace + ? (uint32_t)((uint64_t)generated * (uint64_t)vocab * + sizeof(float)) + : (generated != 0 ? logits_bytes : 0u), decode_usec, err[0] ? 1u : 0u, err); diff --git a/ds4_eval.c b/ds4_eval.c index 0ab6d67bc..dc8ad2a0f 100644 --- a/ds4_eval.c +++ b/ds4_eval.c @@ -3377,7 +3377,7 @@ static bool eval_can_use_local_decode_handoff(ds4_session *session, const eval_ui *ui, ds4_think_mode think_mode) { if (!session || !cfg) return false; - if (ui && ui->enabled) return false; + (void)ui; if (ds4_think_mode_enabled(think_mode)) return false; if (!ds4_session_is_distributed(session)) return false; if (cfg->dist.role != DS4_DISTRIBUTED_COORDINATOR) return false; @@ -3608,6 +3608,7 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, if (produced < 0) { free(tokens); plain_reset_color(use_plain_color); + ui->status[idx] = EVAL_FAILED; ui->generated_tokens[idx] = ui->generated; tui_run_clock_stop(ui); fprintf(stderr, "ds4-eval: distributed local-decode handoff failed for %s: %s\n", @@ -3633,7 +3634,9 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, ui->generated++; ui->generated_tokens[idx] = ui->generated; answer_tokens_generated++; - if (!tty) { + if (tty) { + stream_append_token_text(ui, text, len, false); + } else { fwrite(text, 1, len, stdout); fflush(stdout); } @@ -3641,7 +3644,9 @@ static eval_run_result run_one_case(ds4_engine *engine, ds4_session *session, if (tokens[i] == eos) break; } free(tokens); - if (!tty) { + if (tty) { + stream_append_token_text(ui, NULL, 0, true); + } else { plain_reset_color(use_plain_color); if (!raw.v || raw.len == 0 || raw.v[raw.len - 1] != '\n') fputc('\n', stdout); } diff --git a/tests/ds4_test.c b/tests/ds4_test.c index 3763c52a3..404bd6529 100644 --- a/tests/ds4_test.c +++ b/tests/ds4_test.c @@ -2503,6 +2503,199 @@ static void test_distributed_cli_parse(void) { ds4_dist_options_free(invalid); } +static bool test_distributed_env_enabled(void) { + const char *value = getenv("DS4_RUN_DISTRIBUTED_TEST"); + return value && value[0] && strcmp(value, "0") != 0; +} + +static int test_env_int_or(const char *name, int fallback) { + const char *value = getenv(name); + if (!value || !value[0]) return fallback; + char *end = NULL; + long parsed = strtol(value, &end, 10); + if (!end || *end != '\0' || parsed <= 0 || parsed > INT_MAX) return fallback; + return (int)parsed; +} + +static void test_distributed_local_decode_push(void) { +#ifdef DS4_NO_GPU + fprintf(stderr, "ds4-test: local-decode push skip (GPU support is not compiled in)\n"); + return; +#else + if (!test_distributed_env_enabled()) { + fprintf(stderr, + "ds4-test: local-decode push skip (set DS4_RUN_DISTRIBUTED_TEST=1 and run a worker for the configured coordinator listen host/port)\n"); + return; + } + + char err[256]; + const char *listen_host = getenv("DS4_TEST_DISTRIBUTED_LISTEN_HOST"); + if (!listen_host || !listen_host[0]) listen_host = "127.0.0.1"; + const int listen_port = test_env_int_or("DS4_TEST_DISTRIBUTED_LISTEN_PORT", 1234); + const int route_wait_ms = test_env_int_or("DS4_TEST_DISTRIBUTED_ROUTE_WAIT_MS", 30000); + const int route_wait_tries = route_wait_ms < 100 ? 1 : route_wait_ms / 100; + ds4_engine_options engine_opt = { + .model_path = test_model_path(), +#ifdef __APPLE__ + .backend = DS4_BACKEND_METAL, +#else + .backend = DS4_BACKEND_CUDA, +#endif + }; + ds4_dist_options dist_opt = { + .role = DS4_DISTRIBUTED_COORDINATOR, + .layers = { + .start = 0, + .end = 21, + .has_output = false, + .set = true, + }, + .listen_host = listen_host, + .listen_port = listen_port, + }; + const int prep_rc = ds4_dist_prepare_engine_options(&dist_opt, &engine_opt, err, sizeof(err)); + TEST_ASSERT(prep_rc == 0); + if (prep_rc != 0) { + fprintf(stderr, "ds4-test: local-decode push setup failed: %s\n", err); + return; + } + + ds4_engine *engine = NULL; + ds4_session *session = NULL; + ds4_tokens prompt = {0}; + ds4_distributed_route_info info = {0}; + char summary[256] = {0}; + + TEST_ASSERT(ds4_engine_open(&engine, &engine_opt) == 0); + if (!engine) return; + + TEST_ASSERT(ds4_session_create(&session, engine, 2048) == 0); + if (!session) { + ds4_engine_close(engine); + return; + } + + int route_rc = 0; + for (int i = 0; i < route_wait_tries; i++) { + route_rc = ds4_session_distributed_route_info(session, + &info, + summary, + sizeof(summary), + err, + sizeof(err)); + if (route_rc != 0) break; + usleep(100000); + } + if (route_rc != 1) { + fprintf(stderr, + "ds4-test: local-decode push skip (%s; listen=%s:%d wait_ms=%d)\n", + err[0] ? err : "distributed route is not ready", + listen_host, + listen_port, + route_wait_ms); + ds4_session_free(session); + ds4_engine_close(engine); + return; + } + + TEST_ASSERT(info.route_hops == 1); + TEST_ASSERT(info.local_decode_expected); + TEST_ASSERT(!info.local_decode_active); + + ds4_encode_chat_prompt(engine, + "", + "Reply with exactly one short word about distributed inference.", + DS4_THINK_NONE, + &prompt); + TEST_ASSERT(prompt.len > 0); + const int sync_rc = ds4_session_sync(session, &prompt, err, sizeof(err)); + TEST_ASSERT(sync_rc == 0); + if (sync_rc != 0) { + fprintf(stderr, "ds4-test: local-decode push sync failed: %s\n", err); + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); + return; + } + + int generated[4] = {0}; + double shard_load_sec = 0.0; + double decode_sec = 0.0; + const int produced = ds4_session_distributed_handoff_argmax(session, + 2, + generated, + 4, + &shard_load_sec, + &decode_sec, + err, + sizeof(err)); + TEST_ASSERT(produced > 0); + if (produced <= 0) { + fprintf(stderr, "ds4-test: local-decode push handoff failed: %s\n", err); + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); + return; + } + + route_rc = ds4_session_distributed_route_info(session, + &info, + summary, + sizeof(summary), + err, + sizeof(err)); + TEST_ASSERT(route_rc == 1); + TEST_ASSERT(info.local_decode_active); + TEST_ASSERT(shard_load_sec > 0.0); + TEST_ASSERT(decode_sec >= 0.0); + + const int forced = ds4_session_argmax(session); + TEST_ASSERT(forced >= 0); + const int eval_rc = ds4_session_eval(session, forced, err, sizeof(err)); + TEST_ASSERT(eval_rc == 0); + if (eval_rc != 0) { + fprintf(stderr, "ds4-test: local-decode push reuse eval failed: %s\n", err); + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); + return; + } + + int second_token = -1; + double second_shard_sec = 0.0; + double second_decode_sec = 0.0; + const int produced_second = ds4_session_distributed_handoff_argmax(session, + 1, + &second_token, + 1, + &second_shard_sec, + &second_decode_sec, + err, + sizeof(err)); + TEST_ASSERT(produced_second == 1); + TEST_ASSERT(second_shard_sec > 0.0); + TEST_ASSERT(second_decode_sec >= 0.0); + + fprintf(stderr, + "ds4-test: local-decode push pass listen=%s:%d route=\"%s\" hops=%u local_decode_active=%s first_handoff=%d reuse_eval=%d second_handoff=%d kv=%.3fs decode=%.3fs decode2=%.3fs\n", + listen_host, + listen_port, + summary, + info.route_hops, + info.local_decode_active ? "yes" : "no", + produced, + forced, + produced_second, + shard_load_sec, + decode_sec, + second_decode_sec); + + ds4_tokens_free(&prompt); + ds4_session_free(session); + ds4_engine_close(engine); +#endif +} + typedef void (*test_fn)(void); typedef struct { @@ -2526,6 +2719,7 @@ static const ds4_test_entry test_entries[] = { #endif {"--server", "server", "server parser/rendering/cache unit tests", test_server_unit_group}, {"--dist-cli-parse", "dist-cli-parse", "distributed CLI parsing and --local-decode validation", test_distributed_cli_parse}, + {"--local-decode-push", "local-decode-push", "distributed worker-owned local-decode handoff smoke (skips unless DS4_RUN_DISTRIBUTED_TEST=1)", test_distributed_local_decode_push}, }; static void test_print_help(const char *prog) { @@ -2550,6 +2744,10 @@ static void test_print_help(const char *prog) { puts(" DS4_TEST_VECTOR_FILE=FILE Simple official-vector fixture."); puts(" DS4_TEST_LOCAL_GOLDEN_FILE=FILE Local top-k golden-vector fixture."); puts(" DS4_TEST_MPP_EQ_CASE=NAME Run only Tensor equivalence cases whose id contains NAME."); + puts(" DS4_RUN_DISTRIBUTED_TEST=1 Enable the local-decode push smoke."); + puts(" DS4_TEST_DISTRIBUTED_LISTEN_HOST=HOST Coordinator listen host for --local-decode-push. Default: 127.0.0.1"); + puts(" DS4_TEST_DISTRIBUTED_LISTEN_PORT=PORT Coordinator listen port for --local-decode-push. Default: 1234"); + puts(" DS4_TEST_DISTRIBUTED_ROUTE_WAIT_MS=N Route wait budget for --local-decode-push. Default: 30000"); } static const ds4_test_entry *test_find_entry(const char *arg) {