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 }