1
2
3
4
5 package oshi.hardware.common;
6
7 import static oshi.util.Memoizer.defaultExpiration;
8 import static oshi.util.Memoizer.memoize;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.HashMap;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Locale;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.function.Supplier;
21 import java.util.stream.Collectors;
22
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import com.sun.jna.Platform;
27
28 import oshi.annotation.concurrent.ThreadSafe;
29 import oshi.driver.linux.proc.Auxv;
30 import oshi.hardware.CentralProcessor;
31 import oshi.util.ParseUtil;
32 import oshi.util.tuples.Quartet;
33
34
35
36
37 @ThreadSafe
38 public abstract class AbstractCentralProcessor implements CentralProcessor {
39
40 private static final Logger LOG = LoggerFactory.getLogger(AbstractCentralProcessor.class);
41
42 private final Supplier<ProcessorIdentifier> cpuid = memoize(this::queryProcessorId);
43 private final Supplier<Long> maxFreq = memoize(this::queryMaxFreq, defaultExpiration());
44
45 private final Supplier<long[]> currentFreq = memoize(this::queryCurrentFreq, defaultExpiration() / 2L);
46 private final Supplier<Long> contextSwitches = memoize(this::queryContextSwitches, defaultExpiration());
47 private final Supplier<Long> interrupts = memoize(this::queryInterrupts, defaultExpiration());
48
49 private final Supplier<long[]> systemCpuLoadTicks = memoize(this::querySystemCpuLoadTicks, defaultExpiration());
50 private final Supplier<long[][]> processorCpuLoadTicks = memoize(this::queryProcessorCpuLoadTicks,
51 defaultExpiration());
52
53
54 private final int physicalPackageCount;
55 private final int physicalProcessorCount;
56 private final int logicalProcessorCount;
57
58
59 private final List<LogicalProcessor> logicalProcessors;
60 private final List<PhysicalProcessor> physicalProcessors;
61 private final List<ProcessorCache> processorCaches;
62 private final List<String> featureFlags;
63
64
65
66
67 protected AbstractCentralProcessor() {
68 Quartet<List<LogicalProcessor>, List<PhysicalProcessor>, List<ProcessorCache>, List<String>> processorLists = initProcessorCounts();
69
70 this.logicalProcessors = Collections.unmodifiableList(processorLists.getA());
71 if (processorLists.getB() == null) {
72 Set<Integer> pkgCoreKeys = this.logicalProcessors.stream()
73 .map(p -> (p.getPhysicalPackageNumber() << 16) + p.getPhysicalProcessorNumber())
74 .collect(Collectors.toSet());
75 List<PhysicalProcessor> physProcs = pkgCoreKeys.stream().sorted()
76 .map(k -> new PhysicalProcessor(k >> 16, k & 0xffff)).collect(Collectors.toList());
77 this.physicalProcessors = Collections.unmodifiableList(physProcs);
78 } else {
79 this.physicalProcessors = Collections.unmodifiableList(processorLists.getB());
80 }
81 this.processorCaches = processorLists.getC() == null ? Collections.emptyList()
82 : Collections.unmodifiableList(processorLists.getC());
83
84 Set<Integer> physPkgs = new HashSet<>();
85 for (LogicalProcessor logProc : this.logicalProcessors) {
86 int pkg = logProc.getPhysicalPackageNumber();
87 physPkgs.add(pkg);
88 }
89 this.logicalProcessorCount = this.logicalProcessors.size();
90 this.physicalProcessorCount = this.physicalProcessors.size();
91 this.physicalPackageCount = physPkgs.size();
92 this.featureFlags = Collections.unmodifiableList(processorLists.getD());
93 }
94
95
96
97
98
99
100 protected abstract Quartet<List<LogicalProcessor>, List<PhysicalProcessor>, List<ProcessorCache>, List<String>> initProcessorCounts();
101
102
103
104
105
106
107 protected abstract ProcessorIdentifier queryProcessorId();
108
109 @Override
110 public ProcessorIdentifier getProcessorIdentifier() {
111 return cpuid.get();
112 }
113
114 @Override
115 public long getMaxFreq() {
116 return maxFreq.get();
117 }
118
119
120
121
122
123
124 protected long queryMaxFreq() {
125 return Arrays.stream(getCurrentFreq()).max().orElse(-1L);
126 }
127
128 @Override
129 public long[] getCurrentFreq() {
130 long[] freq = currentFreq.get();
131 if (freq.length == getLogicalProcessorCount()) {
132 return freq;
133 }
134 long[] freqs = new long[getLogicalProcessorCount()];
135 Arrays.fill(freqs, freq[0]);
136 return freqs;
137 }
138
139
140
141
142
143
144 protected abstract long[] queryCurrentFreq();
145
146 @Override
147 public long getContextSwitches() {
148 return contextSwitches.get();
149 }
150
151
152
153
154
155
156 protected abstract long queryContextSwitches();
157
158 @Override
159 public long getInterrupts() {
160 return interrupts.get();
161 }
162
163
164
165
166
167
168 protected abstract long queryInterrupts();
169
170 @Override
171 public List<LogicalProcessor> getLogicalProcessors() {
172 return this.logicalProcessors;
173 }
174
175 @Override
176 public List<PhysicalProcessor> getPhysicalProcessors() {
177 return this.physicalProcessors;
178 }
179
180 @Override
181 public List<ProcessorCache> getProcessorCaches() {
182 return this.processorCaches;
183 }
184
185 @Override
186 public List<String> getFeatureFlags() {
187 return this.featureFlags;
188 }
189
190 @Override
191 public long[] getSystemCpuLoadTicks() {
192 return systemCpuLoadTicks.get();
193 }
194
195
196
197
198
199
200 protected abstract long[] querySystemCpuLoadTicks();
201
202 @Override
203 public long[][] getProcessorCpuLoadTicks() {
204 return processorCpuLoadTicks.get();
205 }
206
207
208
209
210
211
212 protected abstract long[][] queryProcessorCpuLoadTicks();
213
214 @Override
215 public double getSystemCpuLoadBetweenTicks(long[] oldTicks) {
216 if (oldTicks.length != TickType.values().length) {
217 throw new IllegalArgumentException("Provited tick array length " + oldTicks.length + " should have "
218 + TickType.values().length + " elements");
219 }
220 long[] ticks = getSystemCpuLoadTicks();
221
222 long total = 0;
223 for (int i = 0; i < ticks.length; i++) {
224 total += ticks[i] - oldTicks[i];
225 }
226
227 long idle = ticks[TickType.IDLE.getIndex()] + ticks[TickType.IOWAIT.getIndex()]
228 - oldTicks[TickType.IDLE.getIndex()] - oldTicks[TickType.IOWAIT.getIndex()];
229 LOG.trace("Total ticks: {} Idle ticks: {}", total, idle);
230
231 return total > 0 ? (double) (total - idle) / total : 0d;
232 }
233
234 @Override
235 public double[] getProcessorCpuLoadBetweenTicks(long[][] oldTicks) {
236 long[][] ticks = getProcessorCpuLoadTicks();
237 if (oldTicks.length != ticks.length || oldTicks[0].length != TickType.values().length) {
238 throw new IllegalArgumentException("Provided tick array length " + oldTicks.length + " should be "
239 + ticks.length + ", each subarray having " + TickType.values().length + " elements");
240 }
241 double[] load = new double[ticks.length];
242 for (int cpu = 0; cpu < ticks.length; cpu++) {
243 long total = 0;
244 for (int i = 0; i < ticks[cpu].length; i++) {
245 total += ticks[cpu][i] - oldTicks[cpu][i];
246 }
247
248 long idle = ticks[cpu][TickType.IDLE.getIndex()] + ticks[cpu][TickType.IOWAIT.getIndex()]
249 - oldTicks[cpu][TickType.IDLE.getIndex()] - oldTicks[cpu][TickType.IOWAIT.getIndex()];
250 LOG.trace("CPU: {} Total ticks: {} Idle ticks: {}", cpu, total, idle);
251
252 load[cpu] = total > 0 && idle >= 0 ? (double) (total - idle) / total : 0d;
253 }
254 return load;
255 }
256
257 @Override
258 public int getLogicalProcessorCount() {
259 return this.logicalProcessorCount;
260 }
261
262 @Override
263 public int getPhysicalProcessorCount() {
264 return this.physicalProcessorCount;
265 }
266
267 @Override
268 public int getPhysicalPackageCount() {
269 return this.physicalPackageCount;
270 }
271
272
273
274
275
276
277
278
279
280
281 protected static String createProcessorID(String stepping, String model, String family, String[] flags) {
282 long processorIdBytes = 0L;
283 long steppingL = ParseUtil.parseLongOrDefault(stepping, 0L);
284 long modelL = ParseUtil.parseLongOrDefault(model, 0L);
285 long familyL = ParseUtil.parseLongOrDefault(family, 0L);
286
287 processorIdBytes |= steppingL & 0xf;
288
289 processorIdBytes |= (modelL & 0xf) << 4;
290 processorIdBytes |= (modelL & 0xf0) << 12;
291
292 processorIdBytes |= (familyL & 0xf) << 8;
293 processorIdBytes |= (familyL & 0xff0) << 16;
294
295 long hwcap = 0L;
296 if (Platform.isLinux()) {
297 hwcap = Auxv.queryAuxv().getOrDefault(Auxv.AT_HWCAP, 0L);
298 }
299 if (hwcap > 0) {
300 processorIdBytes |= hwcap << 32;
301 } else {
302 for (String flag : flags) {
303 switch (flag) {
304 case "fpu":
305 processorIdBytes |= 1L << 32;
306 break;
307 case "vme":
308 processorIdBytes |= 1L << 33;
309 break;
310 case "de":
311 processorIdBytes |= 1L << 34;
312 break;
313 case "pse":
314 processorIdBytes |= 1L << 35;
315 break;
316 case "tsc":
317 processorIdBytes |= 1L << 36;
318 break;
319 case "msr":
320 processorIdBytes |= 1L << 37;
321 break;
322 case "pae":
323 processorIdBytes |= 1L << 38;
324 break;
325 case "mce":
326 processorIdBytes |= 1L << 39;
327 break;
328 case "cx8":
329 processorIdBytes |= 1L << 40;
330 break;
331 case "apic":
332 processorIdBytes |= 1L << 41;
333 break;
334 case "sep":
335 processorIdBytes |= 1L << 43;
336 break;
337 case "mtrr":
338 processorIdBytes |= 1L << 44;
339 break;
340 case "pge":
341 processorIdBytes |= 1L << 45;
342 break;
343 case "mca":
344 processorIdBytes |= 1L << 46;
345 break;
346 case "cmov":
347 processorIdBytes |= 1L << 47;
348 break;
349 case "pat":
350 processorIdBytes |= 1L << 48;
351 break;
352 case "pse-36":
353 processorIdBytes |= 1L << 49;
354 break;
355 case "psn":
356 processorIdBytes |= 1L << 50;
357 break;
358 case "clfsh":
359 processorIdBytes |= 1L << 51;
360 break;
361 case "ds":
362 processorIdBytes |= 1L << 53;
363 break;
364 case "acpi":
365 processorIdBytes |= 1L << 54;
366 break;
367 case "mmx":
368 processorIdBytes |= 1L << 55;
369 break;
370 case "fxsr":
371 processorIdBytes |= 1L << 56;
372 break;
373 case "sse":
374 processorIdBytes |= 1L << 57;
375 break;
376 case "sse2":
377 processorIdBytes |= 1L << 58;
378 break;
379 case "ss":
380 processorIdBytes |= 1L << 59;
381 break;
382 case "htt":
383 processorIdBytes |= 1L << 60;
384 break;
385 case "tm":
386 processorIdBytes |= 1L << 61;
387 break;
388 case "ia64":
389 processorIdBytes |= 1L << 62;
390 break;
391 case "pbe":
392 processorIdBytes |= 1L << 63;
393 break;
394 default:
395 break;
396 }
397 }
398 }
399 return String.format(Locale.ROOT, "%016X", processorIdBytes);
400 }
401
402 protected List<PhysicalProcessor> createProcListFromDmesg(List<LogicalProcessor> logProcs,
403 Map<Integer, String> dmesg) {
404
405 boolean isHybrid = dmesg.values().stream().distinct().count() > 1;
406 List<PhysicalProcessor> physProcs = new ArrayList<>();
407 Set<Integer> pkgCoreKeys = new HashSet<>();
408 for (LogicalProcessor logProc : logProcs) {
409 int pkgId = logProc.getPhysicalPackageNumber();
410 int coreId = logProc.getPhysicalProcessorNumber();
411 int pkgCoreKey = (pkgId << 16) + coreId;
412 if (!pkgCoreKeys.contains(pkgCoreKey)) {
413 pkgCoreKeys.add(pkgCoreKey);
414 String idStr = dmesg.getOrDefault(logProc.getProcessorNumber(), "");
415 int efficiency = 0;
416
417
418
419 if (isHybrid && ((idStr.startsWith("ARM Cortex") && ParseUtil.getFirstIntValue(idStr) >= 70)
420 || (idStr.startsWith("Apple")
421 && (idStr.contains("Firestorm") || (idStr.contains("Avalanche")))))) {
422 efficiency = 1;
423 }
424 physProcs.add(new PhysicalProcessor(pkgId, coreId, efficiency, idStr));
425 }
426 }
427 physProcs.sort(Comparator.comparingInt(PhysicalProcessor::getPhysicalPackageNumber)
428 .thenComparingInt(PhysicalProcessor::getPhysicalProcessorNumber));
429 return physProcs;
430 }
431
432
433
434
435
436
437
438 public static List<ProcessorCache> orderedProcCaches(Set<ProcessorCache> caches) {
439 return caches.stream().sorted(Comparator.comparing(
440 c -> -1000 * c.getLevel() + 100 * c.getType().ordinal() - Integer.highestOneBit(c.getCacheSize())))
441 .collect(Collectors.toList());
442 }
443
444 @Override
445 public String toString() {
446 StringBuilder sb = new StringBuilder(getProcessorIdentifier().getName());
447 sb.append("\n ").append(getPhysicalPackageCount()).append(" physical CPU package(s)");
448 sb.append("\n ").append(getPhysicalProcessorCount()).append(" physical CPU core(s)");
449 Map<Integer, Integer> efficiencyCount = new HashMap<>();
450 int maxEfficiency = 0;
451 for (PhysicalProcessor cpu : getPhysicalProcessors()) {
452 int eff = cpu.getEfficiency();
453 efficiencyCount.merge(eff, 1, Integer::sum);
454 if (eff > maxEfficiency) {
455 maxEfficiency = eff;
456 }
457 }
458 int pCores = efficiencyCount.getOrDefault(maxEfficiency, 0);
459 int eCores = getPhysicalProcessorCount() - pCores;
460 if (eCores > 0) {
461 sb.append(" (").append(pCores).append(" performance + ").append(eCores).append(" efficiency)");
462 }
463 sb.append("\n ").append(getLogicalProcessorCount()).append(" logical CPU(s)");
464 sb.append('\n').append("Identifier: ").append(getProcessorIdentifier().getIdentifier());
465 sb.append('\n').append("ProcessorID: ").append(getProcessorIdentifier().getProcessorID());
466 sb.append('\n').append("Microarchitecture: ").append(getProcessorIdentifier().getMicroarchitecture());
467 return sb.toString();
468 }
469 }