Skip to content

[Core][TPU] Support physical chip mask translation for multi-device TPU chips - #65723

Merged
ryanaoleary merged 17 commits into
ray-project:masterfrom
ryanaoleary:fix-tpu-visible-chips-multicore
Sep 17, 2026
Merged

ryanaoleary merged 17 commits into
ray-project:masterfrom
ryanaoleary:fix-tpu-visible-chips-multicore

Conversation

@ryanaoleary

@ryanaoleary ryanaoleary commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Description

On GKE, the TPU device plugin explicitly injects TPU_VISIBLE_CHIPS="0,1,2,3" for privileged containers (securityContext.privileged: true), while leaving it unset for non-privileged containers. On dual-device TPUs (TPU7x), this injected physical chip mask causes Ray to clamp the node to 4 logical resources instead of the 8 detected from hardware (or explicitly set with`--resources='{"TPU": 8}', causing startup validation failures.

Previously, TPUAcceleratorManager handled TPU_VISIBLE_CHIPS without translation:

  1. get_current_process_visible_accelerator_ids() returned physical chip counts resource accounting to fail when auto-detecting or explicitly requesting all logical devices.
  2. set_current_process_visible_accelerator_ids() passed logical device IDs directly into TPU_VISIBLE_CHIPS, setting out-of-bounds physical chip indices for worker processes.

This PR changes:

  • get_current_process_visible_accelerator_ids(): Expands physical chip indices to logical
    device IDs (e.g. ["0", "1", "2", "3"] -> ["0", ..., "7"]).
  • set_current_process_visible_accelerator_ids(): Maps logical device IDs back to physical
    chip indices (device_id // resource_per_chip) before exporting TPU_VISIBLE_CHIPS
  • get_tpu_resource_per_chip(): A single validated accessor for RAY_TPU_RESOURCE_PER_CHIP,
    replacing five copies of int(os.environ.get(...)) in ray/util/tpu.py where a
    non-positive value silently produced zero TPU resources per slice.
  • normalize_tpu_accelerator_type(): A single helper for the canonical v{gen} spelling,
    replacing three inlined variants. This also fixes is_valid_tpu_accelerator_topology(),
    which split TPU-V6E on - before parsing the generation and so rejected every
    TPU--prefixed version.

Both masking directions are gated on RAY_TPU_RESOURCE_PER_CHIP (default 1), so
per-device accounting is opt-in and the default host-level behavior is unchanged.

The above change is required to get TPU_VISIBLE_CHIPS set correctly for both legacy SPMD behavior (workloads request all TPU chips on a host) and with frameworks that run a process per TPU device (i.e. PyTorch).

Related issues

Contributes to: #64055

Additional information

There is some overlap in this PR with: #65221 in terms of the RAY_TPU_RESOURCE_PER_CHIP_ENV_VAR change and getter.

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

Copy link
Copy Markdown
Contributor

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 multi-core TPUs in Ray by mapping physical TPU chips to logical device IDs. It adds helper functions to determine TPU resources per chip and updates the process-visible accelerator ID configuration to handle logical-to-physical mapping. The review feedback highlights a potential TypeError when sorting mixed-type physical chip IDs, dead code and a normalization bug in TPU type resolution, and suggests adding test coverage for mixed-type sorting to prevent regressions.

Comment thread python/ray/_private/accelerators/tpu.py Outdated
Comment thread python/ray/_private/accelerators/tpu.py Outdated
Comment thread python/ray/tests/test_tpu.py Outdated
Comment thread python/ray/_private/accelerators/tpu.py Outdated
@ray-gardener ray-gardener Bot added core Issues that should be addressed in Ray Core community-contribution Contributed by the community labels Aug 25, 2026
@ryanaoleary
ryanaoleary force-pushed the fix-tpu-visible-chips-multicore branch from 95191a5 to 5037376 Compare August 25, 2026 17:33
…ual-chiplet TPUs

Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>

@cursor cursor 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.

Stale Bugbot comment from a previous run.

Comment thread python/ray/_private/accelerators/tpu.py Outdated
Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>
@ryanaoleary
ryanaoleary force-pushed the fix-tpu-visible-chips-multicore branch from 5037376 to 6cb1920 Compare August 28, 2026 23:31
@ryanaoleary

Copy link
Copy Markdown
Contributor Author

cc: @andrewsykim for review if you get time, this fixes the privileged container issue with TPU

Comment thread python/ray/_private/accelerators/tpu.py Outdated
# 3) Dual-Device (v7x): 2 discrete chiplets, enumerated as 2 logical XLA devices
# per chip (4D topology, e.g. "2,2,1,2"). Listed in DUAL_DEVICE_TPU_TYPES.
SINGLE_CORE_TPU_TYPES = ("v5litepod", "v6e")
DUAL_DEVICE_TPU_TYPES = ("v7x",)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

isn't v5p dual chip too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

v5p is dual-core per chip but they're fused since v5p follows megacore architecture (https://docs.jax.dev/en/latest/pallas/tpu/pipelining.html#tpus-in-megacore-configuration) like v4, when I list the devices on the TPU node I only see 1 per chip

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

more context here: #65221 (comment)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I removed DUAL_DEVICE_TPU_TYPES from the PR actually since we shouldn't be auto-detecting dual device types - the behavior needs to be opt/in or it'll break legacy JAX/SPMD behavior. Users specify RAY_TPU_RESOURCE_PER_CHIP and the total TPU resource on the node, and then Slice PG and the accelerator manager ensure the env vars are mapped correctly, etc.

Comment thread python/ray/_private/accelerators/tpu.py Outdated
Comment thread python/ray/_private/accelerators/tpu.py
Comment thread python/ray/_private/accelerators/tpu.py Outdated
…multi-device TPUs

Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>
Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>
Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>
Comment thread python/ray/_private/accelerators/tpu.py Outdated
Comment thread python/ray/_private/accelerators/tpu.py Outdated
Comment thread python/ray/_private/accelerators/tpu.py Outdated
Comment thread python/ray/tests/test_tpu.py Outdated
Comment thread python/ray/_private/accelerators/tpu.py Outdated

# Map logical device IDs to physical chip IDs
physical_chips = {
TPUAcceleratorManager._map_device_to_chip_id(device_id, resource_per_chip)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

From AI review:

Problem: In set_current_process_visible_accelerator_ids, logical devices are mapped to physical chips using dev_idx // devices_per_chip:

If Actor A requests TPU: 1 and is assigned logical device 0, 0 // 2 = 0 
→
→ sets TPU_VISIBLE_CHIPS="0", TPU_CHIPS_PER_HOST_BOUNDS="1,1,1".
If Actor B requests TPU: 1 and is assigned logical device 1, 1 // 2 = 0 
→
→ also sets TPU_VISIBLE_CHIPS="0", TPU_CHIPS_PER_HOST_BOUNDS="1,1,1".

WDYT?

@ryanaoleary ryanaoleary Sep 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think this was a valid issue - TPU_VISIBLE_CHIPS is chip granular and it's actually intended for actors/logical devices to share a chip in the tpu7x case where each chip has 2 separate PJRT devices and frameworks like TorchTPU will run a process per device.
7d8ccab

Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 1a14ce7. Configure here.

Comment thread python/ray/_private/accelerators/tpu.py
Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>
…ting them

Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>
…cess

Signed-off-by: Ryan O'Leary <ryanaoleary@google.com>
@ryanaoleary
ryanaoleary enabled auto-merge (squash) September 15, 2026 05:23
@github-actions github-actions Bot added the go add ONLY when ready to merge, run all tests label Sep 15, 2026
@github-actions
github-actions Bot disabled auto-merge September 15, 2026 05:26
@ryanaoleary
ryanaoleary enabled auto-merge (squash) September 15, 2026 05:26
@ryanaoleary
ryanaoleary enabled auto-merge (squash) September 15, 2026 23:03
@github-actions
github-actions Bot disabled auto-merge September 16, 2026 04:32
@ryanaoleary
ryanaoleary enabled auto-merge (squash) September 16, 2026 22:15
@ryanaoleary
ryanaoleary merged commit 9961fc4 into ray-project:master Sep 17, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution Contributed by the community core Issues that should be addressed in Ray Core go add ONLY when ready to merge, run all tests

2 participants