oshi.hardware.CentralProcessor Maven / Gradle / Ivy
/*
* Copyright 2016-2024 The OSHI Project Contributors
* SPDX-License-Identifier: MIT
*/
package oshi.hardware;
import static oshi.util.Memoizer.memoize;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import oshi.annotation.concurrent.Immutable;
import oshi.annotation.concurrent.ThreadSafe;
import oshi.software.os.OSProcess;
import oshi.software.os.OSThread;
import oshi.util.Constants;
import oshi.util.FileUtil;
import oshi.util.ParseUtil;
import oshi.util.Util;
/**
* This class represents the entire Central Processing Unit (CPU) of a computer system, which may contain one or more
* physical packages (sockets), one or more physical processors (cores), and one or more logical processors (what the
* Operating System sees, which may include hyperthreaded cores.)
*/
@ThreadSafe
public interface CentralProcessor {
/**
* The CPU's identifier strings ,including name, vendor, stepping, model, and family information (also called the
* signature of a CPU).
*
* The Processor Identifier is primarily associated with Intel-based chips. Attempts are made to provide comparable
* values for other chip manufacturers.
*
* @return a {@link ProcessorIdentifier} object encapsulating CPU identifier information.
*/
ProcessorIdentifier getProcessorIdentifier();
/**
* Maximum frequeny (in Hz), of the logical processors on this CPU.
*
* @return The max frequency or -1 if unknown.
*/
long getMaxFreq();
/**
* Attempts to return the current frequency (in Hz), of the logical processors on this CPU.
*
* May not be implemented on all Operating Systems.
*
* On Windows, returns an estimate based on the percent of maximum frequency. On Windows systems with more than 64
* logical processors, may only return frequencies for the current processor group in the first portion of the
* array.
*
* @return An array of processor frequencies for each logical processor on the system. Use the
* {@link #getLogicalProcessors()} to correlate these frequencies with physical packages and processors.
*/
long[] getCurrentFreq();
/**
* Returns an {@code UnmodifiableList} of the CPU's logical processors. The list will be sorted in order of
* increasing NUMA node number, and then processor number. This order is (usually) consistent with other methods
* providing per-processor results.
*
* On some operating systems with variable numbers of logical processors, the size of this array could change and
* may not align with other per-processor methods.
*
* @return An {@code UnmodifiabeList} of logical processors.
*/
List getLogicalProcessors();
/**
* Returns an {@code UnmodifiableList} of the CPU's physical processors. The list will be sorted in order of
* increasing core ID.
*
* @return An {@code UnmodifiabeList} of physical processors.
*/
List getPhysicalProcessors();
/**
* Makes a best-effort attempt to identify the CPU's processor caches. For hybrid processors, both performance and
* efficiency core caches are shown. Only one instance of per-core caches is shown.
*
* Values are unreliable in virtual machines and rely in information made available by the VM or hypervisor. Callers
* should conduct sanity checking of the returned objects. Not all values are available on all operating systems or
* architectures.
*
* Not available on Solaris.
*
* @return An {@code UnmodifiabeList} of processor caches.
*/
List getProcessorCaches();
/**
* Returns a list of platform-specific strings which identify CPU Feature Flags. This string requires user parsing
* to obtain meaningful information.
*
* @return On Windows, returns a list of values for which the {@code IsProcessorFeaturePresent()} function evaluates
* to true.
*
* On macOS x86, returns relevant {@code sysctl.machdep.feature} values. On Apple Silicon, returns relevant
* {@code sysctl hw.optional.arm.FEAT} values.
*
* On Linux, returns the {@code flags} and/or {@code features} fields from {@code /proc/cpuinfo}.
*
* On OpenBSD, FreeBSD, and Solaris, returns {@code dmesg} output containing the word {@code Feature}.
*
* For unimplemented operating systems, returns an empty list.
*/
List getFeatureFlags();
/**
* Returns the "recent cpu usage" for the whole system by counting ticks from {@link #getSystemCpuLoadTicks()}
* between the user-provided value from a previous call.
*
* On some operating systems with variable numbers of logical processors, the size of the array returned from a
* previous call to {@link #getSystemCpuLoadTicks()} could change and will throw an
* {@link IllegalArgumentException}. Calling code on these operating systems should handle this exception.
*
* @param oldTicks A tick array from a previous call to {@link #getSystemCpuLoadTicks()}
* @return CPU load between 0 and 1 (100%)
* @throws IllegalArgumentException if the array sizes differ.
*/
double getSystemCpuLoadBetweenTicks(long[] oldTicks);
/**
* Get System-wide CPU Load tick counters. Returns an array with eight elements representing milliseconds spent in
* User (0), Nice (1), System (2), Idle (3), IOwait (4), Hardware interrupts (IRQ) (5), Software interrupts/DPC
* (SoftIRQ) (6), or Steal (7) states. Use {@link oshi.hardware.CentralProcessor.TickType#getIndex()} to retrieve
* the appropriate index. By measuring the difference between ticks across a time interval, CPU load over that
* interval may be calculated.
*
* On some operating systems with variable numbers of logical processors, the size of this array could change and
* may not align with other per-processor methods.
*
* Note that while tick counters are in units of milliseconds, they may advance in larger increments along with
* (platform dependent) clock ticks. For example, by default Windows clock ticks are 1/64 of a second (about 15 or
* 16 milliseconds) and Linux ticks are distribution and configuration dependent but usually 1/100 of a second (10
* milliseconds).
*
* Nice and IOWait information is not available on Windows, and IOwait and IRQ information is not available on
* macOS, so these ticks will always be zero.
*
* To calculate overall Idle time using this method, include both Idle and IOWait ticks. Similarly, IRQ, SoftIRQ,
* and Steal ticks should be added to the System value to get the total. System ticks also include time executing
* other virtual hosts (steal).
*
* @return An array of 8 long values representing time spent in User, Nice, System, Idle, IOwait, IRQ, SoftIRQ, and
* Steal states.
*/
long[] getSystemCpuLoadTicks();
/**
* Returns the system load average for the number of elements specified, up to 3, representing 1, 5, and 15 minutes.
* The system load average is the sum of the number of runnable entities queued to the available processors and the
* number of runnable entities running on the available processors averaged over a period of time.
*
* This method is designed to provide a hint about the system load and may be queried frequently.
*
* The way in which the load average is calculated is operating system specific but is typically a damped
* time-dependent average. Linux includes processes waiting for system resources such as disks, while macOS and Unix
* consider only processes waiting for CPU.
*
* Windows does not provide a load average. Users may set the configuration property
* {@code oshi.os.windows.loadaverage} to {@code true} to start a daemon thread which will provide a similar metric.
*
* The load average may be unavailable on some platforms (e.g., Windows without the above configuration). If the
* load average is not available, a negative value is returned.
*
* @param nelem Number of elements to return.
* @return an array of the system load averages for 1, 5, and 15 minutes with the size of the array specified by
* nelem; or negative values if not available.
*/
double[] getSystemLoadAverage(int nelem);
/**
* This is a convenience method which collects an initial set of ticks using {@link #getSystemCpuLoadTicks()} and
* passes that result to {@link #getSystemCpuLoadBetweenTicks(long[])} after the specified delay.
*
*
* @param delay Milliseconds to wait.
* @return value between 0 and 1 (100%) that represents the cpu usage in the provided time period.
*/
default double getSystemCpuLoad(long delay) {
long start = System.nanoTime();
long[] oldTicks = getSystemCpuLoadTicks();
long toWait = delay - (System.nanoTime() - start) / 1_000_000;
// protect against IllegalArgumentException
if (toWait > 0L) {
Util.sleep(delay);
}
return getSystemCpuLoadBetweenTicks(oldTicks);
}
/**
* This is a convenience method which collects an initial set of ticks using {@link #getProcessorCpuLoadTicks()} and
* passes that result to {@link #getProcessorCpuLoadBetweenTicks(long[][])} after the specified delay.
*
* On some operating systems with variable numbers of logical processors, the size of the array returned from the
* two calls could change and will throw an {@link IllegalArgumentException}. Calling code on these operating
* systems should handle this exception.
*
* @param delay Milliseconds to wait.
* @return array of CPU load between 0 and 1 (100%) for each logical processor, for the provided time period.
* @throws IllegalArgumentException if the array sizes differ between calls.
*/
default double[] getProcessorCpuLoad(long delay) {
long start = System.nanoTime();
long[][] oldTicks = getProcessorCpuLoadTicks();
long toWait = delay - (System.nanoTime() - start) / 1_000_000;
// protect against IllegalArgumentException
if (toWait > 0L) {
Util.sleep(delay);
}
return getProcessorCpuLoadBetweenTicks(oldTicks);
}
/**
* Returns the "recent cpu usage" for all logical processors by counting ticks from
* {@link #getProcessorCpuLoadTicks()} between the user-provided value from a previous call.
*
* On some operating systems with variable numbers of logical processors, the size of the array returned from the
* two calls could change and will throw an {@link IllegalArgumentException}. Calling code on these operating
* systems should handle this exception.
*
* @param oldTicks A tick array from a previous call to {@link #getProcessorCpuLoadTicks()}
* @return array of CPU load between 0 and 1 (100%) for each logical processor
* @throws IllegalArgumentException if the array sizes differ between calls.
*/
double[] getProcessorCpuLoadBetweenTicks(long[][] oldTicks);
/**
* Get Processor CPU Load tick counters. Returns a two dimensional array, with {@link #getLogicalProcessorCount()}
* arrays, each containing seven elements representing milliseconds spent in User (0), Nice (1), System (2), Idle
* (3), IOwait (4), Hardware interrupts (IRQ) (5), Software interrupts/DPC (SoftIRQ) (6), or Steal (7) states. Use
* {@link oshi.hardware.CentralProcessor.TickType#getIndex()} to retrieve the appropriate index. By measuring the
* difference between ticks across a time interval, CPU load over that interval may be calculated.
*
* Note that while tick counters are in units of milliseconds, they may advance in larger increments along with
* (platform dependent) clock ticks. For example, by default Windows clock ticks are 1/64 of a second (about 15 or
* 16 milliseconds) and Linux ticks are distribution and configuration dependent but usually 1/100 of a second (10
* milliseconds).
*
* Nice and IOwait per processor information is not available on Windows, and IOwait and IRQ information is not
* available on macOS, so these ticks will always be zero.
*
* To calculate overall Idle time using this method, include both Idle and IOWait ticks. Similarly, IRQ, SoftIRQ and
* Steal ticks should be added to the System value to get the total. System ticks also include time executing other
* virtual hosts (steal).
*
* @return A 2D array of logicalProcessorCount x 7 long values representing time spent in User, Nice, System, Idle,
* IOwait, IRQ, SoftIRQ, and Steal states.
*/
long[][] getProcessorCpuLoadTicks();
/**
* Get the number of logical CPUs available for processing. This value may be higher than physical CPUs if
* hyperthreading is enabled.
*
* On some operating systems with variable numbers of logical processors, may return a max value.
*
* @return The number of logical CPUs available.
*/
int getLogicalProcessorCount();
/**
* Get the number of physical CPUs/cores available for processing.
*
* On some operating systems with variable numbers of physical processors available to the OS, may return a max
* value.
*
* @return The number of physical CPUs available.
*/
int getPhysicalProcessorCount();
/**
* Get the number of packages/sockets in the system. A single package may contain multiple cores.
*
* @return The number of physical packages available.
*/
int getPhysicalPackageCount();
/**
* Get the number of system-wide context switches which have occurred.
*
* Not available system-wide on macOS. Process- and Thread-level context switches are available from
* {@link OSProcess#getContextSwitches()} and {@link OSThread#getContextSwitches()}.
*
* @return The number of context switches, if this information is available; 0 otherwise.
*/
long getContextSwitches();
/**
* Get the number of system-wide interrupts which have occurred.
*
* Not available system-wide on macOS.
*
* @return The number of interrupts, if this information is available; 0 otherwise.
*/
long getInterrupts();
/**
* Index of CPU tick counters in the {@link #getSystemCpuLoadTicks()} and {@link #getProcessorCpuLoadTicks()}
* arrays.
*/
enum TickType {
/**
* CPU utilization that occurred while executing at the user level (application).
*/
USER(0),
/**
* CPU utilization that occurred while executing at the user level with nice priority.
*/
NICE(1),
/**
* CPU utilization that occurred while executing at the system level (kernel).
*/
SYSTEM(2),
/**
* Time that the CPU or CPUs were idle and the system did not have an outstanding disk I/O request.
*/
IDLE(3),
/**
* Time that the CPU or CPUs were idle during which the system had an outstanding disk I/O request.
*/
IOWAIT(4),
/**
* Time that the CPU used to service hardware IRQs
*/
IRQ(5),
/**
* Time that the CPU used to service soft IRQs
*/
SOFTIRQ(6),
/**
* Time which the hypervisor dedicated for other guests in the system. Only supported on Linux and AIX
*/
STEAL(7);
private final int index;
TickType(int value) {
this.index = value;
}
/**
* @return The integer index of this ENUM in the processor tick arrays, which matches the output of Linux
* /proc/cpuinfo
*/
public int getIndex() {
return index;
}
}
/**
* A class representing a Logical Processor and its replationship to physical processors, physical packages, and
* logical groupings such as NUMA Nodes and Processor groups, useful for identifying processor topology.
*/
@Immutable
class LogicalProcessor {
private final int processorNumber;
private final int physicalProcessorNumber;
private final int physicalPackageNumber;
private final int numaNode;
private final int processorGroup;
/**
* @param processorNumber the Processor number
* @param physicalProcessorNumber the core number
* @param physicalPackageNumber the package/socket number
*/
public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber) {
this(processorNumber, physicalProcessorNumber, physicalPackageNumber, 0, 0);
}
/**
* @param processorNumber the Processor number
* @param physicalProcessorNumber the core number
* @param physicalPackageNumber the package/socket number
* @param numaNode the NUMA node number
*/
public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber,
int numaNode) {
this(processorNumber, physicalProcessorNumber, physicalPackageNumber, numaNode, 0);
}
/**
* @param processorNumber the Processor number
* @param physicalProcessorNumber the core number
* @param physicalPackageNumber the package/socket number
* @param numaNode the NUMA node number
* @param processorGroup the Processor Group number
*/
public LogicalProcessor(int processorNumber, int physicalProcessorNumber, int physicalPackageNumber,
int numaNode, int processorGroup) {
this.processorNumber = processorNumber;
this.physicalProcessorNumber = physicalProcessorNumber;
this.physicalPackageNumber = physicalPackageNumber;
this.numaNode = numaNode;
this.processorGroup = processorGroup;
}
/**
* The Logical Processor number as seen by the Operating System. Used for assigning process affinity and
* reporting CPU usage and other statistics.
*
* @return the processorNumber
*/
public int getProcessorNumber() {
return processorNumber;
}
/**
* The physical processor (core) id number assigned to this logical processor. Hyperthreaded logical processors
* which share the same physical processor will have the same number.
*
* @return the physicalProcessorNumber
*/
public int getPhysicalProcessorNumber() {
return physicalProcessorNumber;
}
/**
* The physical package (socket) id number assigned to this logical processor. Multicore CPU packages may have
* multiple physical processors which share the same number.
*
* @return the physicalPackageNumber
*/
public int getPhysicalPackageNumber() {
return physicalPackageNumber;
}
/**
* The NUMA node. If the operating system supports Non-Uniform Memory Access this identifies the node number.
* Set to 0 if the operating system does not support NUMA. Not supported on macOS or FreeBSD.
*
* @return the NUMA Node number
*/
public int getNumaNode() {
return numaNode;
}
/**
* The Processor Group. Only applies to Windows systems with more than 64 logical processors. Set to 0 for other
* operating systems or Windows systems with 64 or fewer logical processors.
*
* @return the processorGroup
*/
public int getProcessorGroup() {
return processorGroup;
}
@Override
public String toString() {
return "LogicalProcessor [processorNumber=" + processorNumber + ", coreNumber=" + physicalProcessorNumber
+ ", packageNumber=" + physicalPackageNumber + ", numaNode=" + numaNode + ", processorGroup="
+ processorGroup + "]";
}
}
/**
* A class representing a Physical Processor (a core) providing per-core statistics that may vary, particularly in
* hybrid/modular processors.
*/
@Immutable
class PhysicalProcessor {
private final int physicalPackageNumber;
private final int physicalProcessorNumber;
private final int efficiency;
private final String idString;
public PhysicalProcessor(int physicalPackageNumber, int physicalProcessorNumber) {
this(physicalPackageNumber, physicalProcessorNumber, 0, "");
}
public PhysicalProcessor(int physicalPackageNumber, int physicalProcessorNumber, int efficiency,
String idString) {
this.physicalPackageNumber = physicalPackageNumber;
this.physicalProcessorNumber = physicalProcessorNumber;
this.efficiency = efficiency;
this.idString = idString;
}
/**
* Gets the package id. This is also the physical package number which corresponds to
* {@link LogicalProcessor#getPhysicalPackageNumber()}.
*
* @return the physicalProcessorNumber
*/
public int getPhysicalPackageNumber() {
return physicalPackageNumber;
}
/**
* Gets the core id. This is also the physical processor number which corresponds to
* {@link LogicalProcessor#getPhysicalProcessorNumber()}.
*
* @return the physicalProcessorNumber
*/
public int getPhysicalProcessorNumber() {
return physicalProcessorNumber;
}
/**
* Gets a platform specific measure of processor performance vs. efficiency, useful for identifying cores in
* hybrid/System on Chip (SoC) processors such as ARM's big.LITTLE architecture, Apple's M1, and Intel's P-core
* and E-core hybrid technology. A core with a higher value for the efficiency class has intrinsically greater
* performance and less efficiency than a core with a lower value for the efficiency class.
*
* @return On Windows 10 and higher, returns the {@code EfficiencyClass} value from the
* {@code PROCESSOR_RELATIONSHIP} structure.
*
* On macOS with Apple Silicon, emulates the same relative efficiency class values as Windows.
*
* On Linux, returns the {@code cpu_capacity} value from sysfs. This is an optional cpu node property
* representing CPU capacity expressed in normalized DMIPS/MHz.
*
* On OpenBSD, FreeBSD, and Solaris with ARM big.LITTLE processors, emulates the same relative
* efficiency class values as Windows.
*
* For unimplemented operating systems or architectures, returns 0.
* @see PROCESSOR_RELATIONSHIP
* @see cpu-capacity
*/
public int getEfficiency() {
return efficiency;
}
/**
* Gets a platform specific identification string representing this core. This string requires user parsing to
* obtain meaningful information. As this is an experimental feature, users should not rely on the format.
*
* @return On Windows, returns the per-core Processor ID (CPUID).
*
* On macOS, returns a compatibility string from the IO Registry identifying hybrid cores.
*
* On Linux, returns the {@code MODALIAS} value for the core's driver.
*
* On OpenBSD, FreeBSD, and Solaris, returns a per-core CPU identification string.
*
* For unimplemented operating systems, returns an empty string.
*/
public String getIdString() {
return idString;
}
@Override
public String toString() {
return "PhysicalProcessor [package/core=" + physicalPackageNumber + "/" + physicalProcessorNumber
+ ", efficiency=" + efficiency + ", idString=" + idString + "]";
}
}
/**
* A class representing CPU Cache Memory.
*/
@Immutable
class ProcessorCache {
/**
* The type of cache.
*/
public enum Type {
UNIFIED, INSTRUCTION, DATA, TRACE;
@Override
public String toString() {
return name().substring(0, 1) + name().substring(1).toLowerCase(Locale.ROOT);
}
}
private final byte level;
private final byte associativity;
private final short lineSize;
private final int cacheSize;
private final Type type;
public ProcessorCache(byte level, byte associativity, short lineSize, int cacheSize, Type type) {
this.level = level;
this.associativity = associativity;
this.lineSize = lineSize;
this.cacheSize = cacheSize;
this.type = type;
}
public ProcessorCache(int level, int associativity, int lineSize, long cacheSize, Type type) {
this((byte) level, (byte) associativity, (short) lineSize, (int) cacheSize, type);
}
/**
* The cache level. This member can be 1 (L1), 2 (L2), 3 (L3), or 4 (L4).
*
* @return the level
*/
public byte getLevel() {
return level;
}
/**
* The cache associativity. If this member is {@code 0xFF}, the cache is fully associative.
*
* @return the associativity
*/
public byte getAssociativity() {
return associativity;
}
/**
* The cache line size, in bytes.
*
* @return the line size
*/
public short getLineSize() {
return lineSize;
}
/**
* The cache size, in bytes.
*
* @return the cache size
*/
public int getCacheSize() {
return cacheSize;
}
/**
* The cache type.
*
* @return the type
*/
public Type getType() {
return type;
}
@Override
public String toString() {
return "ProcessorCache [L" + level + " " + type + ", cacheSize=" + cacheSize + ", "
+ (associativity > 0 ? associativity + "-way" : "unknown") + " associativity, lineSize=" + lineSize
+ "]";
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !(obj instanceof ProcessorCache)) {
return false;
}
ProcessorCache other = (ProcessorCache) obj;
return associativity == other.associativity && cacheSize == other.cacheSize && level == other.level
&& lineSize == other.lineSize && type == other.type;
}
@Override
public int hashCode() {
return Objects.hash(associativity, cacheSize, level, lineSize, type);
}
}
/**
* A class encapsulating ghe CPU's identifier strings ,including name, vendor, stepping, model, and family
* information (also called the signature of a CPU)
*/
@Immutable
final class ProcessorIdentifier {
private static final String OSHI_ARCHITECTURE_PROPERTIES = "oshi.architecture.properties";
// Provided in constructor
private final String cpuVendor;
private final String cpuName;
private final String cpuFamily;
private final String cpuModel;
private final String cpuStepping;
private final String processorID;
private final String cpuIdentifier;
private final boolean cpu64bit;
private final long cpuVendorFreq;
private final Supplier microArchictecture = memoize(this::queryMicroarchitecture);
public ProcessorIdentifier(String cpuVendor, String cpuName, String cpuFamily, String cpuModel,
String cpuStepping, String processorID, boolean cpu64bit) {
this(cpuVendor, cpuName, cpuFamily, cpuModel, cpuStepping, processorID, cpu64bit, -1L);
}
public ProcessorIdentifier(String cpuVendor, String cpuName, String cpuFamily, String cpuModel,
String cpuStepping, String processorID, boolean cpu64bit, long vendorFreq) {
this.cpuVendor = cpuVendor.startsWith("0x") ? queryVendorFromImplementer(cpuVendor) : cpuVendor;
this.cpuName = cpuName;
this.cpuFamily = cpuFamily;
this.cpuModel = cpuModel;
this.cpuStepping = cpuStepping;
this.processorID = processorID;
this.cpu64bit = cpu64bit;
// Build Identifier
StringBuilder sb = new StringBuilder();
if (cpuVendor.contentEquals("GenuineIntel")) {
sb.append(cpu64bit ? "Intel64" : "x86");
} else {
sb.append(cpuVendor);
}
sb.append(" Family ").append(cpuFamily);
sb.append(" Model ").append(cpuModel);
sb.append(" Stepping ").append(cpuStepping);
this.cpuIdentifier = sb.toString();
if (vendorFreq > 0) {
this.cpuVendorFreq = vendorFreq;
} else {
// Parse Freq from name string
Pattern pattern = Pattern.compile("@ (.*)$");
Matcher matcher = pattern.matcher(cpuName);
if (matcher.find()) {
String unit = matcher.group(1);
this.cpuVendorFreq = ParseUtil.parseHertz(unit);
} else {
this.cpuVendorFreq = -1L;
}
}
}
/**
* Processor vendor.
*
* @return vendor string.
*/
public String getVendor() {
return cpuVendor;
}
/**
* Name, eg. Intel(R) Core(TM)2 Duo CPU T7300 @ 2.00GHz
*
* @return Processor name.
*/
public String getName() {
return cpuName;
}
/**
* Gets the family. For non-Intel/AMD processors, returns the comparable value, such as the Architecture.
*
* @return the family
*/
public String getFamily() {
return cpuFamily;
}
/**
* Gets the model. For non-Intel/AMD processors, returns the comparable value, such as the Partnum.
*
* @return the model
*/
public String getModel() {
return cpuModel;
}
/**
* Gets the stepping. For non-Intel/AMD processors, returns the comparable value, such as the rnpn composite of
* Variant and Revision.
*
* @return the stepping
*/
public String getStepping() {
return cpuStepping;
}
/**
* Gets the Processor ID. This is a hexidecimal string representing an 8-byte value, normally obtained using the
* CPUID opcode with the EAX register set to 1. The first four bytes are the resulting contents of the EAX
* register, which is the Processor signature, represented in human-readable form by {@link #getIdentifier()} .
* The remaining four bytes are the contents of the EDX register, containing feature flags.
*
* For processors that do not support the CPUID opcode this field is populated with a comparable hex string. For
* example, ARM Processors will fill the first 32 bytes with the MIDR. AIX PowerPC Processors will return the
* machine ID.
*
* NOTE: The order of returned bytes is platform and software dependent. Values may be in either Big Endian or
* Little Endian order.
*
* NOTE: If OSHI is unable to determine the ProcessorID from native sources, it will attempt to reconstruct one
* from available information in the processor identifier.
*
* @return A string representing the Processor ID
*/
public String getProcessorID() {
return processorID;
}
/**
* Identifier, eg. x86 Family 6 Model 15 Stepping 10. For non-Intel/AMD processors, this string is populated
* with comparable values.
*
* @return Processor identifier.
*/
public String getIdentifier() {
return cpuIdentifier;
}
/**
* Is CPU 64bit?
*
* @return True if cpu is 64bit.
*/
public boolean isCpu64bit() {
return cpu64bit;
}
/**
* Vendor frequency (in Hz), eg. for processor named Intel(R) Core(TM)2 Duo CPU T7300 @ 2.00GHz the vendor
* frequency is 2000000000.
*
* @return Processor frequency or -1 if unknown.
*/
public long getVendorFreq() {
return cpuVendorFreq;
}
/**
* Returns the processor's microarchitecture, if known.
*
* @return A string containing the microarchitecture if known. {@link Constants#UNKNOWN} otherwise.
*/
public String getMicroarchitecture() {
return microArchictecture.get();
}
private String queryMicroarchitecture() {
String arch = null;
Properties archProps = FileUtil.readPropertiesFromFilename(OSHI_ARCHITECTURE_PROPERTIES);
// Intel is default, no prefix
StringBuilder sb = new StringBuilder();
// AMD and ARM properties have prefix
String ucVendor = this.cpuVendor.toUpperCase(Locale.ROOT);
if (ucVendor.contains("AMD")) {
sb.append("amd.");
} else if (ucVendor.contains("ARM")) {
sb.append("arm.");
} else if (ucVendor.contains("IBM")) {
// Directly parse the name to POWER#
int powerIdx = this.cpuName.indexOf("_POWER");
if (powerIdx > 0) {
arch = this.cpuName.substring(powerIdx + 1);
}
} else if (ucVendor.contains("APPLE")) {
sb.append("apple.");
}
if (Util.isBlank(arch) && !sb.toString().equals("arm.")) {
// Append family
sb.append(this.cpuFamily);
arch = archProps.getProperty(sb.toString());
}
if (Util.isBlank(arch)) {
// Append model
sb.append('.').append(this.cpuModel);
arch = archProps.getProperty(sb.toString());
}
if (Util.isBlank(arch)) {
// Append stepping
sb.append('.').append(this.cpuStepping);
arch = archProps.getProperty(sb.toString());
}
return Util.isBlank(arch) ? Constants.UNKNOWN : arch;
}
private String queryVendorFromImplementer(String cpuVendor) {
Properties archProps = FileUtil.readPropertiesFromFilename(OSHI_ARCHITECTURE_PROPERTIES);
return archProps.getProperty("hw_impl." + cpuVendor, cpuVendor);
}
@Override
public String toString() {
return getIdentifier();
}
}
}