View Javadoc
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             String vendor = archProps.getProperty("hw_impl." + this.cpuVendor);
882             return (vendor == null ? cpuVendor : vendor);
883         }
884 
885         @Override
886         public String toString() {
887             return getIdentifier();
888         }
889     }
890 }