@@ -14,15 +14,16 @@ namespace LibreHardwareMonitor.Hardware.Cpu;
1414
1515internal class CpuLoad
1616{
17- private readonly float [ ] _threadLoads ;
17+ private static readonly bool _queryIdleTimeSeparated = QueryIdleTimeSeparated ( ) ;
1818
19+ private readonly double [ ] _threadLoads ;
20+ private double _totalLoad ;
1921 private long [ ] _idleTimes ;
20- private float _totalLoad ;
2122 private long [ ] _totalTimes ;
2223
2324 public CpuLoad ( CpuId [ ] [ ] cpuid )
2425 {
25- _threadLoads = new float [ cpuid . Sum ( x => x . Length ) ] ;
26+ _threadLoads = new double [ cpuid . Sum ( x => x . Length ) ] ;
2627 _totalLoad = 0 ;
2728
2829 try
@@ -51,30 +52,62 @@ private static bool GetWindowsTimes(out long[] idle, out long[] total)
5152 idle = null ;
5253 total = null ;
5354
54- //Query processor idle information
55+ //use the idle time routine only with a few specific windows 11 versions
56+ if ( _queryIdleTimeSeparated )
57+ return GetWindowsTimesFromIdleTimes ( out idle , out total ) ;
58+
59+ //Query processor performance information
60+ Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION [ ] perfInformation = new Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION [ 64 ] ;
61+ int perfSize = Marshal . SizeOf ( typeof ( Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ) ) ;
62+ if ( Interop . NtDll . NtQuerySystemInformation ( Interop . NtDll . SYSTEM_INFORMATION_CLASS . SystemProcessorPerformanceInformation , perfInformation , perfInformation . Length * perfSize , out int perfReturn ) != 0 )
63+ return false ;
64+
65+ idle = new long [ perfReturn / perfSize ] ;
66+ total = new long [ perfReturn / perfSize ] ;
67+ for ( int i = 0 ; i < total . Length ; i ++ )
68+ {
69+ idle [ i ] = perfInformation [ i ] . IdleTime ;
70+ total [ i ] = perfInformation [ i ] . KernelTime + perfInformation [ i ] . UserTime ;
71+ }
72+
73+ return true ;
74+ }
75+
76+ private static bool GetWindowsTimesFromIdleTimes ( out long [ ] idle , out long [ ] total )
77+ {
78+ idle = null ;
79+ total = null ;
80+
81+ Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION [ ] perfInformation = new Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION [ 64 ] ;
82+ int perfSize = Marshal . SizeOf ( typeof ( Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ) ) ;
5583 Interop . NtDll . SYSTEM_PROCESSOR_IDLE_INFORMATION [ ] idleInformation = new Interop . NtDll . SYSTEM_PROCESSOR_IDLE_INFORMATION [ 64 ] ;
5684 int idleSize = Marshal . SizeOf ( typeof ( Interop . NtDll . SYSTEM_PROCESSOR_IDLE_INFORMATION ) ) ;
85+
86+ //Query processor performance and idle information
87+ //these 2 methods must be called as directly as possible one after the other
88+
89+ //Query processor idle information
5790 if ( Interop . NtDll . NtQuerySystemInformation ( Interop . NtDll . SYSTEM_INFORMATION_CLASS . SystemProcessorIdleInformation , idleInformation , idleInformation . Length * idleSize , out int idleReturn ) != 0 )
5891 return false ;
5992
6093 //Query processor performance information
61- Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION [ ] perfInformation = new Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION [ 64 ] ;
62- int perfSize = Marshal . SizeOf ( typeof ( Interop . NtDll . SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION ) ) ;
63- if ( Interop . NtDll . NtQuerySystemInformation ( Interop . NtDll . SYSTEM_INFORMATION_CLASS . SystemProcessorPerformanceInformation ,
64- perfInformation ,
65- perfInformation . Length * perfSize ,
66- out int perfReturn ) != 0 )
67- {
94+ if ( Interop . NtDll . NtQuerySystemInformation ( Interop . NtDll . SYSTEM_INFORMATION_CLASS . SystemProcessorPerformanceInformation , perfInformation , perfInformation . Length * perfSize , out int perfReturn ) != 0 )
6895 return false ;
69- }
7096
71- idle = new long [ idleReturn / idleSize ] ;
72- for ( int i = 0 ; i < idle . Length ; i ++ )
73- idle [ i ] = idleInformation [ i ] . IdleTime ;
97+ int perfItemsCount = perfReturn / perfSize ;
98+ int idleItemsCount = idleReturn / idleSize ;
7499
75- total = new long [ perfReturn / perfSize ] ;
76- for ( int i = 0 ; i < total . Length ; i ++ )
100+ if ( perfItemsCount != idleItemsCount )
101+ return false ;
102+
103+ idle = new long [ perfItemsCount ] ;
104+ total = new long [ perfItemsCount ] ;
105+
106+ for ( int i = 0 ; i < perfItemsCount ; i ++ )
107+ {
108+ idle [ i ] = idleInformation [ i ] . IdleTime ;
77109 total [ i ] = perfInformation [ i ] . KernelTime + perfInformation [ i ] . UserTime ;
110+ }
78111
79112 return true ;
80113 }
@@ -132,12 +165,12 @@ private static bool GetUnixTimes(out long[] idle, out long[] total)
132165 return true ;
133166 }
134167
135- public float GetTotalLoad ( )
168+ public double GetTotalLoad ( )
136169 {
137170 return _totalLoad ;
138171 }
139172
140- public float GetThreadLoad ( int thread )
173+ public double GetThreadLoad ( int thread )
141174 {
142175 return _threadLoads [ thread ] ;
143176 }
@@ -157,28 +190,45 @@ public void Update()
157190 if ( newIdleTimes == null )
158191 return ;
159192
160- float total = 0 ;
193+ double total = 0 ;
161194 int count = 0 ;
162195 for ( int i = 0 ; i < _threadLoads . Length && i < _idleTimes . Length && i < newIdleTimes . Length ; i ++ )
163196 {
164- float idle = ( newIdleTimes [ i ] - _idleTimes [ i ] ) / ( float ) ( newTotalTimes [ i ] - _totalTimes [ i ] ) ;
165- _threadLoads [ i ] = 100f * ( 1.0f - Math . Min ( idle , 1.0f ) ) ;
197+ double idle = ( newIdleTimes [ i ] - _idleTimes [ i ] ) / ( double ) ( newTotalTimes [ i ] - _totalTimes [ i ] ) ;
198+ idle = idle < 0.0 ? 0.0 : idle ;
199+ idle = idle > 1.0 ? 1.0 : idle ;
200+
201+ double load = 100.0 * ( 1.0 - Math . Min ( idle , 1.0 ) ) ;
202+ _threadLoads [ i ] = Math . Round ( load , 2 ) ;
166203 total += idle ;
167204 count ++ ;
168205 }
169206
170207 if ( count > 0 )
171208 {
172- total = 1.0f - ( total / count ) ;
173- total = total < 0 ? 0 : total ;
209+ total = 1.0 - ( total / count ) ;
210+ total = total < 0.0 ? 0.0 : total ;
211+ total = total > 1.0 ? 1.0 : total ;
174212 }
175213 else
176214 {
177215 total = 0 ;
178216 }
179-
180- _totalLoad = total * 100 ;
217+
218+ _totalLoad = Math . Round ( total * 100.0 , 2 ) ;
181219 _totalTimes = newTotalTimes ;
182220 _idleTimes = newIdleTimes ;
183221 }
222+
223+ private static bool QueryIdleTimeSeparated ( )
224+ {
225+ if ( Software . OperatingSystem . IsUnix )
226+ return false ;
227+
228+ // From Windows 11 22H2 the CPU idle time returned by SystemProcessorPerformanceInformation is invalid, this issue has been fixed with 24H2.
229+ OperatingSystem os = Environment . OSVersion ;
230+ Version win1122H2 = new Version ( 10 , 0 , 22621 , 0 ) ;
231+ Version win1124H2 = new Version ( 10 , 0 , 26100 , 0 ) ;
232+ return os . Version >= win1122H2 && os . Version < win1124H2 ;
233+ }
184234}
0 commit comments