Skip to content

feat(chs): single-host TPU init for node-local diagnostics + libtpu 0.0.48 - #142

Merged
linamy85 merged 9 commits into
AI-Hypercomputer:chsfrom
simrankaurb:feat/chs-local-node-tpu-diagnostics
Oct 8, 2026
Merged

linamy85 merged 9 commits into
AI-Hypercomputer:chsfrom
simrankaurb:feat/chs-local-node-tpu-diagnostics

Conversation

@simrankaurb

@simrankaurb simrankaurb commented Oct 8, 2026 •

Copy link
Copy Markdown

Summary

Lets a benchmark initialize libtpu as a standalone single host on one VM of a multi-host TPU slice, without touching the slice's ICI routing or contacting tpunetd. Enabled per benchmark via a new config key single_host_tpu_init: true. Also bumps JAX/libtpu to pick up --deepsea_hal_test_allow_multichip_skip_slicebuilder.

Changes

File Change
requirements.txt jax[tpu] / jaxlib 0.10.1 → 0.11.2, libtpu 0.0.41 → 0.0.48
Ironwood/src/benchmark_utils.py (a) New configure_single_host_tpu(): sets TPU_HOST_BOUNDS=1,1,1, TPU_SKIP_MDS_QUERY=true, TPU_WORKER_ID=0, TPU_WORKER_HOSTNAMES=localhost; appends --deepsea_hal_test_skip_slicebuilder=true --deepsea_hal_test_allow_multichip_skip_slicebuilder=true --xla_tpu_use_enhanced_launch_barrier=false to LIBTPU_INIT_ARGS (existing flags matched by exact name). is_single_host_tpu_init() exposes the state to benchmark modules. (b) libtpu 0.0.48 HLO dump format: rename_xla_dump() skips subdirectories now present in the dump dir, and extract_hlo_features_from_file() parses the new replica_groups=mesh[...]{...} syntax in addition to the explicit {{...}} list form.
Ironwood/src/run_benchmark.py Calls configure_single_host_tpu() when the benchmark config has single_host_tpu_init: true. Runs after the benchmark module import (which sets LIBTPU_INIT_ARGS) and before the first JAX device call.
Ironwood/src/benchmark_gemm.py (a) When single_host_tpu_init is active, generate inputs independently on each local device (jax.make_array_from_single_device_arrays) instead of device_put from device 0: SliceBuilder is skipped, so intra-host ICI is unprogrammed and a cross-chip copy would fault. Default path unchanged otherwise. (b) --xla_tpu_enable_async_collective_fusion=false, drop _fuse_all_gather — libtpu 0.0.48 rejects =true on v6e and 7x (FAILED_PRECONDITION: Continuation fusion for AllGather … not supported on platforms other than Viperlite); aligned with op_flags.yaml on main.

Usage

benchmarks:
- benchmark_name: gemm_multiple_run
  single_host_tpu_init: true        # benchmark-level, not a sweep param
  benchmark_sweep_params:
  - {m: 16384, k: 16384, n: 16384, num_runs: 100, dtype: bfloat16, run_on_local_node: True}

single_host_tpu_init controls libtpu process init; run_on_local_node (existing) controls the mesh. Do not set single_host_tpu_init for multi-host benchmarks (e.g. collectives).

Validation (CHS, 16-node pools, PR head 9d68aa1)

Pool Flag Run Report
v6e 8x8 OFF v6e-off3 https://storage.cloud.google.com/simranka/bills_of_health/20261008-144431_v6e-off3-f4tr.html
v6e 8x8 ON v6e-on3 https://storage.cloud.google.com/simranka/bills_of_health/20261008-145803_v6e-on3-itlu.html
7x 4x4x4 OFF 7x-off3 https://storage.cloud.google.com/simranka/bills_of_health/20261008-144915_7x-off3-oyx6.html
7x 4x4x4 ON 7x-on3 https://storage.cloud.google.com/simranka/bills_of_health/20261008-145823_7x-on3-qkkd.html

Notes

  • Other modules that still set --xla_tpu_enable_async_collective_fusion=true (benchmark_compute.py, benchmark_gemm_numerics.py, benchmark_gemm_throttling.py, benchmark_inference_compute.py) will need the same change on libtpu 0.0.48; left out to keep this PR minimal.
  • Background on why skipping SliceBuilder is required: go/rca-tpu-hanging, go/disabling-softslicing, b/517071651.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for running benchmarks on a local node (single host without slicebuilder) and updates JAX/libtpu dependencies. Key feedback points out that appending TPU initialization flags using substring checks on LIBTPU_INIT_ARGS can cause silent bugs, recommending exact flag name matching instead. Additionally, in benchmark_gemm.py, several issues were identified regarding local data initialization, including incorrect indexing of seed_arr, shape mismatches with per_dev_seeds, and non-standard usage of jax.block_until_ready on a tuple. Finally, is_local_node_benchmark in run_benchmark.py should be expanded to check both benchmark_params and benchmark_sweep_params to ensure local node configurations are not missed.

Comment thread Ironwood/src/benchmark_gemm.py Outdated
Comment thread Ironwood/src/benchmark_gemm.py Outdated
Comment thread Ironwood/src/benchmark_gemm.py Outdated
Comment thread Ironwood/src/benchmark_hbm.py Outdated
Comment thread Ironwood/src/benchmark_host_device.py Outdated
Comment thread Ironwood/src/benchmark_utils.py Outdated
Comment thread Ironwood/src/run_benchmark.py Outdated
Comment thread Ironwood/src/benchmark_gemm.py Outdated
@simrankaurb
simrankaurb force-pushed the feat/chs-local-node-tpu-diagnostics branch 8 times, most recently from 10fd65a to 034c740 Compare October 8, 2026 09:18
@simrankaurb
simrankaurb force-pushed the feat/chs-local-node-tpu-diagnostics branch from 227d3f9 to 2c3d0eb Compare October 8, 2026 09:38
…st_tpu_init flag

