xla floor
serves xla-path chapters 04 · 05 · 08 · 10 · streaks check themselves off; the same skill counts on every floor that drills it · all floors
The compiler's decisions, drilled.
The xla path teaches you to read what the compiler did and why. These stations hold the evidence: decisions the framework made silently, fusion plans captured from a real TPU compile, and a hardware profile with an op nobody in the program wrote. Everything here is generated or captured, never retyped.
Active recall, one tap
click the first line where the framework makes a hidden broadcast explicit
program: mlp
add-random-host-offloadingwhich pipeline filed this one?
cpu: jax 0.4.38, CPU, the course machine · tpu: jax 0.11, Colab TPU v6e, LAB·X2 and LAB·X4
y = jnp.exp(x)how many fusion computations does the optimized module hold?
counted on cpu, jax 0.4.38 · a different backend draws these boundaries differently, which is the point of reading your own dump rather than trusting a rule
after
Fusion, side by side
The StableHLO XLA received on the left, the optimized HLO it decided on the right, captured on a real TPU. Fusion ops light up in copper, and the lines still carrying each program's big intermediate are underlined: in the attention program that is the spill, sitting in the compiler's own plan. Chapter 05 teaches the policy that drew these boundaries.
find the fusion ops that carry bf16[1024,1024]: the spill, in the compiler's own plan
module @jit_naive_attention attributes {mhlo.num_partitions = 1 : i32, mhlo.num_replicas = 1 : i32} { func.func public @main(%arg0: tensor<1024x128xbf16>, %arg1: tensor<1024x128xbf16>, %arg2: tensor<1024x128xbf16>) -> (tensor<1024x128xbf16> {jax.result_info = "result"}) { %0 = stablehlo.transpose %arg1, dims = [1, 0] : (tensor<1024x128xbf16>) -> tensor<128x1024xbf16> %1 = stablehlo.dot_general %arg0, %0, contracting_dims = [1] x [0], precision = [DEFAULT, DEFAULT] : (tensor<1024x128xbf16>, tensor<128x1024xbf16>) -> tensor<1024x1024xbf16> %cst = stablehlo.constant dense<0xFF80> : tensor<bf16> %2 = stablehlo.reduce(%1 init: %cst) applies stablehlo.maximum across dimensions = [1] : (tensor<1024x1024xbf16>, tensor<bf16>) -> tensor<1024xbf16> %3 = stablehlo.broadcast_in_dim %2, dims = [0] : (tensor<1024xbf16>) -> tensor<1024x1xbf16> %4 = stablehlo.broadcast_in_dim %3, dims = [0, 1] : (tensor<1024x1xbf16>) -> tensor<1024x1024xbf16> %5 = stablehlo.subtract %1, %4 : tensor<1024x1024xbf16> %6 = stablehlo.exponential %5 : tensor<1024x1024xbf16> %7 = stablehlo.convert %6 : (tensor<1024x1024xbf16>) -> tensor<1024x1024xf32> %cst_0 = stablehlo.constant dense<0.000000e+00> : tensor<f32> %8 = stablehlo.reduce(%7 init: %cst_0) applies stablehlo.add across dimensions = [1] : (tensor<1024x1024xf32>, tensor<f32>) -> tensor<1024xf32> %9 = stablehlo.broadcast_in_dim %8, dims = [0] : (tensor<1024xf32>) -> tensor<1024x1xf32> %10 = stablehlo.convert %9 : (tensor<1024x1xf32>) -> tensor<1024x1xbf16> %11 = stablehlo.broadcast_in_dim %10, dims = [0, 1] : (tensor<1024x1xbf16>) -> tensor<1024x1024xbf16> %12 = stablehlo.divide %6, %11 : tensor<1024x1024xbf16> %13 = stablehlo.dot_general %12, %arg2, contracting_dims = [1] x [0], precision = [DEFAULT, DEFAULT] : (tensor<1024x1024xbf16>, tensor<1024x128xbf16>) -> tensor<1024x128xbf16> return %13 : tensor<1024x128xbf16> } }
HloModule jit_naive_attention, is_scheduled=true, entry_computation_layout={(bf16[1024,128]{1,0:T(8,128)(2,1)}, bf16[1024,128]{1,0:T(8,128)(2,1)}, bf16[1024,128]{1,0:T(8,128)(2,1)})->bf16[1024,128]{1,0:T(8,128)(2,1)}}, allow_spmd_sharding_propagation_to_parameters={true,true,true}, allow_spmd_sharding_propagation_to_output={true}, frontend_attributes={arg_layout_modes="default;default;default",arg_memory_spaces="0;0;0",out_layout_modes="default",out_memory_spaces="0"} %bitcast_fusion (bitcast_input: bf16[1024,128]) -> bf16[1024,128] { %bitcast_input = bf16[1024,128]{1,0:T(8,128)(2,1)S(1)} parameter(0) ROOT %bitcast = bf16[1024,128]{1,0:T(8,128)(2,1)} bitcast(%bitcast_input) } %bitcast_fusion.1 (bitcast_input.1: bf16[1024,128]) -> bf16[1024,128] { %bitcast_input.1 = bf16[1024,128]{1,0:T(8,128)(2,1)} parameter(0) ROOT %bitcast.1 = bf16[1024,128]{1,0:T(8,128)(2,1)} bitcast(%bitcast_input.1) } %fused_computation (param_0: bf16[1024,128], param_1: bf16[1024,128]) -> bf16[1024,1024] { %param_0 = bf16[1024,128]{1,0:T(8,128)(2,1)S(1)} parameter(0) %fusion.1 = bf16[1024,128]{1,0:T(8,128)(2,1)} fusion(%param_0), kind=kLoop, calls=%bitcast_fusion %param_1 = bf16[1024,128]{1,0:T(8,128)(2,1)} parameter(1) %fusion.2 = bf16[1024,128]{1,0:T(8,128)(2,1)} fusion(%param_1), kind=kLoop, calls=%bitcast_fusion.1 ROOT %convolution.1 = bf16[1024,1024]{1,0:T(8,128)(2,1)S(1)} convolution(%fusion.1, %fusion.2), dim_labels=bf_oi->bf, metadata={op_name="jit(naive_attention)/dot_general" stack_frame_id=20} } ENTRY %main.3 (q.1: bf16[1024,128], k.1: bf16[1024,128], v.1: bf16[1024,128]) -> bf16[1024,128] { %q.1 = bf16[1024,128]{1,0:T(8,128)(2,1)} parameter(0), metadata={op_name="q"} %copy-start = (bf16[1024,128]{1,0:T(8,128)(2,1)S(1)}, bf16[1024,128]{1,0:T(8,128)(2,1)}, u32[]{:S(2)}) copy-start(%q.1), cross_program_prefetch_index=0, backend_config={"dma_priority":1,"flag_configs":[],"scoped_memory_configs":[],"used_scoped_memory_configs":[]} %v.1 = bf16[1024,128]{1,0:T(8,128)(2,1)} parameter(2), metadata={op_name="v"} %copy-start.1 = (bf16[1024,128]{1,0:T(8,128)(2,1)S(1)}, bf16[1024,128]{1,0:T(8,128)(2,1)}, u32[]{:S(2)}) copy-start(%v.1), backend_config={"dma_priority":1,"flag_configs":[],"scoped_memory_configs":[],"used_scoped_memory_configs":[]} %k.1 = bf16[1024,128]{1,0:T(8,128)(2,1)} parameter(1), metadata={op_name="k"} %copy-done = bf16[1024,128]{1,0:T(8,128)(2,1)S(1)} copy-done(%copy-start), backend_config={"dma_priority":1,"flag_configs":[],"scoped_memory_configs":[],"used_scoped_memory_configs":[]} %fusion = bf16[1024,1024]{1,0:T(8,128)(2,1)S(1)} fusion(%copy-done, %k.1), kind=kOutput, calls=%fused_computation, metadata={op_name="jit(naive_attention)/dot_general" stack_frame_id=20}, backend_config={"aliasing_operands":{"lists":[]},"convolution_algorithm_config":{"emitter":"EmitAllBatchInSublanes"},"flag_configs":[],"retry_config":{"retry_count":"0"},"scoped_memory_configs":[],"used_scoped_memory_configs":[{"memory_space":"1","offset":"0","size":"262144"}],"window_config":{"buffering_level":"2","cost_model_type":"COST_MODEL_TYPE_CLASSIC","estimated_bundle_count":"0","estimated_cycles":"3528","estimated_scoped_vmem_bytes":"0","estimated_vmem_bytes":"0","input_window_bounds":["128","1"],"is_mask":false,"iteration_bounds":["1","1","1"],"kernel_window_bounds":["128","1"],"ml_estimated_microseconds":0,"output_window_bounds":["128","8"],"pad_input_on_minor_dim":"0","pad_output_on_minor_dim":"0"}} %copy-done.1 = bf16[1024,128]{1,0:T(8,128)(2,1)S(1)} copy-done(%copy-start.1), backend_config={"dma_priority":1,"flag_configs":[],"scoped_memory_configs":[],"used_scoped_memory_configs":[]} ROOT %online-softmax = bf16[1024,128]{1,0:T(8,128)(2,1)} custom-call(%fusion, %copy-done.1), custom_call_target="tpu_custom_call", operand_layout_constraints={bf16[1024,1024]{1,0}, bf16[1024,128]{1,0}}, frontend_attributes={tiling="1024,1024"}, metadata={op_name="online-softmax"}, backend_config={"aliasing_operands":{"lists":[]},"custom_call_config":{"allow_input_fusion":[],"body":"bW9kdWxlIHsKICBmdW5jLmZ1bmMgQG1haW4oJWFyZzA6IGkzMiwgJWFyZzE6IGkzMiwgJWFyZzI6IG1lbXJlZjwxMDI0eDEwMjR4YmYxNiwgI3RwdS5tZW1vcnlfc3BhY2U8dm1lbT4+LCAlYXJnMzogbWVtcmVmPDEwMjR4MTI4eGJmMTYsICN0cHUubWVtb3J5X3NwYWNlPHZtZW0+PiwgJWFyZzQ6IG1lbXJlZjwxMDI0eDEyOHhiZjE2LCAjdHB1Lm1lbW9yeV9zcGFjZTx2bWVtPj4sICVhcmc1OiBtZW1yZWY8MTAyNHgxeGJmMTYsICN0cHUubWVtb3J5X3NwYWNlPHZtZW0+PiwgJWFyZzY6IG1lbXJlZjwxMDI0eDF4YmYxNiwgI3RwdS5tZW1vcnlfc3BhY2U8dm1lbT4+KSBhdHRyaWJ1dGVzIHtkaW1lbnNpb25fc2VtYW50aWNzID0gWyN0cHUuZGltZW5zaW9uX3NlbWFudGljczxwYXJhbGxlbD4sICN0cHUuZGltZW5zaW9uX3NlbWFudGljczxhcmJpdHJhcnk+XSwgaXRlcmF0aW9uX2JvdW5kcyA9IGFycmF5PGk2NDogMSwgMT4sIHNjcmF0Y2hfb3BlcmFuZHMgPSAyIDogaTY0LCB3aW5kb3dfcGFyYW1zID0gW3t0cmFuc2Zvcm1faW5kaWNlcyA9IEBxa19mbiwgd2luZG93X2JvdW5kcyA9IGFycmF5PGk2NDogMTAyNCwgMTAyND59LCB7dHJhbnNmb3JtX2luZGljZXMgPSBAdl9mbiwgd2luZG93X2JvdW5kcyA9IGFycmF5PGk2NDogMTAyNCwgMTI4Pn0sIHt0cmFuc2Zvcm1faW5kaWNlcyA9IEBvaV9mbiwgd2luZG93X2JvdW5kcyA9IGFycmF5PGk2NDogMTAyNCwgMTI4Pn1dfSB7CiAgICAlYzAgPSBhcml0aC5jb25zdGFudCAwIDogaW5kZXgKICAgICVjMF9pMzIgPSBhcml0aC5jb25zdGFudCAwIDogaTMyCiAgICAlMCA9IGFyaXRoLmNtcGkgZXEsICVjMF9pMzIsICVhcmcxIDogaTMyCiAgICBzY2YuaWYgJTAgewogICAgICAlY3N0XzMgPSBhcml0aC5jb25zdGFudCBkZW5zZTwwLjAwMDAwMGUrMDA+IDogdmVjdG9yPDEwMjR4MTI4eGJmMTY+CiAgICAgIHZlY3Rvci5zdG9yZSAlY3N0XzMsICVhcmc0WyVjMCwgJWMwXSA6IG1lbXJlZjwxMDI0eDEyOHhiZjE2LCAjdHB1Lm1lbW9yeV9zcGFjZTx2bWVtPj4sIHZlY3RvcjwxMDI0eDEyOHhiZjE2PgogICAgICAlY3N0XzQgPSBhcml0aC5jb25zdGFudCBkZW5zZTwweEZGODA+IDogdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgICB2ZWN0b3Iuc3RvcmUgJWNzdF80LCAlYXJnNVslYzAsICVjMF0gOiBtZW1yZWY8MTAyNHgxeGJmMTYsICN0cHUubWVtb3J5X3NwYWNlPHZtZW0+PiwgdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgICAlY3N0XzUgPSBhcml0aC5jb25zdGFudCBkZW5zZTwwLjAwMDAwMGUrMDA+IDogdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgICB2ZWN0b3Iuc3RvcmUgJWNzdF81LCAlYXJnNlslYzAsICVjMF0gOiBtZW1yZWY8MTAyNHgxeGJmMTYsICN0cHUubWVtb3J5X3NwYWNlPHZtZW0+PiwgdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgfQogICAgJTEgPSB2ZWN0b3IubG9hZCAlYXJnMlslYzAsICVjMF0gOiBtZW1yZWY8MTAyNHgxMDI0eGJmMTYsICN0cHUubWVtb3J5X3NwYWNlPHZtZW0+PiwgdmVjdG9yPDEwMjR4MTAyNHhiZjE2PgogICAgJWNzdCA9IGFyaXRoLmNvbnN0YW50IGRlbnNlPDB4RkY4MD4gOiB2ZWN0b3I8MTAyNHhiZjE2PgogICAgJTIgPSB2ZWN0b3IubXVsdGlfcmVkdWN0aW9uIDxtYXhpbXVtZj4sICUxLCAlY3N0IFsxXSA6IHZlY3RvcjwxMDI0eDEwMjR4YmYxNj4gdG8gdmVjdG9yPDEwMjR4YmYxNj4KICAgICUzID0gdmVjdG9yLnNoYXBlX2Nhc3QgJTIgOiB2ZWN0b3I8MTAyNHhiZjE2PiB0byB2ZWN0b3I8MTAyNHgxeGJmMTY+CiAgICAlNCA9IHZlY3Rvci5sb2FkICVhcmc1WyVjMCwgJWMwXSA6IG1lbXJlZjwxMDI0eDF4YmYxNiwgI3RwdS5tZW1vcnlfc3BhY2U8dm1lbT4+LCB2ZWN0b3I8MTAyNHgxeGJmMTY+CiAgICAlNSA9IGFyaXRoLm1heGltdW1mICU0LCAlMyA6IHZlY3RvcjwxMDI0eDF4YmYxNj4KICAgICVjc3RfMCA9IGFyaXRoLmNvbnN0YW50IGRlbnNlPDAuMDAwMDAwZSswMD4gOiB2ZWN0b3I8MTAyNHgxeGJmMTY+CiAgICAlNiA9IGFyaXRoLmNtcGYgb2VxLCAlNCwgJTUgOiB2ZWN0b3I8MTAyNHgxeGJmMTY+CiAgICAlNyA9IGFyaXRoLnN1YmYgJTQsICU1IDogdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgJTggPSBhcml0aC5zZWxlY3QgJTYsICVjc3RfMCwgJTcgOiB2ZWN0b3I8MTAyNHgxeGkxPiwgdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgJTkgPSB2ZWN0b3IuYnJvYWRjYXN0ICU1IDogdmVjdG9yPDEwMjR4MXhiZjE2PiB0byB2ZWN0b3I8MTAyNHgxMDI0eGJmMTY+CiAgICAlMTAgPSBhcml0aC5zdWJmICUxLCAlOSA6IHZlY3RvcjwxMDI0eDEwMjR4YmYxNj4KICAgICUxMSA9IG1hdGguZXhwICUxMCA6IHZlY3RvcjwxMDI0eDEwMjR4YmYxNj4KICAgICVjc3RfMSA9IGFyaXRoLmNvbnN0YW50IGRlbnNlPDAuMDAwMDAwZSswMD4gOiB2ZWN0b3I8MTAyNHhiZjE2PgogICAgJTEyID0gdmVjdG9yLm11bHRpX3JlZHVjdGlvbiA8YWRkPiwgJTExLCAlY3N0XzEgWzFdIDogdmVjdG9yPDEwMjR4MTAyNHhiZjE2PiB0byB2ZWN0b3I8MTAyNHhiZjE2PgogICAgJTEzID0gdmVjdG9yLnNoYXBlX2Nhc3QgJTEyIDogdmVjdG9yPDEwMjR4YmYxNj4gdG8gdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgJTE0ID0gdmVjdG9yLmxvYWQgJWFyZzZbJWMwLCAlYzBdIDogbWVtcmVmPDEwMjR4MXhiZjE2LCAjdHB1Lm1lbW9yeV9zcGFjZTx2bWVtPj4sIHZlY3RvcjwxMDI0eDF4YmYxNj4KICAgICUxNSA9IG1hdGguZXhwICU4IDogdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgJTE2ID0gYXJpdGgubXVsZiAlMTUsICUxNCA6IHZlY3RvcjwxMDI0eDF4YmYxNj4KICAgICUxNyA9IGFyaXRoLmFkZGYgJTE2LCAlMTMgOiB2ZWN0b3I8MTAyNHgxeGJmMTY+CiAgICAlMTggPSB2ZWN0b3IubG9hZCAlYXJnNFslYzAsICVjMF0gOiBtZW1yZWY8MTAyNHgxMjh4YmYxNiwgI3RwdS5tZW1vcnlfc3BhY2U8dm1lbT4+LCB2ZWN0b3I8MTAyNHgxMjh4YmYxNj4KICAgICUxOSA9IG1hdGguZXhwICU4IDogdmVjdG9yPDEwMjR4MXhiZjE2PgogICAgJTIwID0gYXJpdGgubXVsZiAlMTksICUxNCA6IHZlY3RvcjwxMDI0eDF4YmYxNj4KICAgICUyMSA9IHZlY3Rvci5icm9hZGNhc3QgJTIwIDogdmVjdG9yPDEwMjR4MXhiZjE2PiB0byB2ZWN0b3I8MTAyNHgxMjh4YmYxNj4KICAgICUyMiA9IGFyaXRoLm11bGYgJTIxLCAlMTggOiB2ZWN0b3I8MTAyNHgxMjh4YmYxNj4KICAgICUyMyA9IHZlY3Rvci5sb2FkICVhcmczWyVjMCwgJWMwXSA6IG1lbXJlZjwxMDI0eDEyOHhiZjE2LCAjdHB1Lm1lbW9yeV9zcGFjZTx2bWVtPj4sIHZlY3RvcjwxMDI0eDEyOHhiZjE2PgogICAgJTI0ID0gdmVjdG9yLnNoYXBlX2Nhc3QgJTIzIDogdmVjdG9yPDEwMjR4MTI4eGJmMTY+IHRvIHZlY3RvcjwxMDI0eDEyOHhiZjE2PgogICAgJTI1ID0gdmVjdG9yLnNoYXBlX2Nhc3QgJTExIDogdmVjdG9yPDEwMjR4MTAyNHhiZjE2PiB0byB2ZWN0b3I8MTAyNHgxMDI0eGJmMTY+CiAgICAlMjYgPSB2ZWN0b3Iuc2hhcGVfY2FzdCAlMjIgOiB2ZWN0b3I8MTAyNHgxMjh4YmYxNj4gdG8gdmVjdG9yPDEwMjR4MTI4eGJmMTY+CiAgICAlMjcgPSBhcml0aC5leHRmICUyNiA6IHZlY3RvcjwxMDI0eDEyOHhiZjE2PiB0byB2ZWN0b3I8MTAyNHgxMjh4ZjMyPgogICAgJTI4ID0gdHB1Lm1hdG11bCAlMjUsICUyNCwgJTI3IHtkaW1lbnNpb25fbnVtYmVycyA9ICN0cHUuZG90X2RpbWVuc2lvbl9udW1iZXJzPFsxXSwgWzBdLCBbMF0sIFsxXSwgWzAsIDAsIDEsIDFdLCBbXSwgW10+LCBwcmVjaXNpb24gPSAjdHB1LmNvbnRyYWN0X3ByZWNpc2lvbjxiZjE2PiwgdHJhbnNwb3NlX2xoc19oaW50ID0gZmFsc2V9IDogdmVjdG9yPDEwMjR4MTAyNHhiZjE2PiwgdmVjdG9yPDEwMjR4MTI4eGJmMTY+LCB2ZWN0b3I8MTAyNHgxMjh4ZjMyPiAtPiB2ZWN0b3I8MTAyNHgxMjh4ZjMyPgogICAgJTI5ID0gYXJpdGgudHJ1bmNmICUyOCA6IHZlY3RvcjwxMDI0eDEyOHhmMzI+IHRvIHZlY3RvcjwxMDI0eDEyOHhiZjE2PgogICAgJTMwID0gdmVjdG9yLnNoYXBlX2Nhc3QgJTI5IDogdmVjdG9yPDEwMjR4MTI4eGJmMTY+IHRvIHZlY3RvcjwxMDI0eDEyOHhiZjE2PgogICAgJWNzdF8yID0gYXJpdGguY29uc3RhbnQgZGVuc2U8MS4wMDAwMDBlKzAwPiA6IHZlY3RvcjwxMDI0eDF4YmYxNj4KICAgICUzMSA9IGFyaXRoLmRpdmYgJWNzdF8yLCAlMTcgOiB2ZWN0b3I8MTAyNHgxeGJmMTY+CiAgICAlMzIgPSB2ZWN0b3IuYnJvYWRjYXN0ICUzMSA6IHZlY3RvcjwxMDI0eDF4YmYxNj4gdG8gdmVjdG9yPDEwMjR4MTI4eGJmMTY+CiAgICAlMzMgPSBhcml0aC5tdWxmICUzMCwgJTMyIDogdmVjdG9yPDEwMjR4MTI4eGJmMTY+CiAgICAlMzQgPSB2ZWN0b3Iuc2hhcGVfY2FzdCAlMzMgOiB2ZWN0b3I8MTAyNHgxMjh4YmYxNj4gdG8gdmVjdG9yPDEwMjR4MTI4eGJmMTY+CiAgICB2ZWN0b3Iuc3RvcmUgJTM0LCAlYXJnNFslYzAsICVjMF0gOiBtZW1yZWY8MTAyNHgxMjh4YmYxNiwgI3RwdS5tZW1vcnlfc3BhY2U8dm1lbT4+LCB2ZWN0b3I8MTAyNHgxMjh4YmYxNj4KICAgIHZlY3Rvci5zdG9yZSAlNSwgJWFyZzVbJWMwLCAlYzBdIDogbWVtcmVmPDEwMjR4MXhiZjE2LCAjdHB1Lm1lbW9yeV9zcGFjZTx2bWVtPj4sIHZlY3RvcjwxMDI0eDF4YmYxNj4KICAgIHZlY3Rvci5zdG9yZSAlMTcsICVhcmc2WyVjMCwgJWMwXSA6IG1lbXJlZjwxMDI0eDF4YmYxNiwgI3RwdS5tZW1vcnlfc3BhY2U8dm1lbT4+LCB2ZWN0b3I8MTAyNHgxeGJmMTY+CiAgICByZXR1cm4KICB9CiAgZnVuYy5mdW5jIEBxa19mbiglYXJnMDogaTMyLCAlYXJnMTogaTMyKSAtPiAoaTMyLCBpMzIpIHsKICAgIHJldHVybiAlYXJnMCwgJWFyZzEgOiBpMzIsIGkzMgogIH0KICBmdW5jLmZ1bmMgQHZfZm4oJWFyZzA6IGkzMiwgJWFyZzE6IGkzMikgLT4gKGkzMiwgaTMyKSB7CiAgICAlYzBfaTMyID0gYXJpdGguY29uc3RhbnQgMCA6IGkzMgogICAgcmV0dXJuICVhcmcxLCAlYzBfaTMyIDogaTMyLCBpMzIKICB9CiAgZnVuYy5mdW5jIEBvaV9mbiglYXJnMDogaTMyLCAlYXJnMTogaTMyKSAtPiAoaTMyLCBpMzIpIHsKICAgICVjMF9pMzIgPSBhcml0aC5jb25zdGFudCAwIDogaTMyCiAgICByZXR1cm4gJWFyZzAsICVjMF9pMzIgOiBpMzIsIGkzMgogIH0KfQ==","input_memory_space_colors":[],"needs_hlo_passes":false,"needs_layout_passes":true,"output_memory_colors":[],"output_memory_space_colors":[]},"flag_configs":[],"retry_config":{"retry_count":"0"},"scoped_memory_configs":[],"used_scoped_memory_configs":[{"memory_space":"1","offset":"0","size":"3305472"}]} }
copper lines are fusion ops · underlined lines carry the program’s big intermediate · dim lines are regions, parameters, and bookkeeping
hover any line on either side · captured on TPU v6 lite, jax 0.11.0, by labs/capture-hlo.ipynb
own account
A real profile, read op by op
Twenty iterations of naive attention, traced on a v6e-1 and aggregated from the device plane: hardware time, not a cost model. Two things to find. The envelope equals the two compute ops alone, so the 89.6 µs copy hid entirely behind compute. And the second-largest op is a custom call nobody wrote: XLA:TPU pattern-matched the softmax and dispatched its own online-softmax kernel, exactly the escape hatch chapter 09 teaches and the measurement habit chapter 10 closes on.
The reading: the envelope is 217.6 µs and so is fusion + online-softmax alone, which means the 89.6 µs copy hid completely behind compute. And the second-largest op is a kernel nobody in this program wrote: the compiler dispatched its own.
hover an op: it explains itself · click for its full HLO text · captured on TPU v6 lite, jax 0.11.0