feat(analyzer): surface TTFT/TPOT as features and CDF figures
The gateway records three epoch-ms stamps per request (admitted, forwarded to backend, backend first token). They reached *-raw.jsonl but stopped there: features.csv had only total latency, and none of the figures covered time-to-first-token. Derive ttft_ms, ttft_e2e_ms and tpot_ms in one helper shared by the streaming path (preparation.py) and the in-memory path (features.py) so the two cannot drift, and add figures 14 (TTFT, backend vs end-to-end) and 15 (TPOT). The two TTFT series are plotted together because their offset is the gateway admission delay, which is then readable straight off the chart. Rows missing a backend stamp and single-token responses are recorded as 0 and filtered at plot time; left in, they would stack at the origin and pull every percentile down. Figure 15 is a single panel: TPOT is near-deterministic (p50 21.9, p90 23.0), so a p90 zoom renders a flat line and a vertical edge. Verified by recomputing ttft_ms straight from the original SLS rows for all 2190 requests of a sample: 0 mismatches. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from collections import Counter
|
||||
from dataclasses import asdict
|
||||
|
||||
from .helpers import percentile, safe_div
|
||||
from .helpers import latency_breakdown, percentile, safe_div
|
||||
from .models import TraceFeatures
|
||||
|
||||
LONG_CONTEXT_THRESHOLD = 32000
|
||||
@@ -75,6 +75,7 @@ def compute_features(records):
|
||||
high_cache=1 if cache_hit_ratio >= HIGH_CACHE_THRESHOLD else 0,
|
||||
tool_burst_alert=1 if (max(bursts) if bursts else 0) >= TOOL_BURST_THRESHOLD else 0,
|
||||
tool_loop_alert=1 if tool_to_tool_count >= TOOL_LOOP_THRESHOLD else 0,
|
||||
**latency_breakdown(record.meta, output_tokens),
|
||||
)
|
||||
feature.pattern_labels = base_pattern_labels(feature)
|
||||
features.append(feature)
|
||||
|
||||
Reference in New Issue
Block a user