The Moment of Truth: Parsing the Torch.Profiler Output for Kimi-K2.5 INT4 on Blackwell
Introduction
In any performance optimization campaign, there comes a pivotal moment when speculation meets measurement — when the hypotheses formed during hours of micro-benchmarking and architectural reasoning are either confirmed or shattered by the cold, hard numbers from a full-system profiler. Message [msg 2447] in this opencode session represents exactly that moment. It is the execution of a custom Python analysis script (analyze_k25_profile.py) that parses the raw torch.profiler output from a live vLLM inference server running the 1-trillion-parameter Kimi-K2.5 INT4 model across 8 NVIDIA RTX PRO 6000 Blackwell GPUs. The message itself is deceptively simple — a single bash command and its truncated output — but it sits at the convergence of a multi-hour, multi-phase benchmarking effort that spanned macro-level throughput tests, micro-benchmarks of individual GEMM operations, NCCL AllReduce burst measurements, and finally this full torch.profiler capture. Understanding what this message reveals, and why it was written, requires tracing the reasoning chain that led to it and appreciating the assumptions that were overturned by its output.
Context and Motivation: Why This Message Was Written
The message was written as the final step in a three-phase profiling campaign. The session's trajectory is essential context. Earlier in the conversation, the assistant and user had been wrestling with the performance characteristics of deploying massive Mixture-of-Experts (MoE) models — first GLM-5-NVFP4, then Kimi-K2.5-NVFP4, and finally Kimi-K2.5 INT4 — on a system with 8x RTX PRO 6000 Blackwell GPUs connected only via PCIe (no NVLink). The initial hypothesis, formed during the GLM-5 deployment, was that the primary bottleneck was the tiny expert GEMMs caused by aggressive tensor parallelism (TP=8) sharding. When an expert's intermediate dimension of 2048 is split across 8 GPUs, each GPU only computes a 256-wide matrix multiplication — far too small to saturate the massive compute throughput of a Blackwell GPU. This "tiny GEMM problem" dominated the team's thinking.
The user had specifically asked about overlapping allreduce with compute, and the assistant had researched disaggregated prefill and data parallelism options. The working theory was that communication overhead was secondary to the compute inefficiency of small matrix multiplications. This led to an extensive investigation of SM120 GEMM optimization strategies: Marlin W4A16 kernels, L2 cache pinning, persistent fused kernels, and column-major tile scheduling. The team even wrote custom micro-benchmarks at exact Kimi-K2.5 dimensions to measure individual GEMM latencies.
But something didn't add up. The macro benchmarks showed a throughput plateau at ~1,536 tok/s at concurrency 128, with single-stream TPOT around 12.1ms. The micro-benchmarks showed individual GEMMs completing in microseconds. The NCCL AllReduce burst measurements showed 6.81ms total for 122 operations at batch=1. The pieces were there, but no one had assembled them into a coherent picture of where the decode step time was actually going. That required the torch.profiler — the definitive tool that captures every CUDA kernel launch and its duration across all GPUs.
What the Message Contains
The message shows the output of running python3 /home/theuser/glm-kimi-sm120-rtx6000bw/analyze_k25_profile.py. The script was written in the preceding message ([msg 2446]) to parse the raw profiler summary files that were retrieved from the remote server in [msg 2445]. The raw profiler data consisted of eight .pt.trace.json.gz files (one per GPU rank, each ~80MB) and corresponding profiler_out_*.txt summary files.
The output header reveals the key aggregate statistics:
KIMI-K2.5 INT4 TORCH.PROFILER ANALYSIS
Total Self CUDA time: 3.050s
Estimated decode steps: ~155
Per-step CUDA time: 19.7ms
Total leaf kernel time: 3.363s
Per decode step: 21.7ms
The script then produced a category breakdown table that was truncated in the conversation data but whose contents can be reconstructed from the subsequent analysis in [msg 2448] and the chunk summary. The categories included:
- allreduce: The dominant category
- Marlin (W4A16 GEMM): The weight computation kernels
- Attention (MLA): Multi-head latent attention
- RMSNorm, RoPE, Silu: Element-wise operations
- Other: Remaining operations The critical finding was that AllReduce accounted for 51.5% of decode time — 11.17ms per step out of a total ~21.7ms. This was a stunning reversal of the working hypothesis.
The Thinking Process Visible in the Message
The message itself is a tool call — a bash command — but the thinking behind it is visible in the surrounding context. The assistant had spent considerable effort setting up the profiler capture. In [msg 2428], it launched vLLM with --profiler-config specifying a torch.profiler configuration. This required restarting the service (which took ~30 minutes to load the 540GB model), waiting through the weight loading phase (monitored across [msg 2437] through [msg 2441]), and then carefully orchestrating the profiling sequence in [msg 2443]: warmup requests, starting the profiler, sending decode requests at batch=1, and stopping the profiler.
The script analyze_k25_profile.py was written in [msg 2446] specifically to parse the profiler output. The assistant recognized the raw profiler tables as "gold" and immediately wrote a parser to extract structured insights. The script's design reflects specific analytical choices: it groups kernel events into semantic categories (allreduce, Marlin, attention, etc.), estimates the number of decode steps from the profiler trace, and computes per-step timing breakdowns. This categorization required deep knowledge of the vLLM execution pipeline — knowing which CUDA kernels correspond to which model operations.
Assumptions Made and Mistakes Revealed
The most significant assumption overturned by this message was that the primary bottleneck was the tiny expert GEMMs. The entire earlier phase of the session — the research into SM120 GEMM optimization, the column-major tile scheduling, the persistent fused kernel designs — was driven by this hypothesis. The profiler data showed that Marlin W4A16 kernels (the quantized GEMM implementation) were not the dominant cost. In fact, the Marlin kernels were performing efficiently, having eliminated the dtype-cast overhead that had plagued the earlier GLM-5 NVFP4 deployment. The real bottleneck was communication.
A secondary assumption was that NCCL AllReduce would be fast enough on PCIe Gen5. The micro-benchmarks in [msg 2426] had shown individual NCCL AllReduce calls taking ~78μs for the 14KB hidden_size messages. But the profiler revealed that 127 allreduce calls per decode step, each at 78μs, accumulate to ~9.9ms — and when combined with the slower vllm::all_reduce custom path (at 1,125μs per call for larger messages), the total allreduce cost reached 11.17ms per step. The PCIe bottleneck, which had been acknowledged but perhaps underestimated, was now quantified with precision.
The assistant also assumed that the custom vllm::all_reduce IPC-based path would be faster than NCCL for small messages — a common optimization. The profiler showed the opposite: at 1,125μs per call, it was 14× slower than NCCL's 78μs. This counterintuitive finding suggested either a configuration issue (e.g., using a suboptimal NCCL protocol) or a fundamental limitation of the IPC shared-memory approach on this particular system topology.
Input Knowledge Required
To understand this message, one needs knowledge of several domains. First, the architecture of Mixture-of-Experts transformer models: how MoE layers route tokens through expert networks, how tensor parallelism shards both attention and expert computations across GPUs, and how allreduce synchronizes gradients/hidden states between devices. Second, the vLLM inference engine architecture: its V1 engine, CUDAGraph compilation, and the custom allreduce implementations it uses. Third, CUDA profiling methodology: what torch.profiler captures, how to interpret CUDA kernel timing, and the distinction between "Self CUDA time" (time spent in the kernel itself) versus "CUDA total" (including child CUDA operations). Fourth, the hardware constraints of PCIe-only multi-GPU systems: the bandwidth limitations, the lack of NVLink's direct peer-to-peer transfers, and the implications for collective communication patterns.
Output Knowledge Created
This message created definitive, quantified knowledge about the Kimi-K2.5 INT4 inference bottleneck on this specific hardware configuration. Before this message, the team had hypotheses and micro-benchmark data but no unified picture. After this message, they knew with certainty that:
- AllReduce is the dominant bottleneck at 51.5% of decode time (11.17ms per step).
- The Marlin W4A16 kernels are not the problem — they eliminated the dtype-cast overhead and are performing well.
- The custom vllm::all_reduce path is unexpectedly slow at 1,125μs per call versus NCCL's 78μs.
- The per-step CUDA time (21.7ms) exceeds the measured TPOT (12.1ms) — indicating that CUDAGraph overlapping of compute and communication is partially masking the true cost, but the gap also suggests that the profiler captures all CUDA operations across streams while the end-to-end latency only measures the critical path. This knowledge directly informed the next phase of the session: the pivot to speculative decoding as a software-only optimization path. Since the bottleneck was communication-bound by PCIe allreduce, and hardware changes (adding NVLink) were not feasible, the only remaining lever was to reduce the number of decode steps per token — which is exactly what speculative decoding does by using a smaller draft model to generate multiple candidate tokens per forward pass.
Conclusion
Message [msg 2447] represents the analytical climax of a long profiling campaign. It is the moment when data supersedes hypothesis, when the carefully constructed narrative about tiny GEMM bottlenecks collapses under the weight of empirical measurement. The message itself — a script execution with truncated output — is unremarkable in isolation, but in context it is the fulcrum on which the entire optimization strategy pivots. It demonstrates a fundamental principle of systems performance work: measure before optimizing, and be prepared for the measurements to contradict your assumptions. The assistant's response in the following message ([msg 2448]) shows immediate, detailed analysis of the findings, confirming that the message achieved its purpose of transforming raw profiler data into actionable insight. The subsequent pivot to speculative decoding, documented in the chunk summary, was a direct consequence of the knowledge created by this single message.