1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package oshi.software.os.windows.nt;
18
19 import java.lang.management.ManagementFactory;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23 import oshi.hardware.Processor;
24 import oshi.software.os.windows.nt.Pdh.PdhFmtCounterValue;
25 import oshi.util.ParseUtil;
26
27 import com.sun.jna.LastErrorException;
28 import com.sun.jna.Native;
29 import com.sun.jna.platform.win32.WinBase;
30 import com.sun.jna.platform.win32.WinBase.SYSTEM_INFO;
31 import com.sun.jna.ptr.IntByReference;
32 import com.sun.jna.ptr.PointerByReference;
33
34
35
36
37
38
39
40
41 @SuppressWarnings("restriction")
42 public class CentralProcessor implements Processor {
43 private static final java.lang.management.OperatingSystemMXBean OS_MXBEAN = ManagementFactory
44 .getOperatingSystemMXBean();
45 private static boolean sunMXBean;
46 static {
47 try {
48 Class.forName("com.sun.management.OperatingSystemMXBean");
49
50 ((com.sun.management.OperatingSystemMXBean) OS_MXBEAN)
51 .getSystemCpuLoad();
52 sunMXBean = true;
53 } catch (ClassNotFoundException e) {
54 sunMXBean = false;
55 }
56 }
57
58
59
60 private static long tickTime = System.currentTimeMillis();
61 private static long[] prevTicks = new long[4];
62 private static long[] curTicks = new long[4];
63 static {
64 updateSystemTicks();
65 System.arraycopy(curTicks, 0, prevTicks, 0, curTicks.length);
66 }
67
68
69 private long procTickTime = System.currentTimeMillis();
70 private long[] prevProcTicks = new long[4];
71 private long[] curProcTicks = new long[4];
72
73
74
75 private static PointerByReference phQuery = new PointerByReference();
76 private static final IntByReference zero = new IntByReference(0);
77 private static final int numCPU;
78 static {
79
80 SYSTEM_INFO sysinfo = new SYSTEM_INFO();
81 Kernel32.INSTANCE.GetSystemInfo(sysinfo);
82 numCPU = sysinfo.dwNumberOfProcessors.intValue();
83
84
85 int ret = Pdh.INSTANCE.PdhOpenQuery(null, zero, phQuery);
86 if (ret != 0)
87 throw new LastErrorException("Cannot open PDH query. Error code: "
88 + String.format("0x%08X", ret));
89
90
91 Runtime.getRuntime().addShutdownHook(new Thread() {
92 @Override
93 public void run() {
94 Pdh.INSTANCE.PdhCloseQuery(phQuery.getValue());
95 }
96 });
97 }
98
99 private static PointerByReference[] phUserCounters = new PointerByReference[numCPU];
100 private static PointerByReference[] phIdleCounters = new PointerByReference[numCPU];
101 static {
102 for (int p = 0; p < numCPU; p++) {
103
104
105
106
107
108
109 String counterPath = String.format("\\Processor(%d)\\%% user time",
110 p);
111 phUserCounters[p] = new PointerByReference();
112 int ret = Pdh.INSTANCE.PdhAddEnglishCounterA(phQuery.getValue(),
113 counterPath, zero, phUserCounters[p]);
114 if (ret != 0)
115 throw new LastErrorException(
116 "Cannot add PDH Counter for % user time for processor "
117 + p + ". Error code: "
118 + String.format("0x%08X", ret));
119 counterPath = String.format("\\Processor(%d)\\%% idle time", p);
120 phIdleCounters[p] = new PointerByReference();
121 ret = Pdh.INSTANCE.PdhAddEnglishCounterA(phQuery.getValue(),
122 counterPath, zero, phIdleCounters[p]);
123 if (ret != 0)
124 throw new LastErrorException(
125 "Cannot add PDH Counter for % idle time for processor "
126 + p + ". Error code: "
127 + String.format("0x%08X", ret));
128 }
129
130 int ret = Pdh.INSTANCE.PdhCollectQueryData(phQuery.getValue());
131 if (ret != 0)
132 throw new LastErrorException(
133 "Cannot collect PDH query data. Error code: "
134 + String.format("0x%08X", ret));
135 }
136
137
138
139 private static long[][] allProcessorTicks = new long[numCPU][4];
140 private static long allProcTickTime = System.currentTimeMillis() - 100;
141
142 private int processorNumber;
143 private String cpuVendor;
144 private String cpuName;
145 private String cpuIdentifier;
146 private Long cpuVendorFreq;
147
148
149
150
151
152
153 public CentralProcessor(int procNo) {
154 if (procNo >= numCPU)
155 throw new IllegalArgumentException("Processor number (" + procNo
156 + ") must be less than the number of CPUs: " + numCPU);
157 this.processorNumber = procNo;
158 updateProcessorTicks();
159 System.arraycopy(allProcessorTicks[processorNumber], 0, curProcTicks,
160 0, curProcTicks.length);
161 }
162
163
164
165
166 @Override
167 public int getProcessorNumber() {
168 return processorNumber;
169 }
170
171
172
173
174
175
176 @Override
177 public String getVendor() {
178 return this.cpuVendor;
179 }
180
181
182
183
184
185
186
187 @Override
188 public void setVendor(String vendor) {
189 this.cpuVendor = vendor;
190 }
191
192
193
194
195
196
197 @Override
198 public String getName() {
199 return this.cpuName;
200 }
201
202
203
204
205
206
207
208 @Override
209 public void setName(String name) {
210 this.cpuName = name;
211 }
212
213
214
215
216
217
218
219 @Override
220 public long getVendorFreq() {
221 if (this.cpuVendorFreq == null) {
222 Pattern pattern = Pattern.compile("@ (.*)$");
223 Matcher matcher = pattern.matcher(getName());
224
225 if (matcher.find()) {
226 String unit = matcher.group(1);
227 this.cpuVendorFreq = Long.valueOf(ParseUtil.parseHertz(unit));
228 } else {
229 this.cpuVendorFreq = Long.valueOf(-1L);
230 }
231 }
232
233 return this.cpuVendorFreq.longValue();
234 }
235
236
237
238
239
240
241
242 @Override
243 public void setVendorFreq(long freq) {
244 this.cpuVendorFreq = Long.valueOf(freq);
245 }
246
247
248
249
250
251
252 @Override
253 public String getIdentifier() {
254 return this.cpuIdentifier;
255 }
256
257
258
259
260
261
262
263 @Override
264 public void setIdentifier(String identifier) {
265 this.cpuIdentifier = identifier;
266 }
267
268
269
270
271 @Override
272 public boolean isCpu64bit() {
273 throw new UnsupportedOperationException();
274 }
275
276
277
278
279 @Override
280 public void setCpu64(boolean cpu64) {
281 throw new UnsupportedOperationException();
282 }
283
284
285
286
287 @Override
288 public String getStepping() {
289 throw new UnsupportedOperationException();
290 }
291
292
293
294
295 @Override
296 public void setStepping(String stepping) {
297 throw new UnsupportedOperationException();
298 }
299
300
301
302
303 @Override
304 public String getModel() {
305 throw new UnsupportedOperationException();
306 }
307
308
309
310
311 @Override
312 public void setModel(String model) {
313 throw new UnsupportedOperationException();
314 }
315
316
317
318
319 @Override
320 public String getFamily() {
321 throw new UnsupportedOperationException();
322 }
323
324
325
326
327 @Override
328 public void setFamily(String family) {
329 throw new UnsupportedOperationException();
330 }
331
332
333
334
335 @Override
336 @Deprecated
337 public float getLoad() {
338
339 return (float) getSystemCpuLoadBetweenTicks() * 100;
340 }
341
342
343
344
345 @Override
346 public double getSystemCpuLoadBetweenTicks() {
347
348 long now = System.currentTimeMillis();
349 boolean update = (now - tickTime > 950);
350 if (update) {
351
352
353 updateSystemTicks();
354 tickTime = now;
355 }
356
357 long total = 0;
358 for (int i = 0; i < curTicks.length; i++) {
359 total += (curTicks[i] - prevTicks[i]);
360 }
361
362 long idle = curTicks[3] - prevTicks[3];
363
364
365 if (update) {
366 System.arraycopy(curTicks, 0, prevTicks, 0, curTicks.length);
367 }
368
369
370 if (total > 0 && idle >= 0) {
371 return (double) (total - idle) / total;
372 }
373 return 0d;
374 }
375
376
377
378
379 @Override
380 public long[] getSystemCpuLoadTicks() {
381 updateSystemTicks();
382
383 long[] ticks = new long[curTicks.length];
384 System.arraycopy(curTicks, 0, ticks, 0, curTicks.length);
385 return ticks;
386 }
387
388
389
390
391
392
393
394
395 private static void updateSystemTicks() {
396 WinBase.FILETIME lpIdleTime = new WinBase.FILETIME();
397 WinBase.FILETIME lpKernelTime = new WinBase.FILETIME();
398 WinBase.FILETIME lpUserTime = new WinBase.FILETIME();
399 if (0 == Kernel32.INSTANCE.GetSystemTimes(lpIdleTime, lpKernelTime,
400 lpUserTime))
401 throw new LastErrorException("Error code: " + Native.getLastError());
402
403 curTicks[0] = lpUserTime.toLong() + Kernel32.WIN32_TIME_OFFSET;
404 curTicks[1] = 0L;
405 curTicks[2] = lpKernelTime.toLong() - lpIdleTime.toLong();
406 curTicks[3] = lpIdleTime.toLong() + Kernel32.WIN32_TIME_OFFSET;
407 }
408
409
410
411
412 @Override
413 public double getSystemCpuLoad() {
414 if (sunMXBean) {
415 return ((com.sun.management.OperatingSystemMXBean) OS_MXBEAN)
416 .getSystemCpuLoad();
417 }
418 return getSystemCpuLoadBetweenTicks();
419 }
420
421
422
423
424 @Override
425 public double getSystemLoadAverage() {
426
427 return OS_MXBEAN.getSystemLoadAverage();
428 }
429
430
431
432
433 @Override
434 public double getProcessorCpuLoadBetweenTicks() {
435
436 long now = System.currentTimeMillis();
437 if (now - procTickTime > 950) {
438
439 updateProcessorTicks();
440
441 System.arraycopy(curProcTicks, 0, prevProcTicks, 0,
442 curProcTicks.length);
443 System.arraycopy(allProcessorTicks[processorNumber], 0,
444 curProcTicks, 0, curProcTicks.length);
445 procTickTime = now;
446 }
447 long total = 0;
448 for (int i = 0; i < curProcTicks.length; i++) {
449 total += (curProcTicks[i] - prevProcTicks[i]);
450 }
451
452 long idle = curProcTicks[3] - prevProcTicks[3];
453
454 return (total > 0 && idle >= 0) ? (double) (total - idle) / total : 0d;
455 }
456
457
458
459
460 public long[] getProcessorCpuLoadTicks() {
461 updateProcessorTicks();
462 return allProcessorTicks[processorNumber];
463 }
464
465
466
467
468
469
470
471 private void updateProcessorTicks() {
472
473
474 long now = System.currentTimeMillis();
475 if (now - allProcTickTime < 100)
476 return;
477
478
479 int ret = Pdh.INSTANCE.PdhCollectQueryData(phQuery.getValue());
480 if (ret != 0)
481 throw new LastErrorException(
482 "Cannot collect PDH query data. Error code: "
483 + String.format("0x%08X", ret));
484
485 long elapsed = now - allProcTickTime;
486 for (int cpu = 0; cpu < numCPU; cpu++) {
487 PdhFmtCounterValue phUserCounterValue = new PdhFmtCounterValue();
488 ret = Pdh.INSTANCE.PdhGetFormattedCounterValue(
489 phUserCounters[cpu].getValue(), Pdh.PDH_FMT_LARGE
490 | Pdh.PDH_FMT_1000, null, phUserCounterValue);
491 if (ret != 0)
492 throw new LastErrorException(
493 "Cannot get PDH User % counter value. Error code: "
494 + String.format("0x%08X", ret));
495
496 PdhFmtCounterValue phIdleCounterValue = new PdhFmtCounterValue();
497 ret = Pdh.INSTANCE.PdhGetFormattedCounterValue(
498 phIdleCounters[cpu].getValue(), Pdh.PDH_FMT_LARGE
499 | Pdh.PDH_FMT_1000, null, phIdleCounterValue);
500 if (ret != 0)
501 throw new LastErrorException(
502 "Cannot get PDH Idle % counter value. Error code: "
503 + String.format("0x%08X", ret));
504
505
506
507
508 long user = elapsed * phUserCounterValue.value.largeValue / 100000;
509 long idle = elapsed * phIdleCounterValue.value.largeValue / 100000;
510
511 allProcessorTicks[cpu][0] += user;
512
513 allProcessorTicks[cpu][2] += (elapsed - user - idle);
514 allProcessorTicks[cpu][3] += idle;
515 }
516 allProcTickTime = now;
517 }
518
519 @Override
520 public String toString() {
521 return getName();
522 }
523 }