Skip to content

Platform-agnostic ROCm Helper (Win/Linux) with hardened GPU detection + Enhancements - #1779

Draft
NeuralFault wants to merge 12 commits into
LykosAI:mainfrom
NeuralFault:rocm-helper-ver2
Draft

NeuralFault wants to merge 12 commits into
LykosAI:mainfrom
NeuralFault:rocm-helper-ver2

Conversation

@NeuralFault

@NeuralFault NeuralFault commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

The ROCm helper is currently Windows-only by construction. Compat.IsWindows gates the install
paths inside every package, RocmSupport and the profiles encode a single AMD feed and a
single device-extra policy, and each Linux AMD package carries its own ad-hoc torch index
and launch environment. This work makes the helper platform-agnostic and moves Linux AMD
installs onto it, so both platforms share one install path, one index policy and one
launch environment, with per-package behaviour expressed in declarative profiles. Detection
is reworked on both platforms so the helper stops depending primarily on a hand-maintained
marketing-name table.

Draft: commits land incrementally. The checklist below is the current state, not a target.

Why

  • Linux AMD installs route through each package's own torch index via --extra-index-url,
    so when a pinned version is missing from the ROCm index the resolver can fall back to a
    non-ROCm wheel from PyPI (Installs CUDA version for Stable Diffusion Webui Reforge for my Radeon 7600XT. #1669). Each package works around that separately today.
  • Windows-specific policy is spread across RocmSupport, six profiles, the package
    classes and BaseGitPackage, so adding a package, an architecture or an index means
    editing several places that must agree.
  • AMD's whl-next repo feed publishes linux_x86_64 wheels and per-arch device packages
    for the same versions as Windows, so the "Linux needs a different mechanism" assumption
    no longer holds.
  • Architecture detection is a hand-maintained marketing-name table on both platforms, so a
    new card is invisible until someone edits it, and VRAM on Linux is read from the PCIe BAR
    aperture rather than from the device.
  • Keeps AMD experience on both OS platforms uniform, maintains support for future GPU
    and ROCm PyTorch releases. Greatly lessens friction and needed user-end maintenance
    required during initial use of packages to have an optimal performing environment on Linux.
    (e.g: In most cases no longer requring/depending on system-wide ROCm, Manual envar
    entry/management, fore-knowledge on needed launch args, having to manually override
    package PyTorch install to have latest modern ROCm and repeating process after package
    update that also resets PyTorch back to CPU build or an older and possible incompatible ROCm build)

Design

  • Install target. RocmInstallTarget resolves platform, index kind, index URL, arch,
    device extra and capability flags (device extras, pair resolution, SDK devel) in one
    place. Windows returns today's values unchanged.
  • Index registry. AMD stable by default, AMD nightly for Vega, plus upstream PyTorch
    rocm7.2 and rocm7.14 selectable per package as overrides.
  • Arch detection, both platforms. Linux reads KFD topology (gfx_target_version) with
    the matching mem_info_vram_total. Windows uses the display driver's own OpenCL runtime
    (CL_DEVICE_NAME for the ISA target, CL_DEVICE_BOARD_NAME_AMD for the marketing name,
    CL_DEVICE_GLOBAL_MEM_SIZE for dedicated VRAM), falling back to the existing table only
    when no OpenCL runtime is present. The table stops being the primary source.
  • One torch install path. The torch slot is extracted from
    StandardPipInstallProcessAsync into a shared InstallTorchAsync, used both by the
    standard flow and by the packages with bespoke installers (InvokeAI, Forge Neo).
  • Profile seam. GetRocmProfile(PyVersion) on BaseGitPackage, so a package declares
    its ROCm intent once and every consumer (install, launch environment, launch options,
    extra commands) reads the same profile.
  • Platform-specific surface stays explicit. Dev SDK is cross-platform; the
    SageAttention, FlashAttention and bitsandbytes commands stay Windows-only and say so.

Progress

  • Scope torch upgrade and reinstall to the torch trio, so transitive dependencies
    (numpy foremost) are not re-resolved against the multi-arch index
  • Accept CDNA targets (gfx908, gfx90a, gfx942, gfx950), resolve MI100/MI210 by adapter
    name (gfx942/gfx950 have no name mapping, so they arrive through KFD on Linux),
    map RX 9050 to gfx1200
  • Classify fused SDPA by the AOTriton image list so CDNA2+ is not forced onto the math
    backend, while gfx908 still falls back cleanly
  • Scrub inherited ROCM_PATH, ROCM_HOME, HIP_PATH, ROCM_DIR and HIP_DIR from
    helper-managed environments, gated by SanitizeRocmSdkEnvironment
  • Rename the Windows-specific helper surface to platform-neutral names
  • RocmInstallTarget and the index registry
  • Arch detection on Linux from KFD topology, including the CPU-node and stepping handling
  • Rank candidate GPUs so an APU cannot win by enumeration order, on both platforms
  • Pin ROCR_VISIBLE_DEVICES (Linux) to the selected GPU when more than one AMD GPU is present
  • Linux branch of the install path (index, optional device extras, SDK step)
  • ComfyUI installs and launches through the helper on Linux, verified on gfx1100 with
    torch 2.14.0+rocm10.0.0, device-gfx1100 and matched rocm-sdk packages
  • Windows arch detection through the driver's OpenCL runtime, with the name table
    demoted to a fallback, and VRAM read from the device rather than the BAR aperture
  • Extract InstallTorchAsync and add the GetRocmProfile seam, so packages declare
    their ROCm intent instead of calling the helper directly
  • Migrate the remaining packages: SwarmUI link, reForge, Forge Neo, InvokeAI,
    OneTrainer, Wan2GP
  • Enable the remaining packages on Linux; OneTrainer stays on its upstream
    requirements-rocm.txt
  • Dev SDK on Linux, extra commands dispatched per platform
  • Auto-expand rocm-sdk-devel with rocm-sdk init at install time
  • Stop the requirements step from resolving torch from PyPI, which is what drags the
    nvidia-* stack into a ROCm venv
  • Move the hardcoded fallback ROCm index ("rocm7.14") into the profile index kind

Testing

  • Every commit builds and keeps dotnet test --filter "~Rocm|~ProcessRunnerTests" green
    (71 cases at the time of writing).
  • Windows: install and upgrade a ROCm package on a gfx1201 based VM, comparing resolved
    torch/torchvision/rocm-sdk-devel, the emitted pip command and the verification output
    before and after each behavioural commit.
  • Linux: install and run ROCm packages on the gfx1100 workstation, with same methodologies with package function tests.

Notes

  • Windows behaviour is intended to be unchanged by the structural commits. Where a commit
    does change Windows behaviour, it says so and why (the CDNA and SDPA commit is one).
  • The Linux path uses AMD's whl-next feed, which serves linux_x86_64 wheels and the
    same per-arch device packages as Windows. Upstream PyTorch's index (download.pytorch.org) remains available per package where a package needs/requires it, or to explicitly match upstream (ex: OneTrainer).

- Pass --upgrade-package and --reinstall-package for torch, torchvision and torchaudio instead of blanket --upgrade and --force-reinstall on the helper-managed ROCm torch install
- Stop the resolver from re-evaluating transitive dependencies against the multi-arch index, where numpy is only published for cp312+ (2.5.2), which fails on 3.11 venvs and overrides per-package numpy pins (ComfyUI <2, reForge 1.26.4, Wan2GP 2.1.2)
- Keep the torch pairing intact: amd-torch-device-gfx* and triton are exact-pinned by the resolved wheels, so they still follow the torch build, and raised floors are still enforced
- Leave declared transitive needs to the package profile pip args, where they stay visible and reviewable
- Make ApplyRocmTorchInstallOptions internal and pass it the overrides list so the emitted flags can be asserted
- Add tests covering an upgrading profile (no blanket flags, three pairs of each scoped flag) and a non-upgrading one (reinstall without upgrade)
- Map MI100 and MI210 by name to gfx908 and gfx90a, covering the PCIe-slot Instincts
- Add gfx908, gfx90a, gfx942 and gfx950 to TryGetCanonicalArchitecture; the stable multi-arch feed publishes device packages for all four
- Leave gfx942 and gfx950 without name entries, since the feed ships linux_x86_64 device wheels for them and no win_amd64 ones, so resolving them from an adapter name would produce an install Windows cannot satisfy; they are picked up by the KFD detector on Linux
- Add SupportsFusedSdpa/PreferMathSdpaFallback keyed to the AOTriton image list (gfx90a, gfx942, gfx950, gfx11xx, gfx120x) and route the math-SDP fallback through it, so CDNA2+ keeps its fused kernels while gfx908 falls back to math like any target without AOTriton images
- Map RX 9050 to gfx1200 alongside the existing 9060 mapping
- Cover the gate, the CDNA name resolution and the predicate with tests
…nments

- Add ProcessRunner.UnsetEnvironmentVariable, a sentinel value that removes the named variable from the child environment instead of setting it
- Mark ROCM_PATH, ROCM_HOME, HIP_PATH, ROCM_DIR and HIP_DIR for removal in helper-managed launch environments so a system ROCm or HIP SDK cannot shadow the venv's self-contained pip SDK
- Gate it behind RocmEnvironmentOptions.SanitizeRocmSdkEnvironment, default on, so installs that intentionally use a system or PyTorch-bundled ROCm can opt out
- Apply the scrub before user environment overrides, so an explicit user value still wins
- Cover the sentinel behaviour and the scrub with tests
- Rename WindowsRocmSupport to RocmSupport, the six *WindowsRocmProfile types to *RocmProfile, and InstallWindowsRocmPackageCommandStep to InstallRocmPackageCommandStep
- Rename the helper members that will be shared across platforms: GetLaunchNoticeLines, ShouldApplyLaunchEnvironment, ApplyRocmLaunchDefaults and EnsureRocmSdkDevelAsync
- Rename the BaseGitPackage helpers to HasRocmSupport and GetRocmCompatibility, and the GPU predicates to HasRocmSupportedGpu, GetRocmSupportedGpu and IsRocmSupportedGpu
- Rename IsUsableWindowsNativeTorchBuild to IsUsableRocmTorchBuild, plus the ComfyUI ROCm command runner and flag that carried a Windows prefix
- Reword the comments and doc comments that described the helper's identity as Windows-specific rather than describing a Windows-specific code path: class summaries, the launch-option hooks, the AOTriton gate (which is arch-based, not OS-based), the compatibility and runtime context summaries, the ComfyUI eligibility and cross-attention notes, and the Forge Neo launch-notice note
- Keep the Windows references where Windows is the actual subject: the bitsandbytes Windows wheel notes, the Reforge accelerate note about Windows ROCm torch builds, the DirectML branch, the Compat.IsWindows gate comments, the platform-contrast notes, and the two install members (BuildWindowsNativeInstallConfig, InstallWindowsNativeTorchAsync) that the profile seam removes later
- Add RocmInstallTarget and RocmIndexKind (AMD stable, AMD nightly, PyTorch rocm7.2, PyTorch rocm7.14); the target carries the index URL, the device extra and the index's capabilities: per-architecture device packages, SDK devel and whether torch must be paired with torchvision
- Add RocmSupport.ResolveTarget, resolving those from the architecture and an optional profile override, keeping Vega on AMD's nightly feed and everything else on stable
- Replace GetMultiArchPythonPackageIndexUrl with GetIndexUrl plus ResolveTarget, so the URL follows the index kind rather than being inferred at each call site
- Read the index URL and device extra from the target in InstallWindowsNativeTorchAsync, EnsureRocmSdkDevelAsync and the Forge Neo profile; the SDK step returns early when the index publishes no rocm-sdk-devel
- Drop RocmMachineState.MultiArchDeviceExtra, since the target owns that decision now, and add RocmPackageProfile.Index for per-package overrides
- Windows behaviour is unchanged: same feed URLs, same device extra, same nightly rule
- Cover Windows stable, Vega nightly, the AMD feed, a PyTorch override with no device extras or SDK step, and an unsupported architecture
- Add RocmArchDetector, which reads gfx_target_version from every KFD topology node, skips CPU nodes, and decodes the value into its ISA name (110000 to gfx1100, 110500 to gfx1150, 100300 to gfx1030, 90010 to gfx90a)
- Cache the result per process; the nodes are written by the amdgpu module, so no ROCm userspace and no marketing-name table is involved
- Resolve the machine's architecture from the driver first on Linux, and fall back to the adapter name table only when KFD has no answer
- Let a driver-resolved architecture make the machine compatible even when no adapter name maps to a supported target, which is the case for cards the table has never heard of
- Correct the failure message, which claimed Windows-only architecture support
- Cover the decoder across RDNA2/3/3.5/4 and CDNA2/3 encodings, plus CPU-node skipping
…rder

- RocmArchDetector now returns one device per KFD node (arch, device index, SIMD count) instead of a bare architecture, and sorts nodes numerically so device indices match the order the runtime enumerates them
- Add SelectPreferred, which picks the device with the most compute: an APU reports a handful of SIMD units against hundreds on a discrete card, and node order carries no information about which is which
- Resolve the Linux architecture from that selection after filtering to targets the feed supports, so a 2 CU RDNA2 APU cannot shadow the discrete card and an unsupported node falls through to the next candidate
- Rank the name-based Windows candidates by memory the same way, which separates a laptop APU's carveout from a discrete adapter when the user has no preference
- PreferredGpu still wins over both rankings
- Tests cover node parsing, both node orders for an APU plus a dGPU, tie-breaking and the memory ranking
…achines

- Carry the selection through RocmMachineState and RocmRuntimeContext: the number of AMD GPU agents and, where known, the ROCm device index
- When more than one AMD GPU is present, helper-managed launches set ROCR_VISIBLE_DEVICES to that index, so an APU that enumerates first cannot become the device an app opens
- Leave single-GPU machines untouched, and skip the pin when the selection has no device index
- Nothing is written to settings; the value is rebuilt per launch and sits in the helper layer, so package and user overrides still win
- Tests cover the multi-GPU pin, the single-GPU no-op and the missing-index case
- Rename the install surface to InstallRocmTorchAsync and BuildRocmInstallConfig, and ResolveWindowsMachineState to ResolveMachineState, so the names no longer describe a Windows-only path
- Install from an index without per-architecture device packages: the upstream PyTorch feeds ship one multi-architecture wheel, so the device extra is optional and only required when the resolved index declares it
- Build the torch and torchvision requirements through one helper, so the requirement form follows the index instead of a hardcoded extra
- Drop RocmInstallTarget.RequiresPairResolution, since the pair resolver runs for every index and the flag had no consumer
- Rename the install verification step and remove Windows wording from it and from the SDK devel progress messages
- Update the interface documentation, which still described both methods as Windows-native and multi-arch specific
- Cover the requirement forms with and without a device extra
- Stop short circuiting the compatibility answer on non-Windows, so GetCompatibility is the single source of truth on both platforms
- Drop the Windows-only gate from ShouldApplyLaunchEnvironment and from ComfyUI's install, sage-attention check and launch environment paths
- ComfyUI now installs torch from the resolved index on Linux, for example on a gfx1100 box means AMD's stable feed with the device-gfx1100 extra and the matching rocm-sdk-devel, and picks up the helper's launch environment
- Move ComfyUI's fallback ROCm index from the rocm7.2 channel to rocm7.14, which is the upstream PyTorch channel the fallback path should target as a last resort
- Keep InvokeAI's launch environment gated to Windows, so only ComfyUI's behaviour changes here
- Make the experimental-support notice platform-neutral, since it now appears on Linux too
… report what it does

- Let the Development SDK command run on Linux
- Derive the ROCm line from the local label on the installed torch (2.14.0+rocm10.0.0 gives 10.0.0) and prefer a rocm-sdk-devel build that matches it, keeping the nightly build date token as the first match for dev builds
- Warn explicitly when that line has no published build and the newest is installed instead, since headers and libraries would then come from a different ROCm release than the runtime loading them
- Realign an already-installed development SDK at the end of every ROCm torch install or upgrade, so existing venvs stop drifting when torch moves
- Run `rocm-sdk init` after the devel package installs, to expand the tree eagerly; a non-zero exit is a warning, since the SDK also initialises lazily on first use
- Stream pip and init output into the install console through progress.AsProcessOutputHandler, so the dialog shows the resolve, download and install instead of only the final line
- Remove Windows specific labeling for devel-sdk install output and dialog title
- Tests covering label parsing, selection order, the exact match predicate and the empty-index case

This branch has not been deployed

No deployments
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.

1 participant