1
2
3
4
5 package oshi.hardware.platform.windows;
6
7 import static oshi.util.Memoizer.memoize;
8
9 import java.util.Arrays;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.Locale;
13 import java.util.Map;
14 import java.util.concurrent.TimeUnit;
15 import java.util.function.Supplier;
16 import java.util.stream.Collectors;
17
18 import oshi.jna.platform.windows.Kernel32.ProcessorFeature;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 import com.sun.jna.platform.win32.Advapi32Util;
23 import com.sun.jna.platform.win32.PowrProf.POWER_INFORMATION_LEVEL;
24 import com.sun.jna.platform.win32.VersionHelpers;
25 import com.sun.jna.platform.win32.Win32Exception;
26 import com.sun.jna.platform.win32.WinReg;
27 import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult;
28
29 import oshi.annotation.concurrent.ThreadSafe;
30 import oshi.driver.windows.LogicalProcessorInformation;
31 import oshi.driver.windows.perfmon.LoadAverage;
32 import oshi.driver.windows.perfmon.ProcessorInformation;
33 import oshi.driver.windows.perfmon.ProcessorInformation.InterruptsProperty;
34 import oshi.driver.windows.perfmon.ProcessorInformation.ProcessorFrequencyProperty;
35 import oshi.driver.windows.perfmon.ProcessorInformation.ProcessorTickCountProperty;
36 import oshi.driver.windows.perfmon.ProcessorInformation.ProcessorUtilityTickCountProperty;
37 import oshi.driver.windows.perfmon.SystemInformation;
38 import oshi.driver.windows.perfmon.SystemInformation.ContextSwitchProperty;
39 import oshi.driver.windows.wmi.Win32Processor;
40 import oshi.driver.windows.wmi.Win32Processor.ProcessorIdProperty;
41 import oshi.hardware.common.AbstractCentralProcessor;
42 import oshi.jna.Struct.CloseableSystemInfo;
43 import oshi.jna.platform.windows.Kernel32;
44 import oshi.jna.platform.windows.PowrProf;
45 import oshi.jna.platform.windows.PowrProf.ProcessorPowerInformation;
46 import oshi.util.GlobalConfig;
47 import oshi.util.ParseUtil;
48 import oshi.util.platform.windows.WmiUtil;
49 import oshi.util.tuples.Pair;
50 import oshi.util.tuples.Quartet;
51 import oshi.util.tuples.Triplet;
52
53
54
55
56 @ThreadSafe
57 final class WindowsCentralProcessor extends AbstractCentralProcessor {
58
59 private static final Logger LOG = LoggerFactory.getLogger(WindowsCentralProcessor.class);
60
61
62 private Map<String, Integer> numaNodeProcToLogicalProcMap;
63
64
65 private static final boolean USE_LOAD_AVERAGE = GlobalConfig.get(GlobalConfig.OSHI_OS_WINDOWS_LOADAVERAGE, false);
66 static {
67 if (USE_LOAD_AVERAGE) {
68 LoadAverage.startDaemon();
69 }
70 }
71
72
73 private static final boolean USE_CPU_UTILITY = VersionHelpers.IsWindows8OrGreater()
74 && GlobalConfig.get(GlobalConfig.OSHI_OS_WINDOWS_CPU_UTILITY, false);
75
76
77
78 private final Supplier<Pair<List<String>, Map<ProcessorUtilityTickCountProperty, List<Long>>>> processorUtilityCounters = USE_CPU_UTILITY
79 ? memoize(WindowsCentralProcessor::queryProcessorUtilityCounters, TimeUnit.MILLISECONDS.toNanos(300L))
80 : null;
81
82 private Map<ProcessorUtilityTickCountProperty, List<Long>> initialUtilityCounters = USE_CPU_UTILITY
83 ? processorUtilityCounters.get().getB()
84 : null;
85
86 private Long utilityBaseMultiplier = null;
87
88
89
90
91 @Override
92 protected ProcessorIdentifier queryProcessorId() {
93 String cpuVendor = "";
94 String cpuName = "";
95 String cpuIdentifier = "";
96 String cpuFamily = "";
97 String cpuModel = "";
98 String cpuStepping = "";
99 long cpuVendorFreq = 0L;
100 String processorID;
101 boolean cpu64bit = false;
102
103 final String cpuRegistryRoot = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\";
104 String[] processorIds = Advapi32Util.registryGetKeys(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryRoot);
105 if (processorIds.length > 0) {
106 String cpuRegistryPath = cpuRegistryRoot + processorIds[0];
107 cpuVendor = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryPath,
108 "VendorIdentifier");
109 cpuName = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryPath,
110 "ProcessorNameString");
111 cpuIdentifier = Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryPath,
112 "Identifier");
113 try {
114 cpuVendorFreq = Advapi32Util.registryGetIntValue(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryPath, "~MHz")
115 * 1_000_000L;
116 } catch (Win32Exception e) {
117
118 }
119 }
120 if (!cpuIdentifier.isEmpty()) {
121 cpuFamily = parseIdentifier(cpuIdentifier, "Family");
122 cpuModel = parseIdentifier(cpuIdentifier, "Model");
123 cpuStepping = parseIdentifier(cpuIdentifier, "Stepping");
124 }
125 try (CloseableSystemInfo sysinfo = new CloseableSystemInfo()) {
126 Kernel32.INSTANCE.GetNativeSystemInfo(sysinfo);
127 int processorArchitecture = sysinfo.processorArchitecture.pi.wProcessorArchitecture.intValue();
128 if (processorArchitecture == 9
129 || processorArchitecture == 12
130 || processorArchitecture == 6) {
131 cpu64bit = true;
132 }
133 }
134 WmiResult<ProcessorIdProperty> processorId = Win32Processor.queryProcessorId();
135 if (processorId.getResultCount() > 0) {
136 processorID = WmiUtil.getString(processorId, ProcessorIdProperty.PROCESSORID, 0);
137 } else {
138 processorID = createProcessorID(cpuStepping, cpuModel, cpuFamily,
139 cpu64bit ? new String[] { "ia64" } : new String[0]);
140 }
141 return new ProcessorIdentifier(cpuVendor, cpuName, cpuFamily, cpuModel, cpuStepping, processorID, cpu64bit,
142 cpuVendorFreq);
143 }
144
145
146
147
148
149
150
151
152 private static String parseIdentifier(String identifier, String key) {
153 String[] idSplit = ParseUtil.whitespaces.split(identifier);
154 boolean found = false;
155 for (String s : idSplit) {
156
157 if (found) {
158 return s;
159 }
160 found = s.equals(key);
161 }
162
163 return "";
164 }
165
166 @Override
167 protected Quartet<List<LogicalProcessor>, List<PhysicalProcessor>, List<ProcessorCache>, List<String>> initProcessorCounts() {
168 Triplet<List<LogicalProcessor>, List<PhysicalProcessor>, List<ProcessorCache>> lpi;
169 if (VersionHelpers.IsWindows7OrGreater()) {
170 lpi = LogicalProcessorInformation.getLogicalProcessorInformationEx();
171
172
173
174 int curNode = -1;
175 int procNum = 0;
176
177 int lp = 0;
178 this.numaNodeProcToLogicalProcMap = new HashMap<>();
179 for (LogicalProcessor logProc : lpi.getA()) {
180 int node = logProc.getNumaNode();
181
182 if (node != curNode) {
183 curNode = node;
184 procNum = 0;
185 }
186 numaNodeProcToLogicalProcMap.put(String.format(Locale.ROOT, "%d,%d", logProc.getNumaNode(), procNum++),
187 lp++);
188 }
189 } else {
190 lpi = LogicalProcessorInformation.getLogicalProcessorInformation();
191 }
192 List<String> featureFlags = Arrays.stream(ProcessorFeature.values())
193 .filter(f -> Kernel32.INSTANCE.IsProcessorFeaturePresent(f.value())).map(ProcessorFeature::name)
194 .collect(Collectors.toList());
195 return new Quartet<>(lpi.getA(), lpi.getB(), lpi.getC(), featureFlags);
196 }
197
198 @Override
199 public long[] querySystemCpuLoadTicks() {
200
201
202
203
204
205
206 long[] ticks = new long[TickType.values().length];
207
208 long[][] procTicks = getProcessorCpuLoadTicks();
209 for (int i = 0; i < ticks.length; i++) {
210 for (long[] procTick : procTicks) {
211 ticks[i] += procTick[i];
212 }
213 }
214 return ticks;
215 }
216
217 @Override
218 public long[] queryCurrentFreq() {
219 if (VersionHelpers.IsWindows7OrGreater()) {
220 Pair<List<String>, Map<ProcessorFrequencyProperty, List<Long>>> instanceValuePair = ProcessorInformation
221 .queryFrequencyCounters();
222 List<String> instances = instanceValuePair.getA();
223 Map<ProcessorFrequencyProperty, List<Long>> valueMap = instanceValuePair.getB();
224 List<Long> percentMaxList = valueMap.get(ProcessorFrequencyProperty.PERCENTOFMAXIMUMFREQUENCY);
225 if (!instances.isEmpty()) {
226 long maxFreq = this.getMaxFreq();
227 long[] freqs = new long[getLogicalProcessorCount()];
228 for (String instance : instances) {
229 int cpu = instance.contains(",") ? numaNodeProcToLogicalProcMap.getOrDefault(instance, 0)
230 : ParseUtil.parseIntOrDefault(instance, 0);
231 if (cpu >= getLogicalProcessorCount()) {
232 continue;
233 }
234 freqs[cpu] = percentMaxList.get(cpu) * maxFreq / 100L;
235 }
236 return freqs;
237 }
238 }
239
240 return queryNTPower(2);
241 }
242
243 @Override
244 public long queryMaxFreq() {
245 long[] freqs = queryNTPower(1);
246 return Arrays.stream(freqs).max().orElse(-1L);
247 }
248
249
250
251
252
253
254
255 private long[] queryNTPower(int fieldIndex) {
256 ProcessorPowerInformation ppi = new ProcessorPowerInformation();
257 ProcessorPowerInformation[] ppiArray = (ProcessorPowerInformation[]) ppi.toArray(getLogicalProcessorCount());
258 long[] freqs = new long[getLogicalProcessorCount()];
259 if (0 != PowrProf.INSTANCE.CallNtPowerInformation(POWER_INFORMATION_LEVEL.ProcessorInformation, null, 0,
260 ppiArray[0].getPointer(), ppi.size() * ppiArray.length)) {
261 LOG.error("Unable to get Processor Information");
262 Arrays.fill(freqs, -1L);
263 return freqs;
264 }
265 for (int i = 0; i < freqs.length; i++) {
266 if (fieldIndex == 1) {
267 freqs[i] = ppiArray[i].maxMhz * 1_000_000L;
268 } else if (fieldIndex == 2) {
269 freqs[i] = ppiArray[i].currentMhz * 1_000_000L;
270 } else {
271 freqs[i] = -1L;
272 }
273
274 if (freqs[i] == 0) {
275 freqs[i] = getProcessorIdentifier().getVendorFreq();
276 }
277 }
278 return freqs;
279 }
280
281 @Override
282 public double[] getSystemLoadAverage(int nelem) {
283 if (nelem < 1 || nelem > 3) {
284 throw new IllegalArgumentException("Must include from one to three elements.");
285 }
286 return LoadAverage.queryLoadAverage(nelem);
287 }
288
289 @Override
290 public long[][] queryProcessorCpuLoadTicks() {
291
292 List<String> instances;
293 List<Long> systemList;
294 List<Long> userList;
295 List<Long> irqList;
296 List<Long> softIrqList;
297 List<Long> idleList;
298
299 List<Long> baseList = null;
300 List<Long> systemUtility = null;
301 List<Long> processorUtility = null;
302 List<Long> processorUtilityBase = null;
303 List<Long> initSystemList = null;
304 List<Long> initUserList = null;
305 List<Long> initBase = null;
306 List<Long> initSystemUtility = null;
307 List<Long> initProcessorUtility = null;
308 List<Long> initProcessorUtilityBase = null;
309 if (USE_CPU_UTILITY) {
310 Pair<List<String>, Map<ProcessorUtilityTickCountProperty, List<Long>>> instanceValuePair = processorUtilityCounters
311 .get();
312 instances = instanceValuePair.getA();
313 Map<ProcessorUtilityTickCountProperty, List<Long>> valueMap = instanceValuePair.getB();
314 systemList = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTPRIVILEGEDTIME);
315 userList = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTUSERTIME);
316 irqList = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTINTERRUPTTIME);
317 softIrqList = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTDPCTIME);
318
319 idleList = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTPROCESSORTIME);
320 baseList = valueMap.get(ProcessorUtilityTickCountProperty.TIMESTAMP_SYS100NS);
321
322 systemUtility = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTPRIVILEGEDUTILITY);
323 processorUtility = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTPROCESSORUTILITY);
324 processorUtilityBase = valueMap.get(ProcessorUtilityTickCountProperty.PERCENTPROCESSORUTILITY_BASE);
325
326 initSystemList = initialUtilityCounters.get(ProcessorUtilityTickCountProperty.PERCENTPRIVILEGEDTIME);
327 initUserList = initialUtilityCounters.get(ProcessorUtilityTickCountProperty.PERCENTUSERTIME);
328 initBase = initialUtilityCounters.get(ProcessorUtilityTickCountProperty.TIMESTAMP_SYS100NS);
329
330 initSystemUtility = initialUtilityCounters.get(ProcessorUtilityTickCountProperty.PERCENTPRIVILEGEDUTILITY);
331 initProcessorUtility = initialUtilityCounters
332 .get(ProcessorUtilityTickCountProperty.PERCENTPROCESSORUTILITY);
333 initProcessorUtilityBase = initialUtilityCounters
334 .get(ProcessorUtilityTickCountProperty.PERCENTPROCESSORUTILITY_BASE);
335 } else {
336 Pair<List<String>, Map<ProcessorTickCountProperty, List<Long>>> instanceValuePair = ProcessorInformation
337 .queryProcessorCounters();
338 instances = instanceValuePair.getA();
339 Map<ProcessorTickCountProperty, List<Long>> valueMap = instanceValuePair.getB();
340 systemList = valueMap.get(ProcessorTickCountProperty.PERCENTPRIVILEGEDTIME);
341 userList = valueMap.get(ProcessorTickCountProperty.PERCENTUSERTIME);
342 irqList = valueMap.get(ProcessorTickCountProperty.PERCENTINTERRUPTTIME);
343 softIrqList = valueMap.get(ProcessorTickCountProperty.PERCENTDPCTIME);
344
345 idleList = valueMap.get(ProcessorTickCountProperty.PERCENTPROCESSORTIME);
346 }
347
348 int ncpu = getLogicalProcessorCount();
349 long[][] ticks = new long[ncpu][TickType.values().length];
350 if (instances.isEmpty() || systemList == null || userList == null || irqList == null || softIrqList == null
351 || idleList == null
352 || (USE_CPU_UTILITY && (baseList == null || systemUtility == null || processorUtility == null
353 || processorUtilityBase == null || initSystemList == null || initUserList == null
354 || initBase == null || initSystemUtility == null || initProcessorUtility == null
355 || initProcessorUtilityBase == null))) {
356 return ticks;
357 }
358 for (String instance : instances) {
359 int cpu = instance.contains(",") ? numaNodeProcToLogicalProcMap.getOrDefault(instance, 0)
360 : ParseUtil.parseIntOrDefault(instance, 0);
361 if (cpu >= ncpu) {
362 continue;
363 }
364 ticks[cpu][TickType.SYSTEM.getIndex()] = systemList.get(cpu);
365 ticks[cpu][TickType.USER.getIndex()] = userList.get(cpu);
366 ticks[cpu][TickType.IRQ.getIndex()] = irqList.get(cpu);
367 ticks[cpu][TickType.SOFTIRQ.getIndex()] = softIrqList.get(cpu);
368 ticks[cpu][TickType.IDLE.getIndex()] = idleList.get(cpu);
369
370
371 if (USE_CPU_UTILITY) {
372
373
374
375
376
377
378
379
380
381
382 long deltaT = baseList.get(cpu) - initBase.get(cpu);
383 if (deltaT > 0) {
384
385 long deltaBase = processorUtilityBase.get(cpu) - initProcessorUtilityBase.get(cpu);
386
387
388
389
390 long multiplier = lazilyCalculateMultiplier(deltaBase, deltaT);
391
392
393 if (multiplier > 0) {
394
395 long deltaProc = processorUtility.get(cpu) - initProcessorUtility.get(cpu);
396 long deltaSys = systemUtility.get(cpu) - initSystemUtility.get(cpu);
397
398
399
400 long newUser = initUserList.get(cpu) + multiplier * (deltaProc - deltaSys) / 100;
401 long newSystem = initSystemList.get(cpu) + multiplier * deltaSys / 100;
402
403
404 long delta = newUser - ticks[cpu][TickType.USER.getIndex()];
405 ticks[cpu][TickType.USER.getIndex()] = newUser;
406
407 delta += newSystem - ticks[cpu][TickType.SYSTEM.getIndex()];
408 ticks[cpu][TickType.SYSTEM.getIndex()] = newSystem;
409
410 ticks[cpu][TickType.IDLE.getIndex()] -= delta;
411 }
412 }
413 }
414
415
416 ticks[cpu][TickType.SYSTEM.getIndex()] -= ticks[cpu][TickType.IRQ.getIndex()]
417 + ticks[cpu][TickType.SOFTIRQ.getIndex()];
418
419
420
421 ticks[cpu][TickType.SYSTEM.getIndex()] /= 10_000L;
422 ticks[cpu][TickType.USER.getIndex()] /= 10_000L;
423 ticks[cpu][TickType.IRQ.getIndex()] /= 10_000L;
424 ticks[cpu][TickType.SOFTIRQ.getIndex()] /= 10_000L;
425 ticks[cpu][TickType.IDLE.getIndex()] /= 10_000L;
426 }
427
428 return ticks;
429 }
430
431
432
433
434
435
436
437
438 private synchronized long lazilyCalculateMultiplier(long deltaBase, long deltaT) {
439 if (utilityBaseMultiplier == null) {
440
441
442
443 if (deltaT >> 32 > 0) {
444 initialUtilityCounters = processorUtilityCounters.get().getB();
445 return 0L;
446 }
447
448
449 if (deltaBase <= 0) {
450 deltaBase += 1L << 32;
451 }
452 long multiplier = Math.round((double) deltaT / deltaBase);
453
454
455 if (deltaT < 50_000_000L) {
456 return multiplier;
457 }
458 utilityBaseMultiplier = multiplier;
459 }
460 return utilityBaseMultiplier;
461 }
462
463 private static Pair<List<String>, Map<ProcessorUtilityTickCountProperty, List<Long>>> queryProcessorUtilityCounters() {
464 return ProcessorInformation.queryProcessorCapacityCounters();
465 }
466
467 @Override
468 public long queryContextSwitches() {
469 return SystemInformation.queryContextSwitchCounters().getOrDefault(ContextSwitchProperty.CONTEXTSWITCHESPERSEC,
470 0L);
471 }
472
473 @Override
474 public long queryInterrupts() {
475 return ProcessorInformation.queryInterruptCounters().getOrDefault(InterruptsProperty.INTERRUPTSPERSEC, 0L);
476 }
477 }