|
16 | 16 | from typing import Any, cast |
17 | 17 |
|
18 | 18 | # These backends consume an explicit integer device id while materializing |
19 | | -# their simulator. MuJoCo/Motrix/Drake either run on the host or own their |
20 | | -# device selection internally and must not receive a synthetic override. |
| 19 | +# their simulator. MuJoCo/Motrix/Drake run CPU-authoritative physics; their |
| 20 | +# optional accelerator Manager buffers are selected separately through |
| 21 | +# ``manager_torch_device``. |
21 | 22 | BACKEND_ENV_DEVICE_FIELDS: dict[str, str] = { |
22 | 23 | "isaacgym": "isaacgym_device_id", |
23 | 24 | "isaacsim": "isaacsim_device_id", |
|
41 | 42 | # integer payload sent to that worker before construction. |
42 | 43 | _EXTERNAL_CUDA_IPC_BACKENDS = {"isaacgym", "isaacsim"} |
43 | 44 |
|
| 45 | +# HOST_BRIDGE backends accept optional accelerator Torch carriers across their packed |
| 46 | +# boundary. A process may explicitly request those carriers on its learner Torch |
| 47 | +# device; unset non-accelerator requests retain the owner/default CPU placement. |
| 48 | +_HOST_BRIDGE_TORCH_BACKENDS = {"mujoco", "motrix", "drake", "superdex"} |
| 49 | + |
44 | 50 |
|
45 | 51 | # Set once ``bind_genesis_process_device`` has pinned CUDA_VISIBLE_DEVICES for |
46 | 52 | # this process. Genesis/Quadrants binds its CUDA runtime to the first visible |
@@ -170,6 +176,35 @@ def apply_backend_env_device_override( |
170 | 176 | return result |
171 | 177 |
|
172 | 178 |
|
| 179 | +def apply_manager_torch_device_override( |
| 180 | + env_cfg_override: Mapping[str, Any] | None, |
| 181 | + backend_type: str, |
| 182 | + *, |
| 183 | + learner_device: str | None = None, |
| 184 | +) -> dict[str, Any]: |
| 185 | + """Return an env override selecting optional HOST_BRIDGE Torch carriers. |
| 186 | +
|
| 187 | + The input mapping is never mutated. Explicit CPU requests force CPU carriers. |
| 188 | + Unset and non-CUDA learner requests retain owner/default placement. A CUDA request |
| 189 | + is validated against backend capabilities when the environment binds. |
| 190 | + DEVICE_RESIDENT backends own placement and never receive this synthetic field. |
| 191 | + """ |
| 192 | + |
| 193 | + result = dict(env_cfg_override) if env_cfg_override is not None else {} |
| 194 | + if _normalize_backend(backend_type) not in _HOST_BRIDGE_TORCH_BACKENDS: |
| 195 | + return result |
| 196 | + if learner_device is None: |
| 197 | + return result |
| 198 | + device = str(learner_device).strip() |
| 199 | + if not device or device.lower() == "cpu": |
| 200 | + result["manager_torch_device"] = "cpu" |
| 201 | + return result |
| 202 | + if device.split(":", 1)[0].lower() != "cuda": |
| 203 | + return result |
| 204 | + result["manager_torch_device"] = device |
| 205 | + return result |
| 206 | + |
| 207 | + |
173 | 208 | def resolve_backend_process_device(backend_type: str, learner_device: str | None) -> str | None: |
174 | 209 | backend = _normalize_backend(backend_type) |
175 | 210 | if ( |
@@ -399,6 +434,7 @@ def _reset_genesis_device_pin_for_tests() -> None: |
399 | 434 | __all__ = [ |
400 | 435 | "BACKEND_ENV_DEVICE_FIELDS", |
401 | 436 | "apply_backend_env_device_override", |
| 437 | + "apply_manager_torch_device_override", |
402 | 438 | "bind_backend_process_device", |
403 | 439 | "bind_backend_process_device_for_backend", |
404 | 440 | "bind_genesis_process_device", |
|
0 commit comments