All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neko233.toolchain.metrics.cpu.CentralProcessor Maven / Gradle / Ivy

package com.neko233.toolchain.metrics.cpu;

import com.neko233.toolchain.common.base.*;
import com.neko233.toolchain.common.file.FileUtils233;
import com.neko233.toolchain.common.annotation.Immutable;
import com.neko233.toolchain.common.annotation.ThreadSafe;

import java.util.List;
import java.util.Properties;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@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 consistent with other methods providing per-processor * results. * * @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(); /** * Returns the "recent cpu usage" for the whole system by counting ticks from * {@link #getSystemCpuLoadTicks()} between the user-provided value from a * previous call. * * @param oldTicks A tick array from a previous call to * {@link #getSystemCpuLoadTicks()} * @return CPU load between 0 and 1 (100%) */ 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 TickType} 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 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 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) { ThreadUtils233.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. * * @param delay Milliseconds to wait. * @return array of CPU load between 0 and 1 (100%) for each logical processor, * for the provided time period. */ 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) { ThreadUtils233.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. * * @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 */ 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 TickType} 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. * * @return The number of logical CPUs available. */ int getLogicalProcessorCount(); /** * Get the number of physical CPUs/cores available for processing. * * @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(); /** * 获取一个数字, 当因 Mac/Windows/Linux 不兼容时, 自动切换 * Get the number of system-wide context switches which have occurred. * * @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 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 = "neko233.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 = Memoizer.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; 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 = DeviceParseUtil233.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 Constants233#UNKNOWN} otherwise. */ public String getMicroarchitecture() { return microArchictecture.get(); } private String queryMicroarchitecture() { String arch = null; Properties archProps = FileUtils233.readPropertiesFromFilename(OSHI_ARCHITECTURE_PROPERTIES); // Intel is default, no prefix StringBuilder sb = new StringBuilder(); // AMD and ARM properties have prefix String ucVendor = this.cpuVendor.toUpperCase(); 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 (StringUtils233.isBlank(arch) && !sb.toString().equals("arm.")) { // Append family sb.append(this.cpuFamily); arch = archProps.getProperty(sb.toString()); } if (StringUtils233.isBlank(arch)) { // Append model sb.append('.').append(this.cpuModel); arch = archProps.getProperty(sb.toString()); } if (StringUtils233.isBlank(arch)) { // Append stepping sb.append('.').append(this.cpuStepping); arch = archProps.getProperty(sb.toString()); } return StringUtils233.isBlank(arch) ? Constants233.UNKNOWN : arch; } @Override public String toString() { return getIdentifier(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy