1 /*
2 * Copyright 2016-2024 The OSHI Project Contributors
3 * SPDX-License-Identifier: MIT
4 */
5 package oshi.hardware;
6
7 import static oshi.util.Memoizer.memoize;
8
9 import java.util.List;
10 import java.util.Locale;
11 import java.util.Objects;
12 import java.util.Properties;
13 import java.util.function.Supplier;
14 import java.util.regex.Matcher;
15 import java.util.regex.Pattern;
16
17 import oshi.annotation.concurrent.Immutable;
18 import oshi.annotation.concurrent.ThreadSafe;
19 import oshi.software.os.OSProcess;
20 import oshi.software.os.OSThread;
21 import oshi.util.Constants;
22 import oshi.util.FileUtil;
23 import oshi.util.ParseUtil;
24 import oshi.util.Util;
25
26 /**
27 * This class represents the entire Central Processing Unit (CPU) of a computer system, which may contain one or more
28 * physical packages (sockets), one or more physical processors (cores), and one or more logical processors (what the
29 * Operating System sees, which may include hyperthreaded cores.)
30 */
31 @ThreadSafe
32 public interface CentralProcessor {
33
34 /**
35 * The CPU's identifier strings ,including name, vendor, stepping, model, and family information (also called the
36 * signature of a CPU).
37 * <p>
38 * The Processor Identifier is primarily associated with Intel-based chips. Attempts are made to provide comparable
39 * values for other chip manufacturers.
40 *
41 * @return a {@link ProcessorIdentifier} object encapsulating CPU identifier information.
42 */
43 ProcessorIdentifier getProcessorIdentifier();
44
45 /**
46 * Maximum frequeny (in Hz), of the logical processors on this CPU.
47 *
48 * @return The max frequency or -1 if unknown.
49 */
50 long getMaxFreq();
51
52 /**
53 * Attempts to return the current frequency (in Hz), of the logical processors on this CPU.
54 * <p>
55 * May not be implemented on all Operating Systems.
56 * <p>
57 * On Windows, returns an estimate based on the percent of maximum frequency. On Windows systems with more than 64
58 * logical processors, may only return frequencies for the current processor group in the first portion of the
59 * array.
60 *
61 * @return An array of processor frequencies for each logical processor on the system. Use the
62 * {@link #getLogicalProcessors()} to correlate these frequencies with physical packages and processors.
63 */
64 long[] getCurrentFreq();
65
66 /**
67 * Returns an {@code UnmodifiableList} of the CPU's logical processors. The list will be sorted in order of
68 * increasing NUMA node number, and then processor number. This order is (usually) consistent with other methods
69 * providing per-processor results.
70 * <p>
71 * On some operating systems with variable numbers of logical processors, the size of this array could change and
72 * may not align with other per-processor methods.
73 *
74 * @return An {@code UnmodifiabeList} of logical processors.
75 */
76 List<LogicalProcessor> getLogicalProcessors();
77
78 /**
79 * Returns an {@code UnmodifiableList} of the CPU's physical processors. The list will be sorted in order of
80 * increasing core ID.
81 *
82 * @return An {@code UnmodifiabeList} of physical processors.
83 */
84 List<PhysicalProcessor> getPhysicalProcessors();
85
86 /**
87 * Makes a best-effort attempt to identify the CPU's processor caches. For hybrid processors, both performance and
88 * efficiency core caches are shown. Only one instance of per-core caches is shown.
89 * <p>
90 * Values are unreliable in virtual machines and rely in information made available by the VM or hypervisor. Callers
91 * should conduct sanity checking of the returned objects. Not all values are available on all operating systems or
92 * architectures.
93 * <p>
94 * Not available on Solaris.
95 *
96 * @return An {@code UnmodifiabeList} of processor caches.
97 */
98 List<ProcessorCache> getProcessorCaches();
99
100 /**
101 * Returns a list of platform-specific strings which identify CPU Feature Flags. This string requires user parsing
102 * to obtain meaningful information.
103 *
104 * @return On Windows, returns a list of values for which the {@code IsProcessorFeaturePresent()} function evaluates
105 * to true.
106 * <p>
107 * On macOS x86, returns relevant {@code sysctl.machdep.feature} values. On Apple Silicon, returns relevant
108 * {@code sysctl hw.optional.arm.FEAT} values.
109 * <p>
110 * On Linux, returns the {@code flags} and/or {@code features} fields from {@code /proc/cpuinfo}.
111 * <p>
112 * On OpenBSD, FreeBSD, and Solaris, returns {@code dmesg} output containing the word {@code Feature}.
113 * <p>
114 * For unimplemented operating systems, returns an empty list.
115 */
116 List<String> getFeatureFlags();
117
118 /**
119 * Returns the "recent cpu usage" for the whole system by counting ticks from {@link #getSystemCpuLoadTicks()}
120 * between the user-provided value from a previous call.
121 * <p>
122 * On some operating systems with variable numbers of logical processors, the size of the array returned from a
123 * previous call to {@link #getSystemCpuLoadTicks()} could change and will throw an
124 * {@link IllegalArgumentException}. Calling code on these operating systems should handle this exception.
125 *
126 * @param oldTicks A tick array from a previous call to {@link #getSystemCpuLoadTicks()}
127 * @return CPU load between 0 and 1 (100%)
128 * @throws IllegalArgumentException if the array sizes differ.
129 */
130 double getSystemCpuLoadBetweenTicks(long[] oldTicks);
131
132 /**
133 * Get System-wide CPU Load tick counters. Returns an array with eight elements representing milliseconds spent in
134 * User (0), Nice (1), System (2), Idle (3), IOwait (4), Hardware interrupts (IRQ) (5), Software interrupts/DPC
135 * (SoftIRQ) (6), or Steal (7) states. Use {@link oshi.hardware.CentralProcessor.TickType#getIndex()} to retrieve
136 * the appropriate index. By measuring the difference between ticks across a time interval, CPU load over that
137 * interval may be calculated.
138 * <p>
139 * On some operating systems with variable numbers of logical processors, the size of this array could change and
140 * may not align with other per-processor methods.
141 * <p>
142 * Note that while tick counters are in units of milliseconds, they may advance in larger increments along with
143 * (platform dependent) clock ticks. For example, by default Windows clock ticks are 1/64 of a second (about 15 or
144 * 16 milliseconds) and Linux ticks are distribution and configuration dependent but usually 1/100 of a second (10
145 * milliseconds).
146 * <p>
147 * Nice and IOWait information is not available on Windows, and IOwait and IRQ information is not available on
148 * macOS, so these ticks will always be zero.
149 * <p>
150 * To calculate overall Idle time using this method, include both Idle and IOWait ticks. Similarly, IRQ, SoftIRQ,
151 * and Steal ticks should be added to the System value to get the total. System ticks also include time executing
152 * other virtual hosts (steal).
153 *
154 * @return An array of 8 long values representing time spent in User, Nice, System, Idle, IOwait, IRQ, SoftIRQ, and
155 * Steal states.
156 */
157 long[] getSystemCpuLoadTicks();
158
159 /**
160 * Returns the system load average for the number of elements specified, up to 3, representing 1, 5, and 15 minutes.
161 * The system load average is the sum of the number of runnable entities queued to the available processors and the
162 * number of runnable entities running on the available processors averaged over a period of time.
163 * <p>
164 * This method is designed to provide a hint about the system load and may be queried frequently.
165 * <p>
166 * The way in which the load average is calculated is operating system specific but is typically a damped
167 * time-dependent average. Linux includes processes waiting for system resources such as disks, while macOS and Unix
168 * consider only processes waiting for CPU.
169 * <p>
170 * Windows does not provide a load average. Users may set the configuration property
171 * {@code oshi.os.windows.loadaverage} to {@code true} to start a daemon thread which will provide a similar metric.
172 * <p>
173 * The load average may be unavailable on some platforms (e.g., Windows without the above configuration). If the
174 * load average is not available, a negative value is returned.
175 *
176 * @param nelem Number of elements to return.
177 * @return an array of the system load averages for 1, 5, and 15 minutes with the size of the array specified by
178 * nelem; or negative values if not available.
179 */
180 double[] getSystemLoadAverage(int nelem);
181
182 /**
183 * This is a convenience method which collects an initial set of ticks using {@link #getSystemCpuLoadTicks()} and
184 * passes that result to {@link #getSystemCpuLoadBetweenTicks(long[])} after the specified delay.
185 *
186 *
187 * @param delay Milliseconds to wait.
188 * @return value between 0 and 1 (100%) that represents the cpu usage in the provided time period.
189 */
190 default double getSystemCpuLoad(long delay) {
191 long start = System.nanoTime();
192 long[] oldTicks = getSystemCpuLoadTicks();
193 long toWait = delay - (System.nanoTime() - start) / 1_000_000;
194 // protect against IllegalArgumentException
195 if (toWait > 0L) {
196 Util.sleep(delay);
197 }
198 return getSystemCpuLoadBetweenTicks(oldTicks);
199 }
200
201 /**
202 * This is a convenience method which collects an initial set of ticks using {@link #getProcessorCpuLoadTicks()} and
203 * passes that result to {@link #getProcessorCpuLoadBetweenTicks(long[][])} after the specified delay.
204 * <p>
205 * On some operating systems with variable numbers of logical processors, the size of the array returned from the
206 * two calls could change and will throw an {@link IllegalArgumentException}. Calling code on these operating
207 * systems should handle this exception.
208 *
209 * @param delay Milliseconds to wait.
210 * @return array of CPU load between 0 and 1 (100%) for each logical processor, for the provided time period.
211 * @throws IllegalArgumentException if the array sizes differ between calls.
212 */
213 default double[] getProcessorCpuLoad(long delay) {
214 long start = System.nanoTime();
215 long[][] oldTicks = getProcessorCpuLoadTicks();
216 long toWait = delay - (System.nanoTime() - start) / 1_000_000;
217 // protect against IllegalArgumentException
218 if (toWait > 0L) {
219 Util.sleep(delay);
220 }
221 return getProcessorCpuLoadBetweenTicks(oldTicks);
222 }
223
224 /**
225 * Returns the "recent cpu usage" for all logical processors by counting ticks from
226 * {@link #getProcessorCpuLoadTicks()} between the user-provided value from a previous call.
227 * <p>
228 * On some operating systems with variable numbers of logical processors, the size of the array returned from the
229 * two calls could change and will throw an {@link IllegalArgumentException}. Calling code on these operating
230 * systems should handle this exception.
231 *
232 * @param oldTicks A tick array from a previous call to {@link #getProcessorCpuLoadTicks()}
233 * @return array of CPU load between 0 and 1 (100%) for each logical processor
234 * @throws IllegalArgumentException if the array sizes differ between calls.
235 */
236 double[] getProcessorCpuLoadBetweenTicks(long[][] oldTicks);
237
238 /**
239 * Get Processor CPU Load tick counters. Returns a two dimensional array, with {@link #getLogicalProcessorCount()}
240 * arrays, each containing seven elements representing milliseconds spent in User (0), Nice (1), System (2), Idle
241 * (3), IOwait (4), Hardware interrupts (IRQ) (5), Software interrupts/DPC (SoftIRQ) (6), or Steal (7) states. Use
242 * {@link oshi.hardware.CentralProcessor.TickType#getIndex()} to retrieve the appropriate index. By measuring the
243 * difference between ticks across a time interval, CPU load over that interval may be calculated.
244 * <p>
245 * Note that while tick counters are in units of milliseconds, they may advance in larger increments along with
246 * (platform dependent) clock ticks. For example, by default Windows clock ticks are 1/64 of a second (about 15 or
247 * 16 milliseconds) and Linux ticks are distribution and configuration dependent but usually 1/100 of a second (10
248 * milliseconds).
249 * <p>
250 * Nice and IOwait per processor information is not available on Windows, and IOwait and IRQ information is not
251 * available on macOS, so these ticks will always be zero.
252 * <p>
253 * To calculate overall Idle time using this method, include both Idle and IOWait ticks. Similarly, IRQ, SoftIRQ and
254 * Steal ticks should be added to the System value to get the total. System ticks also include time executing other
255 * virtual hosts (steal).
256 *
257 * @return A 2D array of logicalProcessorCount x 7 long values representing time spent in User, Nice, System, Idle,
258 * IOwait, IRQ, SoftIRQ, and Steal states.
259 */
260 long[][] getProcessorCpuLoadTicks();
261
262 /**
263 * Get the number of logical CPUs available for processing. This value may be higher than physical CPUs if
264 * hyperthreading is enabled.
265 * <p>
266 * On some operating systems with variable numbers of logical processors, may return a max value.
267 *
268 * @return The number of logical CPUs available.
269 */
270 int getLogicalProcessorCount();
271
272 /**
273 * Get the number of physical CPUs/cores available for processing.
274 * <p>
275 * On some operating systems with variable numbers of physical processors available to the OS, may return a max
276 * value.
277 *
278 * @return The number of physical CPUs available.
279 */
280 int getPhysicalProcessorCount();
281
282 /**
283 * Get the number of packages/sockets in the system. A single package may contain multiple cores.
284 *
285 * @return The number of physical packages available.
286 */
287 int getPhysicalPackageCount();
288
289 /**
290 * Get the number of system-wide context switches which have occurred.
291 * <p>
292 * Not available system-wide on macOS. Process- and Thread-level context switches are available from
293 * {@link OSProcess#getContextSwitches()} and {@link OSThread#getContextSwitches()}.
294 *
295 * @return The number of context switches, if this information is available; 0 otherwise.
296 */
297 long getContextSwitches();
298
299 /**
300 * Get the number of system-wide interrupts which have occurred.
301 * <p>
302 * Not available system-wide on macOS.
303 *
304 * @return The number of interrupts, if this information is available; 0 otherwise.
305 */
306 long getInterrupts();
307
308 /**
309 * Index of CPU tick counters in the {@link #getSystemCpuLoadTicks()} and {@link #getProcessorCpuLoadTicks()}
310 * arrays.
311 */
312 enum TickType {
313 /**
314 * CPU utilization that occurred while executing at the user level (application).
315 */
316 USER(0),
317 /**
318 * CPU utilization that occurred while executing at the user level with nice priority.
319 */
320 NICE(1),
321 /**
322 * CPU utilization that occurred while executing at the system level (kernel).
323 */
324 SYSTEM(2),
325 /**
326 * Time that the CPU or CPUs were idle and the system did not have an outstanding disk I/O request.
327 */
328 IDLE(3),
329 /**
330 * Time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.
331 */
332 IOWAIT(4),
333 /**
334 * Time that the CPU used to service hardware IRQs
335 */
336 IRQ(5),
337 /**
338 * Time that the CPU used to service soft IRQs
339 */
340 SOFTIRQ(6),
341 /**
342 * Time which the hypervisor dedicated for other guests in the system. Only supported on Linux and AIX
343 */
344 STEAL(7);
345
346 private final int index;
347
348 TickType(int value) {
349 this.index = value;
350 }
351
352 /**
353 * @return The integer index of this ENUM in the processor tick arrays, which matches the output of Linux
354 * /proc/cpuinfo
355 */
356 public int getIndex() {
357 return index;
358 }
359 }
360
361 /**
362 * A class representing a Logical Processor and its replationship to physical processors, physical packages, and
363 * logical groupings such as NUMA Nodes and Processor groups, useful for identifying processor topology.
364 */
365 @Immutable
366 class LogicalProcessor {
367 private final int processorNumber;
368 private final int physicalProcessorNumber;
369 private final int physicalPackageNumber;
370 private final int numaNode;
371 private final int processorGroup;
372
373 /**
374 * @param processorNumber the Processor number
375 * @param physicalProcessorNumber the core number
376 * @param physicalPackageNumber the package/socket number
377 */
378 public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber) {
379 this(processorNumber, physicalProcessorNumber, physicalPackageNumber, 0, 0);
380 }
381
382 /**
383 * @param processorNumber the Processor number
384 * @param physicalProcessorNumber the core number
385 * @param physicalPackageNumber the package/socket number
386 * @param numaNode the NUMA node number
387 */
388 public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber,
389 int numaNode) {
390 this(processorNumber, physicalProcessorNumber, physicalPackageNumber, numaNode, 0);
391 }
392
393 /**
394 * @param processorNumber the Processor number
395 * @param physicalProcessorNumber the core number
396 * @param physicalPackageNumber the package/socket number
397 * @param numaNode the NUMA node number
398 * @param processorGroup the Processor Group number
399 */
400 public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber,
401 int numaNode, int processorGroup) {
402 this.processorNumber = processorNumber;
403 this.physicalProcessorNumber = physicalProcessorNumber;
404 this.physicalPackageNumber = physicalPackageNumber;
405 this.numaNode = numaNode;
406 this.processorGroup = processorGroup;
407 }
408
409 /**
410 * The Logical Processor number as seen by the Operating System. Used for assigning process affinity and
411 * reporting CPU usage and other statistics.
412 *
413 * @return the processorNumber
414 */
415 public int getProcessorNumber() {
416 return processorNumber;
417 }
418
419 /**
420 * The physical processor (core) id number assigned to this logical processor. Hyperthreaded logical processors
421 * which share the same physical processor will have the same number.
422 *
423 * @return the physicalProcessorNumber
424 */
425 public int getPhysicalProcessorNumber() {
426 return physicalProcessorNumber;
427 }
428
429 /**
430 * The physical package (socket) id number assigned to this logical processor. Multicore CPU packages may have
431 * multiple physical processors which share the same number.
432 *
433 * @return the physicalPackageNumber
434 */
435 public int getPhysicalPackageNumber() {
436 return physicalPackageNumber;
437 }
438
439 /**
440 * The NUMA node. If the operating system supports Non-Uniform Memory Access this identifies the node number.
441 * Set to 0 if the operating system does not support NUMA. Not supported on macOS or FreeBSD.
442 *
443 * @return the NUMA Node number
444 */
445 public int getNumaNode() {
446 return numaNode;
447 }
448
449 /**
450 * The Processor Group. Only applies to Windows systems with more than 64 logical processors. Set to 0 for other
451 * operating systems or Windows systems with 64 or fewer logical processors.
452 *
453 * @return the processorGroup
454 */
455 public int getProcessorGroup() {
456 return processorGroup;
457 }
458
459 @Override
460 public String toString() {
461 return "LogicalProcessor [processorNumber=" + processorNumber + ", coreNumber=" + physicalProcessorNumber
462 + ", packageNumber=" + physicalPackageNumber + ", numaNode=" + numaNode + ", processorGroup="
463 + processorGroup + "]";
464 }
465 }
466
467 /**
468 * A class representing a Physical Processor (a core) providing per-core statistics that may vary, particularly in
469 * hybrid/modular processors.
470 */
471 @Immutable
472 class PhysicalProcessor {
473 private final int physicalPackageNumber;
474 private final int physicalProcessorNumber;
475 private final int efficiency;
476 private final String idString;
477
478 public PhysicalProcessor(int physicalPackageNumber, int physicalProcessorNumber) {
479 this(physicalPackageNumber, physicalProcessorNumber, 0, "");
480 }
481
482 public PhysicalProcessor(int physicalPackageNumber, int physicalProcessorNumber, int efficiency,
483 String idString) {
484 this.physicalPackageNumber = physicalPackageNumber;
485 this.physicalProcessorNumber = physicalProcessorNumber;
486 this.efficiency = efficiency;
487 this.idString = idString;
488 }
489
490 /**
491 * Gets the package id. This is also the physical package number which corresponds to
492 * {@link LogicalProcessor#getPhysicalPackageNumber()}.
493 *
494 * @return the physicalProcessorNumber
495 */
496 public int getPhysicalPackageNumber() {
497 return physicalPackageNumber;
498 }
499
500 /**
501 * Gets the core id. This is also the physical processor number which corresponds to
502 * {@link LogicalProcessor#getPhysicalProcessorNumber()}.
503 *
504 * @return the physicalProcessorNumber
505 */
506 public int getPhysicalProcessorNumber() {
507 return physicalProcessorNumber;
508 }
509
510 /**
511 * Gets a platform specific measure of processor performance vs. efficiency, useful for identifying cores in
512 * hybrid/System on Chip (SoC) processors such as ARM's big.LITTLE architecture, Apple's M1, and Intel's P-core
513 * and E-core hybrid technology. A core with a higher value for the efficiency class has intrinsically greater
514 * performance and less efficiency than a core with a lower value for the efficiency class.
515 *
516 * @return On Windows 10 and higher, returns the {@code EfficiencyClass} value from the
517 * {@code PROCESSOR_RELATIONSHIP} structure.
518 * <p>
519 * On macOS with Apple Silicon, emulates the same relative efficiency class values as Windows.
520 * <p>
521 * On Linux, returns the {@code cpu_capacity} value from sysfs. This is an optional cpu node property
522 * representing CPU capacity expressed in normalized DMIPS/MHz.
523 * <p>
524 * On OpenBSD, FreeBSD, and Solaris with ARM big.LITTLE processors, emulates the same relative
525 * efficiency class values as Windows.
526 * <p>
527 * For unimplemented operating systems or architectures, returns 0.
528 * @see <a href=
529 * "https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship">PROCESSOR_RELATIONSHIP</a>
530 * @see <a href=
531 * "https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/cpu-capacity.txt">cpu-capacity</a>
532 */
533 public int getEfficiency() {
534 return efficiency;
535 }
536
537 /**
538 * Gets a platform specific identification string representing this core. This string requires user parsing to
539 * obtain meaningful information. As this is an experimental feature, users should not rely on the format.
540 *
541 * @return On Windows, returns the per-core Processor ID (CPUID).
542 * <p>
543 * On macOS, returns a compatibility string from the IO Registry identifying hybrid cores.
544 * <p>
545 * On Linux, returns the {@code MODALIAS} value for the core's driver.
546 * <p>
547 * On OpenBSD, FreeBSD, and Solaris, returns a per-core CPU identification string.
548 * <p>
549 * For unimplemented operating systems, returns an empty string.
550 */
551 public String getIdString() {
552 return idString;
553 }
554
555 @Override
556 public String toString() {
557 return "PhysicalProcessor [package/core=" + physicalPackageNumber + "/" + physicalProcessorNumber
558 + ", efficiency=" + efficiency + ", idString=" + idString + "]";
559 }
560 }
561
562 /**
563 * A class representing CPU Cache Memory.
564 */
565 @Immutable
566 class ProcessorCache {
567
568 /**
569 * The type of cache.
570 */
571 public enum Type {
572 UNIFIED, INSTRUCTION, DATA, TRACE;
573
574 @Override
575 public String toString() {
576 return name().substring(0, 1) + name().substring(1).toLowerCase(Locale.ROOT);
577 }
578 }
579
580 private final byte level;
581 private final byte associativity;
582 private final short lineSize;
583 private final int cacheSize;
584 private final Type type;
585
586 public ProcessorCache(byte level, byte associativity, short lineSize, int cacheSize, Type type) {
587 this.level = level;
588 this.associativity = associativity;
589 this.lineSize = lineSize;
590 this.cacheSize = cacheSize;
591 this.type = type;
592 }
593
594 public ProcessorCache(int level, int associativity, int lineSize, long cacheSize, Type type) {
595 this((byte) level, (byte) associativity, (short) lineSize, (int) cacheSize, type);
596 }
597
598 /**
599 * The cache level. This member can be 1 (L1), 2 (L2), 3 (L3), or 4 (L4).
600 *
601 * @return the level
602 */
603 public byte getLevel() {
604 return level;
605 }
606
607 /**
608 * The cache associativity. If this member is {@code 0xFF}, the cache is fully associative.
609 *
610 * @return the associativity
611 */
612 public byte getAssociativity() {
613 return associativity;
614 }
615
616 /**
617 * The cache line size, in bytes.
618 *
619 * @return the line size
620 */
621 public short getLineSize() {
622 return lineSize;
623 }
624
625 /**
626 * The cache size, in bytes.
627 *
628 * @return the cache size
629 */
630 public int getCacheSize() {
631 return cacheSize;
632 }
633
634 /**
635 * The cache type.
636 *
637 * @return the type
638 */
639 public Type getType() {
640 return type;
641 }
642
643 @Override
644 public String toString() {
645 return "ProcessorCache [L" + level + " " + type + ", cacheSize=" + cacheSize + ", "
646 + (associativity > 0 ? associativity + "-way" : "unknown") + " associativity, lineSize=" + lineSize
647 + "]";
648 }
649
650 @Override
651 public boolean equals(Object obj) {
652 if (this == obj) {
653 return true;
654 }
655 if (obj == null || !(obj instanceof ProcessorCache)) {
656 return false;
657 }
658 ProcessorCache other = (ProcessorCache) obj;
659 return associativity == other.associativity && cacheSize == other.cacheSize && level == other.level
660 && lineSize == other.lineSize && type == other.type;
661 }
662
663 @Override
664 public int hashCode() {
665 return Objects.hash(associativity, cacheSize, level, lineSize, type);
666 }
667 }
668
669 /**
670 * A class encapsulating ghe CPU's identifier strings ,including name, vendor, stepping, model, and family
671 * information (also called the signature of a CPU)
672 */
673 @Immutable
674 final class ProcessorIdentifier {
675 private static final String OSHI_ARCHITECTURE_PROPERTIES = "oshi.architecture.properties";
676
677 // Provided in constructor
678 private final String cpuVendor;
679 private final String cpuName;
680 private final String cpuFamily;
681 private final String cpuModel;
682 private final String cpuStepping;
683 private final String processorID;
684 private final String cpuIdentifier;
685 private final boolean cpu64bit;
686 private final long cpuVendorFreq;
687
688 private final Supplier<String> microArchictecture = memoize(this::queryMicroarchitecture);
689
690 public ProcessorIdentifier(String cpuVendor, String cpuName, String cpuFamily, String cpuModel,
691 String cpuStepping, String processorID, boolean cpu64bit) {
692 this(cpuVendor, cpuName, cpuFamily, cpuModel, cpuStepping, processorID, cpu64bit, -1L);
693 }
694
695 public ProcessorIdentifier(String cpuVendor, String cpuName, String cpuFamily, String cpuModel,
696 String cpuStepping, String processorID, boolean cpu64bit, long vendorFreq) {
697 this.cpuVendor = cpuVendor.startsWith("0x") ? queryVendorFromImplementer(cpuVendor) : cpuVendor;
698 this.cpuName = cpuName;
699 this.cpuFamily = cpuFamily;
700 this.cpuModel = cpuModel;
701 this.cpuStepping = cpuStepping;
702 this.processorID = processorID;
703 this.cpu64bit = cpu64bit;
704
705 // Build Identifier
706 StringBuilder sb = new StringBuilder();
707 if (cpuVendor.contentEquals("GenuineIntel")) {
708 sb.append(cpu64bit ? "Intel64" : "x86");
709 } else {
710 sb.append(cpuVendor);
711 }
712 sb.append(" Family ").append(cpuFamily);
713 sb.append(" Model ").append(cpuModel);
714 sb.append(" Stepping ").append(cpuStepping);
715 this.cpuIdentifier = sb.toString();
716
717 if (vendorFreq > 0) {
718 this.cpuVendorFreq = vendorFreq;
719 } else {
720 // Parse Freq from name string
721 Pattern pattern = Pattern.compile("@ (.*)$");
722 Matcher matcher = pattern.matcher(cpuName);
723 if (matcher.find()) {
724 String unit = matcher.group(1);
725 this.cpuVendorFreq = ParseUtil.parseHertz(unit);
726 } else {
727 this.cpuVendorFreq = -1L;
728 }
729 }
730 }
731
732 /**
733 * Processor vendor.
734 *
735 * @return vendor string.
736 */
737 public String getVendor() {
738 return cpuVendor;
739 }
740
741 /**
742 * Name, eg. Intel(R) Core(TM)2 Duo CPU T7300 @ 2.00GHz
743 *
744 * @return Processor name.
745 */
746 public String getName() {
747 return cpuName;
748 }
749
750 /**
751 * Gets the family. For non-Intel/AMD processors, returns the comparable value, such as the Architecture.
752 *
753 * @return the family
754 */
755 public String getFamily() {
756 return cpuFamily;
757 }
758
759 /**
760 * Gets the model. For non-Intel/AMD processors, returns the comparable value, such as the Partnum.
761 *
762 * @return the model
763 */
764 public String getModel() {
765 return cpuModel;
766 }
767
768 /**
769 * Gets the stepping. For non-Intel/AMD processors, returns the comparable value, such as the rnpn composite of
770 * Variant and Revision.
771 *
772 * @return the stepping
773 */
774 public String getStepping() {
775 return cpuStepping;
776 }
777
778 /**
779 * Gets the Processor ID. This is a hexidecimal string representing an 8-byte value, normally obtained using the
780 * CPUID opcode with the EAX register set to 1. The first four bytes are the resulting contents of the EAX
781 * register, which is the Processor signature, represented in human-readable form by {@link #getIdentifier()} .
782 * The remaining four bytes are the contents of the EDX register, containing feature flags.
783 * <p>
784 * For processors that do not support the CPUID opcode this field is populated with a comparable hex string. For
785 * example, ARM Processors will fill the first 32 bytes with the MIDR. AIX PowerPC Processors will return the
786 * machine ID.
787 * <p>
788 * NOTE: The order of returned bytes is platform and software dependent. Values may be in either Big Endian or
789 * Little Endian order.
790 * <p>
791 * NOTE: If OSHI is unable to determine the ProcessorID from native sources, it will attempt to reconstruct one
792 * from available information in the processor identifier.
793 *
794 * @return A string representing the Processor ID
795 */
796 public String getProcessorID() {
797 return processorID;
798 }
799
800 /**
801 * Identifier, eg. x86 Family 6 Model 15 Stepping 10. For non-Intel/AMD processors, this string is populated
802 * with comparable values.
803 *
804 * @return Processor identifier.
805 */
806 public String getIdentifier() {
807 return cpuIdentifier;
808 }
809
810 /**
811 * Is CPU 64bit?
812 *
813 * @return True if cpu is 64bit.
814 */
815 public boolean isCpu64bit() {
816 return cpu64bit;
817 }
818
819 /**
820 * Vendor frequency (in Hz), eg. for processor named Intel(R) Core(TM)2 Duo CPU T7300 @ 2.00GHz the vendor
821 * frequency is 2000000000.
822 *
823 * @return Processor frequency or -1 if unknown.
824 */
825 public long getVendorFreq() {
826 return cpuVendorFreq;
827 }
828
829 /**
830 * Returns the processor's microarchitecture, if known.
831 *
832 * @return A string containing the microarchitecture if known. {@link Constants#UNKNOWN} otherwise.
833 */
834 public String getMicroarchitecture() {
835 return microArchictecture.get();
836 }
837
838 private String queryMicroarchitecture() {
839 String arch = null;
840 Properties archProps = FileUtil.readPropertiesFromFilename(OSHI_ARCHITECTURE_PROPERTIES);
841 // Intel is default, no prefix
842 StringBuilder sb = new StringBuilder();
843 // AMD and ARM properties have prefix
844 String ucVendor = this.cpuVendor.toUpperCase(Locale.ROOT);
845 if (ucVendor.contains("AMD")) {
846 sb.append("amd.");
847 } else if (ucVendor.contains("ARM")) {
848 sb.append("arm.");
849 } else if (ucVendor.contains("IBM")) {
850 // Directly parse the name to POWER#
851 int powerIdx = this.cpuName.indexOf("_POWER");
852 if (powerIdx > 0) {
853 arch = this.cpuName.substring(powerIdx + 1);
854 }
855 } else if (ucVendor.contains("APPLE")) {
856 sb.append("apple.");
857 }
858 if (Util.isBlank(arch) && !sb.toString().equals("arm.")) {
859 // Append family
860 sb.append(this.cpuFamily);
861 arch = archProps.getProperty(sb.toString());
862 }
863
864 if (Util.isBlank(arch)) {
865 // Append model
866 sb.append('.').append(this.cpuModel);
867 arch = archProps.getProperty(sb.toString());
868 }
869
870 if (Util.isBlank(arch)) {
871 // Append stepping
872 sb.append('.').append(this.cpuStepping);
873 arch = archProps.getProperty(sb.toString());
874 }
875
876 return Util.isBlank(arch) ? Constants.UNKNOWN : arch;
877 }
878
879 private String queryVendorFromImplementer(String cpuVendor) {
880 Properties archProps = FileUtil.readPropertiesFromFilename(OSHI_ARCHITECTURE_PROPERTIES);
881 return archProps.getProperty("hw_impl." + cpuVendor, cpuVendor);
882 }
883
884 @Override
885 public String toString() {
886 return getIdentifier();
887 }
888 }
889 }