Issues / #3418

#3418 Picking a single GPU in the app (Ryzen iGPU + discrete Radeon) is broken twice over

open · @squidwardboom · 1 Kommentare · Auf GitHub

needs-format

Beschreibung

## Environment

| | |
|---|---|
| Strata | 0.1.45.3, **Windows app install** (`Strata-0.2.0-beta-windows-hip-rdna3.exe`) |
| Engine | `strata-engine` 0.1.45.3, `windows-x86_64-hip-rdna3` |
| CPU / iGPU | Ryzen 7 7800X3D → `AMD Radeon(TM) Graphics`, **gfx1036** |
| GPU | **AMD Radeon RX 7900 XTX**, gfx1100, 24 GB |
| Install | default `LOCALAPPDATA` layout; model Qwen3.8-Flash-Next IQ3_S |

The two cards matter: HIP numbers the **iGPU 0** and the **7900 XTX 1**, while the display-adapter order used elsewhere numbers them the other way round.

```
> strata-device.exe --list-devices
device 0: AMD Radeon(TM) Graphics
  arch gfx1036, 43.7 GiB, wave32
  cannot run: GPU 0 (AMD Radeon(TM) Graphics, gfx1036) is not an architecture this Strata engine was compiled for
  (gfx1100,gfx1101,gfx1102,gfx1151); ... or choose another GPU with HIP_VISIBLE_DEVICES
device 1: AMD Radeon RX 7900 XTX
  arch gfx1100, 24.0 GiB, wave32
```

```
> Get-CimInstance Win32_VideoController | select Name
AMD Radeon RX 7900 XTX      <- display-adapter order: 0
AMD Radeon(TM) Graphics     <- display-adapter order: 1
```

---

## Bug 1 — a single-card pick is sent as `gpus` and rejected by the schema

### Steps

1. Settings → pick the GPU → select **Radeon RX 7900 XTX** (the only card the list offers; the iGPU is correctly filtered out).
2. Load the model.

### Actual

```
Gpus='0' is not valid (several GPUs sharing the model: '0,2' or 'all' (experimental))
```

### Expected

The card is accepted and the model loads.

### Cause

`strata_install` carries two mutually exclusive GPU parameters:

```python
# control/tools/strata_mcp.py:1470
GPUS_PATTERN = r"all|\d{1,2}(,\d{1,2}){1,7}"

# control/tools/strata_mcp.py:1532-1535
"gpu":  {"type": "integer", "minimum": 0, "maximum": 63,
         "description": "one GPU, as nvidia-smi numbers them (default: the one with the most VRAM)"},
"gpus": {"type": "string", "pattern": GPUS_PATTERN, "maxLength": 40,
         "description": "several GPUs sharing the model: '0,2' or 'all' (experimental)"},
```

```python
# control/tools/strata_mcp.py:1807-1808
if gpu is not None and gpus is not None:
    raise ToolError("give gpu (one card) or gpus (several), not both")
```

The one-card case is meant to go through `gpu` (integer). The app's Settings puts the selection into `gpus` instead, as a string — so a single card arrives as `"0"`, which `GPUS_PATTERN` cannot match (it needs ≥ 2 comma-separated cards, or `all`). The schema rejects it before it ever reaches `install_plan()`.

### Suggested fix

When exactly one card is selected, emit `gpu: <n>` (integer). Reserve `gpus` for 2+ cards. Optionally make the pattern accept a single number and treat it as the one-card case, so a client that never distinguishes the two still works.

---

## Bug 2 — with the app install, that number is the display-adapter index, not the HIP ordinal, so the engine starts on the iGPU and dies

Fixing bug 1 alone (sending `gpu=0`) does **not** help on this machine: the UI's `0` means "the first usable card in display-adapter order", but the engine receives it as `HIP_VISIBLE_DEVICES=0`, which is the iGPU.

### Actual

```
server_exited (exit code 1): EngineDied: the engine exited before it was ready (see strata-iq3_s.log)
```

```
strata: GPU 0 (AMD Radeon(TM) Graphics, gfx1036) is not an architecture this Strata engine was
        compiled for (gfx1100,gfx1101,gfx1102,gfx1151); compile it for this card
        (./setup.sh --backend hip, or -DCMAKE_HIP_ARCHITECTURES=gfx1036, docs/AMD_HIP.md)
        or choose another GPU with HIP_VISIBLE_DEVICES
```

### Cause

