http://bugs.winehq.org/show_bug.cgi?id=58397
Bug ID: 58397 Summary: Missing power_supply class attributes for NtPowerInformation blocks threads and causes fps stutter Product: Wine Version: unspecified Hardware: x86-64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: P2 Component: ntdll Assignee: wine-bugs@winehq.org Reporter: rtdiasmendes@gmail.com Distribution: Mint
Created attachment 78805 --> http://bugs.winehq.org/attachment.cgi?id=78805 logs mentioned in the bug Description
Affected Application:
- Tainted Grail: Fall of Avalon
Observed Symptoms:
- Frametime spikes from ~5ms to ~100ms occurring at ~1Hz intervals.
- GPU frame dispatch (via DXVK) is delayed due to thread blocking in Wine’s battery status polling logic.
Performance Analysis (see attached logs):
- strace shows constant, repeated attempts to read nonexistent files in /sys/class/power_supply/BAT1/
- perf stat reveals ~8,270 openat() syscalls in 10 second window (on game title screen).
- perf record/report shows significant thread time consumed inside NtPowerInformation-related logic in ntdll.
Root Cause:
- In dlls/ntdll/unix/system.c, the function fill_battery_state() (Linux version) hardcodes the use of attributes: "charge_now" "charge_full" and "current_now".
- These attributes are not universally present in /sys/class/power_supply/. On some systems, particularly those using energy-based reporting (µWh), the ABI-compliant alternatives are: "energy_now", "energy_full" and "power_now".
- Since Wine looks only for the "charge_*" files and fails to return expected information, the game loops the query constantly which results in openat() being used in a tight polling loop - blocking threads and causing intermittent CPU stalls that propagate to the GPU rendering pipeline.
Solution 1: - Verify what attributes are present in the power_supply class. - Implement logic with supplied attributes.
Solution 2: - Attempt to read the already-implemented files. - Fallback to "energy_*" if those are not present.
I gather solution 1 has a more consistent impact across different systems, while solution 2 is more lightweight on systems with "charge_*" and heavier on others.
Further reading: - https://docs.kernel.org/power/power_supply_class.html - https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-power - https://github.com/torvalds/linux/blob/master/include/linux/power_supply.h - https://github.com/torvalds/linux/blob/master/drivers/power/supply/power_sup...
Note:
Attribute "scope", while implemented in the kernel, is undocumented in the power_supply_class docs. Will later check if the rest of the documentation is up to date and raise the appropriate issue upstream. Until then, do not assume it correctly reflects the kernel implementation.
Disclaimer:
This issue was identified and reproduced using Proton-GE, Proton (Steam Runtime), Soda and Flatpak's build. I am reporting it here for visibility and discussion since it appears to originate from WineHQ’s upstream implementation of NtPowerInformation.
Out-of-scope commentary:
While Wine's behavior of querying /sys/class/power_supply/ on every NtPowerInformation() call correctly emulates the Windows API semantics, it has unintended performance implications on Linux. This is due to the fact that retrieving battery information from sysfs involves real filesystem I/O, including frequent failed lookups on systems that expose energy_* instead of charge_* attributes.
Therefore, applications may call NtPowerInformation() without prioritizing caching or proper fallback logic as they expect the operation to have a lower-cost then it does on Linux - causing significant and unnecessary performance degradation.
Will raise this for an enchancement in the proper channels.
http://bugs.winehq.org/show_bug.cgi?id=58397
Tomás Mendes rtdiasmendes@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |rtdiasmendes@gmail.com
--- Comment #1 from Tomás Mendes rtdiasmendes@gmail.com --- Just to clarify:
The strace messages seen on the attachment repeat in loop while the game is running.
http://bugs.winehq.org/show_bug.cgi?id=58397
--- Comment #2 from Tomás Mendes rtdiasmendes@gmail.com --- Mirrored issue downstream:
https://github.com/ValveSoftware/Proton/issues/8834
http://bugs.winehq.org/show_bug.cgi?id=58397
Tomás Mendes rtdiasmendes@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Blocks| |58401
http://bugs.winehq.org/show_bug.cgi?id=58397
Tomás Mendes rtdiasmendes@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Blocks|58401 |
http://bugs.winehq.org/show_bug.cgi?id=58397
Tomás Mendes rtdiasmendes@gmail.com changed:
What |Removed |Added ---------------------------------------------------------------------------- Depends on| |58401