fan: multi-fan RPM with sysfs hwmon fallback for Battlemage/xe (Arc P… - #148
fan: multi-fan RPM with sysfs hwmon fallback for Battlemage/xe (Arc P…#148thevisad wants to merge 1 commit into
Conversation
|
Related to #146 |
|
Hi @thevisad thanks for the contributions! No issues with Windows build or runtime for this PR as well as #149 on Windows Server {2022,2025} and w/ Visual Studio {17(2022),18(2026)}. I really need to set up build actions... :). I'll take a proper look today and should be able to grab a multi-tile system for verification there as well. |
|
@savery42 thanks! One small heads-up from a self-check on my end, since it slipped past both the Linux build and your Windows build: I compile-checked the two internal util TUs standalone under MSVC with /WX, and it surfaced a C4273 (inconsistent dll linkage) on this PR — the internal xpum::hwmon fan helpers in hwmon_fan_utils.h were annotated LIBXPUM_API, i.e. exported from the DLL. That's inconsistent with the temperature helpers (which are plain) and with the goal of keeping them off the exported surface. The full DLL build resolves the macro consistently so it stays green, which is why your Windows build was clean, and it's benign on Linux, so it hid on both sides; only a standalone /WX compile flagged it. Fixed: dropped LIBXPUM_API from the five internal decls. meson test is still 11/11, and both util TUs now compile clean under MSVC /std:c++20 /WX (VS 2022). Pushed to the branch, head 4c089ee. #149 (temperature) was already clean — its helpers never carried the macro. Appreciate you grabbing a multi-tile box for verification — thanks for taking the time on these. |
savery42
left a comment
There was a problem hiding this comment.
Same general comment on the temp PR regrding OS specific code to be placed in the OAL
| std::ostringstream oss; | ||
| oss << std::fixed << std::setprecision(precision); | ||
| oss << "Fan " << fanId << ": " << value << unit; | ||
| return oss.str(); |
There was a problem hiding this comment.
// c++20 style / nit
| std::ostringstream oss; | |
| oss << std::fixed << std::setprecision(precision); | |
| oss << "Fan " << fanId << ": " << value << unit; | |
| return oss.str(); | |
| return std::format("Fan {}: {:.{}f}{}", fanId, value, precision, unit); |
| static const std::string prefix = "fan"; | ||
| static const std::string suffix = "_input"; |
There was a problem hiding this comment.
// c++20 / nit
| static const std::string prefix = "fan"; | |
| static const std::string suffix = "_input"; | |
| constexpr std::string_view prefix = "fan"; | |
| constexpr std::string_view suffix = "_input"; |
Avoids allocation
| if (name.size() <= prefix.size() + suffix.size()) { | ||
| return false; | ||
| } | ||
| if (name.compare(0, prefix.size(), prefix) != 0) { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
// c++20 / nit
starts_with(), ends_with()
| for (char c : digits) { | ||
| if (c < '0' || c > '9') { | ||
| return false; | ||
| } | ||
| } |
There was a problem hiding this comment.
| for (char c : digits) { | |
| if (c < '0' || c > '9') { | |
| return false; | |
| } | |
| } |
std::from_chars will already stop at the first non-digit, so caught by res.ptr != end
Report fan RPM on the tested Arc Pro B70 when Level Zero Sysman enumerates no fan handles. Move hwmon traversal into the OS abstraction layer, preserve Level Zero as authoritative when a handle exists, retain valid 0-RPM readings, add the RPM stats row, and cover discovery/parsing with Linux tests and Windows compile validation. Signed-off-by: thevisad <373694+thevisad@users.noreply.github.com>
|
@savery42 Thanks. Same OAL treatment here. OAL move. The fan hwmon traversal is now in oal/lin/hwmon_fan.cpp: getHwmonInputPaths(bdf, prefix) returns {zero-based fan index -> fanN_input path} (strict fan_input matching, index-overflow rejected), with a Windows stub in oal/win/hwmon_fan.cpp. OAL only discovers the fanN_input paths; the RPM read/parse/validate and the Level-Zero-vs-sysfs decision stay in hal (hwmon_fan_utils). Per your point, I deliberately did not push RPM value interpretation down into the traversal; OAL stays pure filesystem discovery. Contract. decideFanRpmSource: successful enumeration with >= 1 handle picks Level Zero; enumeration reporting no fan or denying an unprivileged process picks sysfs (the #146 normal-user case); 0 handles picks sysfs; any other enumeration failure propagates. Genuine per-fan identity: getAllSpeedsRpm iterates all Level Zero handles keyed by real fan id, and in the zero-handle case reads every fanN_input OAL resolved, so no fan is dropped. Per-fan row formatting moved to std::format, locked by a cmd_stats regression test. Tests. New OAL suite oal/lin/test/hwmon_fan_tests (7 / 26), plus fan_tests (14 / 53) and cmd_stats_test (3 / 8). meson test: 12/12 suites green. Hardware: the B70 reports Fan Speed (RPM) Fan 0: 1177 RPM tracking fan1_input. Scope: the tested B70 exposes a single fan hwmon node; the multi-fan paths are unit-tested but not run on multi-fan silicon (called out in the PR body). Windows. The touched surface (oal/win/hwmon_fan.cpp, hwmon_fan_utils.cpp) is verified clean with MSVC 19.44 at /std:c++20 /WX, and that pass actually caught a real defect (the fan internal helpers were LIBXPUM_API-exported; removed). This is a compile check of the modified TUs, not a full Windows product build. Single DCO-signed commit; the PR description is updated to match. Relates to #146. |
Description
xpu-smi statsreportsFan Speed (RPM): N/Aon the Intel Arc Pro B70 (Battlemage,xedriver) eventhough the fan is spinning and its RPM is published on the PCI device's hwmon node (
fanN_input): LevelZero sysman enumerates no fan handle on this device. This PR adds per-fan RPM reporting with a sysfs-hwmon
fallback for that case, a correct Level Zero error contract, genuine per-fan identity, and validated
discovery, while leaving the existing percent path byte-identical where Level Zero exposes fan handles.
What it does
decideFanRpmSource(enumResult, fanCount):enumeration failure → propagate;
fanCount == 0→ sysfs;fanCount >= 1→ Level Zero. sysfs isnever consulted when a fan handle exists.
getSpeedRpmByIdreads a specific L0 handle (propagates its error; acceptsrpm >= 0);getAllSpeedsRpmiterates all L0 handles keyed by real fan id, and in the zero-handlecase enumerates all
fanN_inputnodes (fan1_input→0,fan2_input→1, …). The stats collectorkeys samples by real fan id — no fan is dropped.
resolveSysfsHwmonsetszes_pci_properties_t.stype(required by the Level Zero API contract), scansall
hwmon*nodes, and accepts a candidate only when a real RPM value parses (not merely that thefile opens), so a malformed node cannot shadow a valid one.
readFanInputFromDirreturnsZE_RESULT_ERROR_INVALID_NULL_POINTERfor a null out-pointer;parseFanInputIndexusesstd::from_charsand rejects overflow.xpum::hwmonutility (hwmon_fan_utils.{h,cpp}), not on the exportedfanclass. The HAL getters propagate Level Zero errors and never substitute a sysfs value for a realdriver failure; the stats collector treats an unavailable RPM sample as absent (like other optional
xpu-smi statsmetrics), so it does not makexpu-smiexit with the Level Zero failure.Testing
decideFanRpmSourcematrix incl. inconsistentfanCount>0 && handles==nullptr→internal error; RPM parse incl.0, malformed, overflow; index parsereadFanInputFromDiragainst a temp hwmon dir incl. null-ptr classification;percent-rendering unchanged vs
" RPM"rendering). Fullmeson test: 11/11 suites.xe, kernel7.0.0-28-generic, Level Zero1.27.0):xpu-smi statsreportsFan Speed (RPM) Fan 0: 1177 RPM, tracking rawfan1_input;Fan Speed (%)staysN/A; discoveryselected the correct hwmon node.
Scope / limitations
fanN_inputin the fallback) buthardware-validated only on the single-fan B70; the multi-fan paths are exercised by unit tests, not on
multi-fan silicon.
zesFanGetStatefailing on a present handle) iscovered by the selection logic but not unit-mocked, because injecting that failure would require
fabricating a device handle; documented in the code.
EAGAINon a back-to-back read, so hwmon resolution isvalidated once and cached rather than re-read every sample.
std::filesystem). Windows was not build-tested. The doctesttest targets require a
doctestpackage in CI.Fixes:
Relates-To:
Type of change
Affected components
hal— Hardware Abstraction Layerial— Interface / Application Layeroal— OS Abstraction Layerxpumd— XPU Manager Daemoncli/smici/ build systemChecklist
Signed-off-by(DCO)Fan Speed (RPM)row /fan.speed_rpmmetric is described here; no new CLI option