the path · 0/15
start the path

the kernel path · The machines · lesson 06 of 9

XProf, and the three accounts

The profiler is how prediction meets the machine, and a program has three cost tellings that this site once caught disagreeing in public.

the goal Capture a trace both ways, then rank the cost model, the rooflineThe floor model: latency is at least the larger of FLOPs over peak compute and bytes over bandwidth. Predict first, measure second.taught in /l/tpu →, and the timeline by trustworthiness for the question you are asking.

mastery work · this chapter0/2
  1. go →
manual items are your word; auto items complete from your streaks, labs, and can-you ticks · stored in your browser only
§ 01

XProf, the whole instrument

XProf is the profiler for the whole XLAThe compiler: brilliant at fusing along dataflow edges, structurally unable to change your algorithm. That gap is why kernels exist.taught in /l/xla → stack: a capture library wired into jax, plus a viewer that renders what it caught. You reach it two ways. Programmatically, jax.profiler.trace writes a capture you can parse in code, which is how this course uses it. Interactively, the TensorBoard profile plugin (now the standalone xprof project) opens the same capture as a set of tools, each built to answer one kind of question.

Know the tools by the question each answers. The overview page answers where the step went: device compute, input pipeline, or host. The trace viewer is the timeline itself, every op on every plane against time: overlap and bubbles live here, and GYM·08 is a reading of exactly this pane's data. The op profile is the league table: time by op and category, which five ops actually matter. The memory tools answer OOM forensics: allocation over time, and which buffer owns the peak. The graph viewer is the compiled HLO, clickable. Newer builds add a rooflineThe floor model: latency is at least the larger of FLOPs over peak compute and bytes over bandwidth. Predict first, measure second.taught in /l/tpu → view that places each op against the machine's ceiling automatically, which is stage 0's discipline as a built-in pane.

The routing table, by symptom: a slow step starts at the overview page. Low MXUThe systolic matmul array: 128x128 on v5e, 256x256 on v6e. Matmuls only; everything else is the VPU’s job.taught in /l/tpu → utilization goes to the op profile, then the trace viewer to find the bubbles between compute. An OOM goes to the memory viewer. An op you cannot explain goes to the graph viewer, and if it is a custom call, to this course's museum of reasons the models cannot see inside it. Multi-chip timing questions go to the pod tools, which is gate 04 country.

§ 02

Reading the machine's own account

Everything before this section predicts; this section checks. The whole rooflineThe floor model: latency is at least the larger of FLOPs over peak compute and bytes over bandwidth. Predict first, measure second.taught in /l/tpu → discipline earns its keep only when you can hold the prediction next to what the machine actually did, and the machine keeps an account: the profiler's device timeline, one timed event per op, straight from the hardware. Capturing it costs four lines. Compile outside the trace window, run enough steady-state iterations to swamp noise, and read the xplane files that land.

the capture pattern, verified on v6e-1 by LAB·2.3: compile outside, trace steady state
# capture: compile OUTSIDE the window, then trace steady-state iterations
fn = jax.jit(naive_attention)
fn(*xs).block_until_ready()

with jax.profiler.trace("/tmp/xprof-run"):
    for _ in range(20):
        fn(*xs).block_until_ready()

# what lands: plugins/profile/<run>/<host>.xplane.pb, one per host

The working loop has four beats, and the order is the discipline. Predict the number from constants first, the way stage 0 drills. Profile to get the machine's account. Attribute the gap op by op: an unattributed gap is a guess wearing a number. Then change exactly one thing and measure again. Every optimization story this site tells, from the dimension_semantics retune to the byte-confirm, is this loop run honestly.

the loop this whole course runs: the attribute beat is the one people skip, and skipping it turns the rest into guessing
predict from chip constantsbefore any run profile capture the devicetimeline, steady state attribute the gap, op by opnamed, not guessed fix one thing measure again: the loop is the method an unattributed gap is a guess wearing a number
§ 03

The three accounts, and when each lies

A program's cost has three tellings, and this site caught them disagreeing in public. The first is the cost model: compiled.cost_analysis() returns XLAThe compiler: brilliant at fusing along dataflow edges, structurally unable to change your algorithm. That gap is why kernels exist.taught in /l/xla →'s own estimate of flops and bytes, instantly, with no hardware. It said naive attention at seq 8192 moves 155.2 MB. The second is the round-trip arithmetic from chapter 04: the score matrix written and read is 276.8 MB with I/O. Nearly a factor of two apart, and both cannot be right.

The third account settled it. The device timeline put 217.6 µs of hardware time on the two ops that carry the score matrix, and time converts to bytes through bandwidth. Not nameplate bandwidth: no real stream hits the datasheet ceiling. A pure 1 GB copy measured this chip at 1287.5 GB/s, 80.5% of nameplate, and at that achieved rate 217.6 µs is 280.2 MB. The estimate said 276.8. Agreement within 1.2%, and the cost model's 155.2 turned out to be an artifact: it cannot see inside custom calls.

three tellings of the same program, with the numbers this site measured: the models argue, the hardware referees
the cost model compiled.cost_analysis()said 155.2 MBblind inside custom calls the device timeline hardware time, per op217.6 µs on the S opstruth for time, not bytes achieved bandwidth a pure 1 GB copy, timed1287.5 GB/s = 80.5%of the nameplate ceiling excluded: cannot see the custom call time × achieved rate 280.2 MB vs 276.8 estimatedagreement within 1.2% gate 02, closed by this arithmetic · rows M-018 to M-023 on the bench

Why was there a custom call inside a program made of jnp ops? Because the timeline held a surprise worth the whole exercise: XLAThe compiler: brilliant at fusing along dataflow edges, structurally unable to change your algorithm. That gap is why kernels exist.taught in /l/xla →:TPU had pattern-matched the softmax and second matmul and dispatched its own kernel, named %online-softmax in the timeline, tiled 1024,1024. The compiler recognized a famous shape and swapped in a hand-written crossing. Recognition, not derivation: chapter 05 draws that line precisely, and this trace is its best evidence.

before you move on

Check yourself

01 What are the three accounts of a program, and which one arbitrates?

The cost model from compiled.cost_analysis(), the roofline prediction, and the measured timeline. The timeline arbitrates: the first two predict, the device plane records what ran.

02 What are the two ways to reach XProf?

Programmatically, wrapping the code you care about with the capture API, and interactively through the profiler UI; both land in the same viewer.

assigned

Readings