# Changelog — XPUSYS-Monitor-NG All notable changes for the Windows-native AMD ROCm port are documented here. This fork is based on [ComfyUI-XPUSYS-Monitor](https://github.com/allanmeng/ComfyUI-XPUSYS-Monitor) v1.0.3 by allanmeng. The version below tracks deviations from that baseline. --- ## v0.1.0 — 2026-06-08 ### Intent The upstream AMD provider (`providers/amd.py`) relied on `rocm_smi_lib` — a Linux-only Python package that wraps `librocm_smi64.so`. On Windows with AMD ROCm, `pip install rocm_smi_lib` fails because the native `.so` library does not exist. This port replaces every `rocm_smi` call with a Windows-native alternative. ### Detection: `providers/__init__.py` **Problem:** The upstream detection function `_is_amd_rocme()` accessed `torch.version.roc` directly. On Windows AMD ROCm builds (tested with PyTorch 2.9.1+rocm7.2.1), the `roc` attribute **does not exist** on the `torch.version` module — raising `AttributeError`. The outer `try/except` caught it and returned `False`, causing the auto-detector to load `NvidiaProvider` instead of `AMDProvider`. The GPU name fallback code after the `roc` check was unreachable. **Fix:** Replaced bare attribute access with `getattr(torch.version, 'roc', None)`. Added a secondary signal `getattr(torch.version, 'hip', None)` for HIP-based detection. Added a tertiary fallback scanning the GPU device name (via `torch.cuda.get_device_name(0)`) for the markers `"amd"`, `"radeon"`, or `"advanced micro devices"`. ### VRAM: `providers/amd.py` → `_read_vram()` **Problem:** The upstream AMD provider used `rocm_smi.getMemFreeVdev(0)`, `rocm_smi.getMemSizeVdev(0)`, and `rocm_smi.getMemUsedVdev(0)` for driver-level VRAM reads. Without `rocm_smi_lib`, the fallback returned only total VRAM from `torch.cuda.get_device_properties(0).total_memory`, leaving `free` and `driver_used` as `0.0` — making the PRED predictor and VRAM capsule unusable. **Fix:** Replaced all three `rocm_smi` VRAM calls with `torch.cuda.mem_get_info(device_index)`, which returns `(free_bytes, total_bytes)` from the AMD driver on ROCm 6+ for Windows. Moved the call inside a `try/except` with a fallback to `get_device_properties().total_memory` if `mem_get_info` is unavailable. Added `torch.cuda.synchronize()` before reads to force CUDA/HIP context creation (some ROCm builds defer context init until the first GPU operation, returning zeros otherwise). ### GPU Load: `providers/amd.py` → `_read_gpu_load()` **Problem:** The upstream used `rocm_smi.getGpuBusyVdev(0)`. No standard Python-accessible equivalent exists on Windows AMD. **Solution attempted — PDH (ctypes):** Added `_PdhQuery` to `providers/_utils.py` using `ctypes` wrappers around `pdh.dll` to query `\GPU Engine(*)\Utilization Percentage`. The wildcard counter path does not aggregate correctly with `PdhGetFormattedCounterValue` (returns only the first matching instance). This approach was disabled for AMD in favour of typeperf. **Solution adopted — typeperf:** Added `_TypeperfGpuQuery` to `providers/_utils.py`. Uses Windows built-in `typeperf.exe` (available since Vista) with the same counter path `\GPU Engine(*)\Utilization Percentage`. Output is CSV; we parse columns after the timestamp and take `max()` across all engine instances. Averaging would dilute the signal (hundreds of engine columns including idle video/copy/timer). `max()` correctly reflects the busiest engine (typically 3D or Compute during a ComfyUI workflow). At idle all engines report ~0%, so the capsule drops cleanly. **Attempted — amdsmi:** Added `_AmdSmiGpuQuery` to `providers/_utils.py` using the official AMD SMI Python library (`pip install amdsmi`). On Windows the library searches for `libamd_smi.so` (a Linux shared object) at `D:\opt\rocm\lib\`, which does not exist on the tested configuration. The class logs a single info line and gracefully skips if `amdsmi` is not installed or fails to load. ### GPU Frequency / Temperature / Power: `providers/amd.py` **Problem:** The upstream used `rocm_smi.getSingleClockSpeed(0)`, `rocm_smi.getTempVdev(0)`, `rocm_smi.getPowerVdev(0)`, and `rocm_smi.getPowerCapVdev(0)` for clock speed, temperature, and power draw. The AMD Windows WDDM driver on the RX 9070 XT does not register these performance counters through any standard Python-accessible interface. **Resolution:** All three return sentinel values matching the `GPUSnapshot` contract defaults — `0.0` for frequency, `-1.0` for temperature, `(-1.0, 0.0, False)` for power. The frontend displays these as unavailable (`--` / greyed out), identical behaviour to when the Intel provider cannot open Level Zero handles or the NVIDIA provider cannot reach pynvml. ### Shared Utilities: `providers/_utils.py` (new file) **Problem:** The upstream AMD provider imported system-level CPU and RAM utility functions (`_get_cpu_info`, `_read_cpu_ram_stats`, `_read_commit_charge`) from `providers/intel.py`. This created a spurious dependency on the Intel Level Zero provider code for non-Intel users. **Fix:** Extracted these three functions plus `_is_admin()` into a new shared module `providers/_utils.py`. Also relocated `_PdhQuery`, `_TypeperfGpuQuery`, and `_AmdSmiGpuQuery` into the same module. Both `amd.py` and `nvidia.py` now import from `_utils.py` instead of `intel.py`. The `intel.py` module is no longer needed unless the Intel provider is loaded (auto-detection fallback path). ### NVIDIA Provider: `providers/nvidia.py` **Change:** Updated import path from `from .intel import ...` to `from ._utils import ...`. No functional change — identical utility functions. ### Frontend: `web/xpu_monitor.js` **Problem:** The `__init__.py` declares `WEB_DIRECTORY = "./web"` which tells ComfyUI to serve the JavaScript toolbar extension from a `web/` subdirectory. This directory was not included in the initial workspace, causing the toolbar capsules to not render. **Fix:** Added `web/xpu_monitor.js` (56 KB, identical to upstream v1.0.3). The file is the full JavaScript frontend that renders the seven-capsule status bar, handles WebSocket updates from the backend, and provides the VRAM predictor UI. No modifications were made. ### Dependencies: `requirements.txt` **Change:** `rocm_smi_lib` commented out with an explanatory note. No replacement dependency added — VRAM reads use `torch.cuda` (bundled with the ROCm PyTorch installation), GPU load reads use `typeperf` (Windows built-in), and CPU/RAM reads use `psutil` (already required by the upstream). ### Project Metadata: `pyproject.toml` **Changes:** - Repository URL updated to `https://github.com/forkless/XPUSYS-Monitor-NG` - Display name set to `XPUSYS-Monitor-NG` - Description updated to reflect the POC nature - Publisher ID set to `forkless` ### Documentation - `README.md` — rewritten for the fork with POC context, status table, relationship to upstream, tested hardware, support disclaimer, MIT license - `AMD.md` — detailed technical summary of every change, intent, and end result table - `LICENSE.md` — MIT license (matches upstream)