New analysis/characterization/elastic_migration_v2/ packages the
unified_v2 + unified_kv_both experiments into a self-contained
results section that the paper can cite as the "we tried selective
PD-sep migration" case study. The section finds three independent
reasons PD-sep doesn't help on agentic w600:
1. Mooncake kv_both substrate alone (no PD-sep ever firing) imposes
TTFT p90 +45%, TPOT p90 +25%, hotspot index +19% vs plain
unified. Per-step KVConnectorMetadata maintenance and block
reservation semantics dominate even when no transfer is pending.
2. PD-sep gate fires only 0.16-0.41% of requests across two
gate-tightness configurations. 88-76% are killed by
new_local < threshold because 93% intra-session reuse on agentic
traces leaves a small uncached tail; 19% are killed by
chosen_no_active_decode (snapshot-time gate). Even relaxed
thresholds can't grow trigger rate past 0.5%.
3. When PD-sep fires, the calibrated cost model
(0.3s + bytes / 2.7 GB/s) is wrong by 10-20x. 5 triggered
requests in v2.1 saw realized TTFT 12-45s vs model-predicted
migrate cost 0.7-2.2s, consistent with the E2 audit's finding
that D-side block pre-reservation and missing layerwise
pipelining dominate the decode_sent -> first_token clock.
Three-way comparison (unified vs unified_kv_both vs unified_v2):
v2 vs the kv_both control is roughly net-zero (-10% hotspot,
-14% TPOT p90, +3% TTFT p90, +9% TTFT p99). v2 vs plain unified is
strictly worse by 27-49% across latency percentiles because the
kv_both substrate tax is unavoidable when the policy is enabled.
Contents:
- README.md: the four results sections, the three-way comparison
table, an explicit "what this claims for the paper" list, and a
cross-reference index to the earlier characterization documents.
- data/: b3_policy_comparison.json + per-policy breakdown.json
+ per-policy hotspot_index.json for the four policies in scope.
- figures/: 4 PNGs rendered by render_figures.py:
* fig_kv_both_overhead.png — 4-metric bar chart with delta
annotations showing kv_both alone costs +45% TTFT p90.
* fig_v2_trigger_funnel.png — per-reason request count for the
two gate configurations on log scale.
* fig_v2_predicted_vs_actual.png — scatter of model-predicted
migrate cost vs realized TTFT for the 5 triggered requests,
with y=x, 10x, and 20x reference lines.
* fig_three_way_hotspot.png — per-worker TTFT p90 grouped bars
across the three policies.
The section is intentionally self-contained: it lists what the
experiment validates (cost model picks correct candidates;
shadow-drift fix is necessary; same-worker interference is real)
alongside what it disproves (per-request PD-sep on agentic via
Mooncake is not a net win in current implementation).
Refs: E1/E2 subagent audits, B2 microbench, unified_v2 commits
19f69a9 / 4b833d3 / 95c8ef8.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Characterization Analyzer Runbook
CPU-only scaffold for Batch 0 and Batch 1 in
analysis/characterization_todo_for_interns.md.
This directory has three components:
analyze.py: Batch 0/1 analyzer for trace and per-request metrics.summarize_runs.py: CPU-only audit of already completed benchmark directories.protocols.md: exact protocol for Batch 2-6 experiments that require fresh GPU runs or additional instrumentation.
The analyzer reads existing trace and metrics artifacts and writes:
outputs/characterization/<date>/<task_name>/
├── manifest.json
├── raw/
├── summary.json
├── summary.md
├── audit.md
├── session_concurrency.json
├── session_arrival_stats.json
├── turn_interval_stats.json
├── trace_profile.json
├── invalid_runs.md
├── workload_summary.json
├── kv_footprint_summary.json
├── reuse_decomposition.json
├── session_skew.json
├── append_delta_stats.json
└── figures/
If matplotlib is installed, simple PNG/PDF figures are emitted under
figures/. If it is not installed, all JSON/Markdown data artifacts are still
written.
Canonical Data Sources
Canonical full traces live on dash0:
- formatted trace:
~/ali-trace/trace-glm5.1-formatted/ - raw unformatted trace:
~/ali-trace/trace-glm5.1/
For the current GLM-5.1 characterization, prefer the compact formatted file:
~/ali-trace/trace-glm5.1-formatted/051315-051317.jsonl
Do not pass 051315-051317-raw.jsonl or the files under
~/ali-trace/trace-glm5.1/ directly to this analyzer unless you first convert
them to the formatted schema. Those raw files are tens to hundreds of GiB and
contain full prompt payloads rather than the compact characterization schema.
The analyzer is CPU-only. For full trace characterization, either:
- run it on dash0 against the formatted JSONL files without starting any GPU service; or
- copy/rsync the needed trace files from dash0 to this repository or another local path, then run the analyzer locally.
Only light directory/field inspection is needed on dash0 before choosing which trace file to analyze.
The raw unformatted directory is listed as a source option for provenance, but
this analyzer expects formatted JSONL records. Raw files should be converted to
the formatted schema before being passed to --trace.
Inputs
Trace JSONL:
- Expected formatted fields:
chat_id,parent_chat_id,timestamp,input_length,output_length,type,turn,hash_ids, optionalsession_id. - If
session_idis absent, sessions are reconstructed fromparent_chat_idchains. timestampis treated as scheduled trace time, not proof of actual dispatch time.
Metrics JSONL:
- Expected replayer fields:
request_id,session_id,turn_id,trace_timestamp_s,input_length,output_length,cached_tokens,latency_s,ttft_s,tpot_s,actual_output_tokens,error. - If the metrics file is from the current replayer, it does not include actual
dispatch/finish wall-clock timestamps. Batch 0 will therefore mark actual
session sequentiality as unavailable and separately report a scheduled
estimate from
trace_timestamp_s + latency_s.
Proxy breakdown:
- Optional JSON/JSONL with fields such as
request_id,t_proxy_recv,t_first_token,t_done,cache_hit,estimated_new_tokens,route_class,routed_to,policy. - Batch 0 can prove actual per-session in-flight concurrency only when these
timing rows can be joined to analyzed requests by
request_id. - Existing proxy breakdown artifacts may not contain
session_id; without a request-id join to trace/metrics, they can still support append/cache-hit statistics but not per-session concurrency.
Run config:
- Optional JSON, usually
outputs/<run>/config.json. - Used for manifest fields such as
policy,time_scale, and request count when available.
Commands
Trace-only dry run:
python3 analysis/characterization/analyze.py \
--trace traces/w600_r0.0015_st30.jsonl \
--task-name w600_trace_only \
--overwrite
Trace plus replayer metrics:
python3 analysis/characterization/analyze.py \
--trace traces/w600_r0.0015_st30.jsonl \
--metrics outputs/smoke_test/metrics.jsonl \
--task-name smoke_trace_metrics \
--overwrite
Proxy breakdown append/cache analysis:
python3 analysis/characterization/analyze.py \
--breakdown outputs/contention_16s_elastic/breakdown.json \
--config outputs/contention_16s_elastic/config.json \
--task-name contention_breakdown \
--overwrite
Full trace on dash0, CPU-only:
python3 analysis/characterization/analyze.py \
--trace ~/ali-trace/trace-glm5.1-formatted/051315-051317.jsonl \
--task-name full_trace_characterization \
--overwrite
Local run after copying from dash0:
rsync -av dash0:~/ali-trace/trace-glm5.1-formatted/<trace-file>.jsonl traces/
python3 analysis/characterization/analyze.py \
--trace traces/<trace-file>.jsonl \
--task-name full_trace_characterization \
--overwrite
By default the analyzer records file size and mtime but skips full SHA256
hashing, because canonical raw trace files can be hundreds of GiB. Add
--hash-inputs only when you intentionally want a full file hash.
KV footprint requires a model-specific value:
python3 analysis/characterization/analyze.py \
--trace traces/w600_r0.0015_st30.jsonl \
--kv-bytes-per-token 98304 \
--task-name w600_with_kv_estimate \
--overwrite
Summarize existing completed runs:
python3 analysis/characterization/summarize_runs.py
This writes:
analysis/characterization/current_results/
├── run_summaries.json
├── comparisons.json
├── claim_matrix.json
├── reviewer_risk_register.json
├── current_results.md
├── characterization_claim_matrix.md
├── all_figures_index.md
├── reviewer_risk_register.md
└── reproduction_commands.sh
Batch 0 Semantics
The online-serving invariant is:
Each session has at most one in-flight turn.
The analyzer reports:
- actual interval status from dispatch and finish/error timestamps;
- scheduled estimate from trace timestamps plus latency when available;
- per-session max in-flight;
- session start-time distribution;
- turn inter-arrival distribution;
- attempted/completed/error counts and goodput when metrics exist;
- run classification.
Important limitation: trace timestamps alone cannot prove actual replay
sequentiality. A run is only classified as online_realistic when actual
per-request dispatch and finish/error timestamps prove
max_inflight_per_session <= 1.
Batch 1 Semantics
The analyzer reports:
- input/output CDF stats;
- input/output ratio;
- KV footprint CDF stats when
--kv-bytes-per-tokenis supplied; - session skew and top-session contribution;
- append/uncached token stats when
cached_tokensorcache_hitexists; - reuse decomposition when both cached-token fields and
hash_idsexist.
Reuse decomposition is conservative:
intra_session: cached hash block was seen earlier in the same session;cross_session: cached hash block was seen earlier in another session;shared/system-prefix: early-position block appears in many sessions;unclassified: cached tokens could not be mapped to a previously seen hash block.
If cached-token/cache-hit fields are absent, reuse and append artifacts are
written with status: "unavailable" and list the required fields.
Limitations
- The script does not run a benchmark, query a live service, touch GPU state, or start any daemon.
- Request-id joins are exact. If trace, metrics, and proxy artifacts use
different request IDs, the unmatched rows are preserved under
raw/. - Actual Batch 0 sequentiality needs actual dispatch and finish/error
timestamps. Current
replayer/metrics.pymetrics are not enough by themselves. kv_bytes_per_tokendepends on model architecture, layer count, KV heads, head dimension, and dtype. The analyzer will not guess it.- Shared/system-prefix reuse classification is a heuristic based on trace
hash_idspositions and cross-session frequency. Adjust--shared-prefix-min-sessionsand--system-prefix-blocksif the formatted trace provides a stronger system-prefix marker.