`serve/server.py` already has the correction for this (#325), and says what should feed it:

```python
# control/serve/server.py:2964-2977
def hip_visible(cfg: dict) -> list[int]:
    """AMD: the devices the engine should see, as the HIP runtime numbers them (HIP_VISIBLE_DEVICES).

    On Linux setup's KFD order is HIP's order, so the config's "gpu" is it.  On Windows setup finds the cards in the
    display-adapter order, and an integrated Radeon that HIP also enumerates takes ordinal 0 and pushes the discrete
    card to 1 (#325): setup records the ordinal `strata-device --list-devices` gave the card as "hip_ordinal", which
    wins for a one-card config.  Without it (a config from before), the config's "gpu"."""
    ordinal = cfg.get("hip_ordinal")
    if ordinal is not None and str(ordinal).strip() != "" and len(gpu_list(cfg)) <= 1:
        ...
    return ordered_gpus(cfg)
```

Two things stop that from working on the app install:

**(a) The card list is built in display-adapter order, because the HIP probe is never found.**

```python
# control/setup.py:3503-3513
def hip_devices(probe=None, text=None) -> list[dict] | None:
    if text is None:
        probe = probe or ROOT / "engine" / ("strata-device.exe" if WIN else "strata-device")
        ...
        if not probe.exists() or not hip_engine:
            return None
```

`ROOT` is `Path(__file__).resolve().parent` = `<install>\control`, and the app install keeps the engine in the **component** layout, not at `<install>\control\engine`:

```
<LOCALAPPDATA>\Programs\Strata\control\            <- ROOT
<LOCALAPPDATA>\Programs\Strata\engine-bundle\0.1.45.3-windows-x86_64-hip-rdna3\strata-device.exe
<LOCALAPPDATA>\Strata\components\engine\0.1.45.3-windows-x86_64-hip-rdna3\strata-device.exe   <- the one that runs
```

So `hip_devices()` returns `None`, and `amd_gpus_win()` falls back to `amd_gpus_windows()`:

```python
# control/setup.py:3319-3333
def amd_gpus_win() -> list[dict]:
    """Windows: the AMD GPUs as the HIP runtime numbers them once the HIP engine is installed (hip_devices), else in
    the display-adapter order (amd_gpus_windows)."""
    hip = hip_devices()
    if not hip:
        return amd_gpus_windows()
```

Observed on this machine:

```
amd_gpus_win():
  index=0  AMD Radeon RX 7900 XTX       arch=gfx1100   usable=True
  index=1  AMD Radeon(TM) Graphics      arch=unknown   usable=False
```

The 7900 XTX is therefore offered as **GPU 0**, and that 0 is what lands in the config as `"gpu": 0` — which the engine reads as HIP ordinal 0, the iGPU.

Note the Terminal / `git clone` install does not hit this: there `ROOT\engine\strata-device.exe` exists, `hip_devices()` succeeds, and the same card is correctly numbered 1. The two install layouts number the same card differently, and only the app layout gets it wrong.

**(b) Nothing ever writes `hip_ordinal`.** The docstring above says setup records it, but a tree-wide grep for `hip_ordinal` finds only readers and tests — no producer:

```
control/serve/replicas.py:98        c.pop("hip_ordinal", None)
control/serve/server.py:2969,2971   docstring + cfg.get("hip_ordinal")
control/serve/test_server.py:1786-1794
control/serve/test_replicas.py:37,46
```

So no Windows AMD install reaches `hip_visible()` with an ordinal, and the fallback `ordered_gpus(cfg)` always feeds the display-adapter index to `HIP_VISIBLE_DEVICES`.

### Suggested fix

1. Make `hip_devices()` resolve the probe through `strata_control.engine_component` (`engine_dir()` / the current engine component folder) instead of the hardcoded `ROOT / "engine"`, so the app's component layout numbers cards the way HIP does. Then `gpu: 1` for this machine is correct without any ordinal at all.
2. Independently, have setup/Control actually record `hip_ordinal` (from `strata-device --list-devices`) when it writes a one-card Windows AMD config, as `hip_visible()` already expects.
3. As cheap insurance, `hip_visible()` could skip devices whose arch the engine cannot run (`--list-devices` already prints `cannot run:` for them) instead of trusting the ordinal blindly.

---

## Workaround that works today

Add the ordinal by hand to the run config (`<LOCALAPPDATA>\Strata\install\strata-<model>.json`):

```json
"backend": "hip",
"gpu": 0,
"hip_ordinal": 1,
```

With that the model loads and answers normally:

```
strata generate: session is up (engine 0.1.45.3)
strata generate: expert cache 5749 slots, 10.92 GiB of VRAM
```

## Related

#325 (iGPU takes HIP ordinal 0), #524, #942

Mehr auf der Site

Links zu Install, Modellen, Releases.