Proton version: GE-Proton10-34 (reproduced on multiple Proton versions; root
cause verified present in current upstream Wine, see below)
Issue description
The game polls Windows battery status (GetSystemPowerStatus /
NtPowerInformation(SystemBatteryState)) ~46×/s from its main thread — it is a
Unity 2021 title and Unity exposes SystemInfo.batteryStatus.
Wine answers every call by re-reading /sys/class/power_supply/* — see fill_battery_state() in dlls/ntdll/unix/system.c (current upstream master,
~line 4347): opendir + per-attribute reads of type/status/voltage_now/
charge_full/charge_now on each call, no caching. Windows answers this API from
cached data.
The Linux ACPI battery driver caches attribute values for 1 s
(/sys/module/battery/parameters/cache_time = 1000 default). Once per second
one read misses that cache and performs a synchronous embedded-controller
query. On this laptop (Lenovo IdeaPad, Ryzen 7 5800H) that query takes ~66 ms
with the game's main thread blocked:
read of BAT0/energy_now after cache expiry: 66.1 ms
immediate cached re-read: 0.093 ms
Result: an ~82 ms frame spike every ~1.07 s (1 s kernel cache + 66 ms stall +
frame catch-up), i.e. a metronomic stutter for the whole play session.
MangoHud frametime logs: median spike 82 ms, median interval 1.071 s, ~100
spikes per 90 s. strace shows the main thread blocked ~65 ms in read() of
/sys/class/power_supply/ADP0/online, BAT0/* on the same period.
Not reproducible on native Windows (API is cached there) or on desktops
(no battery to read), which makes it look like a game/hardware problem —
it is likely underdiagnosed among laptop players. Main menu is unaffected
(no battery polling there), gameplay is affected from the first second.
Confirmed workaround
echo 600000 > /sys/module/battery/parameters/cache_time removes the stutter
completely (verified with frametime logs). Suggested proper fix: cache battery
state in ntdll for a few seconds, or refresh it off the calling thread.
Per-game workaround (auto-toggle via Steam launch options)
To avoid leaving the long cache system-wide, the following applies it only
while the game runs and restores the default on exit (including crashes):
Root-owned helper /usr/local/bin/battery-cache-set (validates input,
can only write this one file):
#!/bin/bash
if [[ "$1" =~ ^[0-9]{3,7}$ ]]; then
echo "$1" > /sys/module/battery/parameters/cache_time
else
echo "usage: battery-cache-set <milliseconds>" >&2
exit 1
fi
Sudoers rule (file in /etc/sudoers.d/, mode 440, replace YOURUSER):
Compatibility Report
System Information
cause verified present in current upstream Wine, see below)
Issue description
The game polls Windows battery status (GetSystemPowerStatus /
NtPowerInformation(SystemBatteryState)) ~46×/s from its main thread — it is a
Unity 2021 title and Unity exposes SystemInfo.batteryStatus.
Wine answers every call by re-reading /sys/class/power_supply/* — see
fill_battery_state()indlls/ntdll/unix/system.c(current upstream master,~line 4347): opendir + per-attribute reads of type/status/voltage_now/
charge_full/charge_now on each call, no caching. Windows answers this API from
cached data.
The Linux ACPI battery driver caches attribute values for 1 s
(
/sys/module/battery/parameters/cache_time= 1000 default). Once per secondone read misses that cache and performs a synchronous embedded-controller
query. On this laptop (Lenovo IdeaPad, Ryzen 7 5800H) that query takes ~66 ms
with the game's main thread blocked:
Result: an ~82 ms frame spike every ~1.07 s (1 s kernel cache + 66 ms stall +
frame catch-up), i.e. a metronomic stutter for the whole play session.
MangoHud frametime logs: median spike 82 ms, median interval 1.071 s, ~100
spikes per 90 s. strace shows the main thread blocked ~65 ms in read() of
/sys/class/power_supply/ADP0/online, BAT0/* on the same period.
Not reproducible on native Windows (API is cached there) or on desktops
(no battery to read), which makes it look like a game/hardware problem —
it is likely underdiagnosed among laptop players. Main menu is unaffected
(no battery polling there), gameplay is affected from the first second.
Confirmed workaround
echo 600000 > /sys/module/battery/parameters/cache_timeremoves the stuttercompletely (verified with frametime logs). Suggested proper fix: cache battery
state in ntdll for a few seconds, or refresh it off the calling thread.
Per-game workaround (auto-toggle via Steam launch options)
To avoid leaving the long cache system-wide, the following applies it only
while the game runs and restores the default on exit (including crashes):
Root-owned helper
/usr/local/bin/battery-cache-set(validates input,can only write this one file):
Sudoers rule (file in /etc/sudoers.d/, mode 440, replace YOURUSER):
User wrapper script (executable, anywhere in your home):
Steam launch options for the game:
Note: while the long cache is active, desktop battery percentage and
low-battery warnings update lazily between AC plug/unplug events.
Reproduction
charge_now attribute twice, >1 s apart, and time the reads).
MangoHud frametime CSVs (before / after workaround) and system information:
https://gist.github.com/johndphipps-design/440efe100d0476da69f0c1d39c7a8b48
strace captures available on request.