- Add 'single_host_tpu_init' as a benchmark-level config key that triggers
  configure_single_host_tpu() (renamed from configure_local_node_tpu).
  It acts at the libtpu init layer, once per process.
- 'run_on_local_node' stays a sweep-param-only knob (JAX device selection)
  and is no longer injected from benchmark_config.
- Revert the unused run_on_local_node kwargs in benchmark_hbm.py and
  benchmark_host_device.py since params are no longer injected.
Prints the env vars and final LIBTPU_INIT_ARGS so a run's logs show that
single_host_tpu_init actually took effect before libtpu initialized.
libtpu 0.0.48 rejects --xla_tpu_enable_async_collective_fusion=true at
backend init on v6e (ghostlite) and 7x with FAILED_PRECONDITION
("Continuation fusion for AllGather ... not supported on platforms other
than Viperlite"), which broke gemm_multiple_run regardless of the
single_host_tpu_init flag. These benchmarks are per-device matmuls with no
all-gathers, so the fusion flags have no effect on what is measured. Turn
them off unconditionally in all modules that set them, and drop the
now-redundant rewrite from configure_single_host_tpu().
Keep --xla_tpu_enable_async_collective_fusion=false (required by libtpu
0.0.48 on v6e/7x), restore _multiple_steps=true and drop _fuse_all_gather,
matching the gemm_flags set in AI-Hypercomputer/accelerator-microbenchmarks
main. No behavioral change while the master switch is off.
Keep the PR scoped to the benchmarks CHS runs. Other modules that set
--xla_tpu_enable_async_collective_fusion=true will need the same change
to run on libtpu 0.0.48; see op_flags.yaml on main.
@simrankaurb simrankaurb changed the title feat(chs): support single-host TPU diagnostics on multi-host slices in Ironwood/src feat(chs): single-host TPU init for node-local diagnostics + libtpu 0.0.48 Oct 8, 2026
…pu_init

The per-device data path exists because SliceBuilder is skipped under
single_host_tpu_init, leaving intra-host ICI unprogrammed so a device_put
from device 0 would be a cross-chip DMA. Tie the branch to that condition
(via is_single_host_tpu_init()) instead of to the mesh choice
(run_on_local_node), which keeps the default path unchanged for all
non-single-host runs.
@simrankaurb
simrankaurb force-pushed the feat/chs-local-node-tpu-diagnostics branch from 5179b35 to 9d68aa1 Compare October 8, 2026 14:41
…igure_single_host_tpu

Substring matching could skip a flag whose name is a prefix of an
already-present flag. Compare against the set of exact flag names instead.
- benchmark_utils.py: wrap docstring to 80 cols, use maxsplit=1 in flag
  name splits, strip trailing whitespace
- requirements.txt: add missing trailing newline
@linamy85

linamy85 commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Some side note:

  • jax 0.11.2 has the jax.device_get device-to-host regression (chs: is not using d2h yet)
  • jax 0.11.1 the create_mesh has changed and will impact parallel 2x4x4 topology. (chs: non-parallel atm)

@linamy85
linamy85 merged commit 5fb8259 into AI-Hypercomputer:chs Oct 8, 2026
1 check passed
simrankaurb added a commit to simrankaurb/accelerator-microbenchmarks that referenced this pull request Oct 26, 2026
… multi-host slices

Adds a benchmark-level `single_host_tpu_init: true` config key and a
`--single_host_tpu_init` CLI flag (default off) that initialize the
current host standalone inside a multi-host slice, so single-host
benchmarks such as `gemm` and `hbm` can be used for node-local
diagnostics (e.g. Cluster Health Scanner) without the other hosts of the
slice participating. Existing behaviour is unchanged when the flag is off.

When enabled, `core/single_host.py` (applied after op_flags and before
the first JAX device call) forces a 1-host topology (`TPU_HOST_BOUNDS`,
`TPU_WORKER_ID`, `TPU_WORKER_HOSTNAMES`, `TPU_SKIP_MDS_QUERY`), skips
SliceBuilder/tpunetd (`--deepsea_hal_test_skip_slicebuilder=true`,
`--deepsea_hal_test_allow_multichip_skip_slicebuilder=true`) and disables
the cross-host launch barrier. This mirrors the `chs` branch (AI-Hypercomputer#142).

Because the slice's ICI routing is left untouched, device-to-device
transfers hang in this mode. `GeneralizedGemmBenchmark.generate_inputs`
previously sampled the operands on the default device and broadcast them
with `jax.device_put(x, replicated_sharding)`, which hung for any matrix
size ("Slow PjRt TPU operation detected" on all local devices). With the
flag on, the operands are now generated independently on each local mesh
device from a CPU-pinned key and assembled with
`jax.make_array_from_single_device_arrays`, so the only transfers are
host->device. The default path is untouched (pure additions).

Verified on a tpu7x-standard-4t host of a 2x2x4 slice (jax 0.12.0,
libtpu 0.0.50), with no manual environment set up in the pod:
- `single_host_tpu_init: true`, gemm 16384^3 bf16 x20, xprof
  local_slowest_device: 2127 TFLOP/s per chip, 20/20 xprof runs, 78 s.
- `--single_host_tpu_init` gemm 1024^3: 20 s; hbm copy 1G elems: 2790 GB/s.
- Control without the flag on the same node fails at init ("Expected 4
  worker addresses, got 1").
- CPU: the flagged and default input paths yield identical replicated
  arrays and outputs; config/CLI validation covered.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants