/** * Oshi (https://github.com/oshi/oshi) * * Copyright (c) 2010 - 2017 The Oshi Project Team * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Maintainers: * dblock[at]dblock[dot]org * widdis[at]gmail[dot]com * enrico.bianchi[at]gmail[dot]com * * Contributors: * https://github.com/oshi/oshi/graphs/contributors */ package oshi.hardware.platform.windows; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sun.jna.Native; import com.sun.jna.platform.win32.Advapi32Util; import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.Kernel32Util; import com.sun.jna.platform.win32.WinBase; import com.sun.jna.platform.win32.WinBase.SYSTEM_INFO; import com.sun.jna.platform.win32.WinNT; import com.sun.jna.platform.win32.WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION; import com.sun.jna.platform.win32.WinReg; import oshi.hardware.common.AbstractCentralProcessor; import oshi.util.ParseUtil; import oshi.util.platform.windows.WmiUtil; /** * A CPU as defined in Windows registry. * * @author dblock[at]dblock[dot]org * @author alessio.fachechi[at]gmail[dot]com * @author widdis[at]gmail[dot]com */ public class WindowsCentralProcessor extends AbstractCentralProcessor { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(WindowsCentralProcessor.class); // Save Windows version info for 32 bit/64 bit branch later private static final byte majorVersion = Kernel32.INSTANCE.GetVersion().byteValue(); /** * Create a Processor */ public WindowsCentralProcessor() { super(); // Initialize class variables initVars(); // Initialize tick arrays initTicks(); LOG.debug("Initialized Processor"); } /** * Initializes Class variables */ private void initVars() { final String cpuRegistryRoot = "HARDWARE\\DESCRIPTION\\System\\CentralProcessor"; String[] processorIds = Advapi32Util.registryGetKeys(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryRoot); if (processorIds.length > 0) { String cpuRegistryPath = cpuRegistryRoot + "\\" + processorIds[0]; setVendor(Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryPath, "VendorIdentifier")); setName(Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryPath, "ProcessorNameString")); setIdentifier( Advapi32Util.registryGetStringValue(WinReg.HKEY_LOCAL_MACHINE, cpuRegistryPath, "Identifier")); } SYSTEM_INFO sysinfo = new SYSTEM_INFO(); Kernel32.INSTANCE.GetNativeSystemInfo(sysinfo); if (sysinfo.processorArchitecture.pi.wProcessorArchitecture.intValue() == 9 // PROCESSOR_ARCHITECTURE_AMD64 || sysinfo.processorArchitecture.pi.wProcessorArchitecture.intValue() == 6) { // PROCESSOR_ARCHITECTURE_IA64 setCpu64(true); } else if (sysinfo.processorArchitecture.pi.wProcessorArchitecture.intValue() == 0) { // PROCESSOR_ARCHITECTURE_INTEL setCpu64(false); } setProcessorID(WmiUtil.selectStringFrom(null, "Win32_Processor", "ProcessorID", null)); } /** * Updates logical and physical processor counts from /proc/cpuinfo */ @Override protected void calculateProcessorCounts() { // Get number of logical processors SYSTEM_INFO sysinfo = new SYSTEM_INFO(); Kernel32.INSTANCE.GetSystemInfo(sysinfo); this.logicalProcessorCount = sysinfo.dwNumberOfProcessors.intValue(); // Get number of physical processors WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] processors = Kernel32Util.getLogicalProcessorInformation(); for (SYSTEM_LOGICAL_PROCESSOR_INFORMATION proc : processors) { if (proc.relationship == WinNT.LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore) { this.physicalProcessorCount++; } } } /** * {@inheritDoc} */ @Override public long[] getSystemCpuLoadTicks() { long[] ticks = new long[TickType.values().length]; WinBase.FILETIME lpIdleTime = new WinBase.FILETIME(); WinBase.FILETIME lpKernelTime = new WinBase.FILETIME(); WinBase.FILETIME lpUserTime = new WinBase.FILETIME(); if (!Kernel32.INSTANCE.GetSystemTimes(lpIdleTime, lpKernelTime, lpUserTime)) { LOG.error("Failed to update system idle/kernel/user times. Error code: " + Native.getLastError()); return ticks; } // IOwait: // Windows does not measure IOWait. // IRQ: // Percent time raw value is cumulative 100NS-ticks // Divide by 10000 to get milliseconds Map<String, List<String>> irq = WmiUtil.selectStringsFrom(null, "Win32_PerfRawData_Counters_ProcessorInformation", "PercentInterruptTime,PercentDPCTime", "WHERE Name=\"_Total\""); if (!irq.get("PercentInterruptTime").isEmpty()) { ticks[TickType.IRQ.getIndex()] = ParseUtil.parseLongOrDefault(irq.get("PercentInterruptTime").get(0), 0L) / 10000L; ticks[TickType.SOFTIRQ.getIndex()] = ParseUtil.parseLongOrDefault(irq.get("PercentDPCTime").get(0), 0L) / 10000L; } // Units are in 100-ns, divide by 10000 for ms ticks[TickType.IDLE.getIndex()] = lpIdleTime.toDWordLong().longValue() / 10000L; ticks[TickType.SYSTEM.getIndex()] = lpKernelTime.toDWordLong().longValue() / 10000L - ticks[TickType.IDLE.getIndex()]; ticks[TickType.USER.getIndex()] = lpUserTime.toDWordLong().longValue() / 10000L; // Additional decrement to avoid double counting in the total array ticks[TickType.SYSTEM.getIndex()] -= ticks[TickType.IRQ.getIndex()] + ticks[TickType.SOFTIRQ.getIndex()]; return ticks; } /** * {@inheritDoc} */ @Override public double[] getSystemLoadAverage(int nelem) { if (nelem < 1 || nelem > 3) { throw new IllegalArgumentException("Must include from one to three elements."); } double[] average = new double[nelem]; // TODO: If Windows ever actually implements a laod average for 1/5/15, // return it for (int i = 0; i < average.length; i++) { average[i] = -1; } return average; } /** * {@inheritDoc} */ @Override public long[][] getProcessorCpuLoadTicks() { long[][] ticks = new long[this.logicalProcessorCount][TickType.values().length]; // Percent time raw value is cumulative 100NS-ticks // Divide by 10000 to get milliseconds Map<String, List<String>> wmiTicks = WmiUtil.selectStringsFrom(null, "Win32_PerfRawData_Counters_ProcessorInformation", "Name,PercentIdleTime,PercentPrivilegedTime,PercentUserTime,PercentInterruptTime,PercentDPCTime", "WHERE NOT Name LIKE \"%_Total\""); for (int index = 0; index < wmiTicks.get("Name").size(); index++) { // It would be too easy if the WMI order matched logical processors // but alas, it goes "0,3"; "0,2"; "0,1"; "0,0". So let's do it // right and actually string match the name. The first 0 will be // there unless we're dealing with NUMA nodes for (int cpu = 0; cpu < this.logicalProcessorCount; cpu++) { String name = "0," + cpu; if (wmiTicks.get("Name").get(index).equals(name)) { // Skipping nice and IOWait, they'll stay 0 ticks[cpu][TickType.USER.getIndex()] = ParseUtil .parseLongOrDefault(wmiTicks.get("PercentUserTime").get(index), 0L) / 10000L; ticks[cpu][TickType.SYSTEM.getIndex()] = ParseUtil .parseLongOrDefault(wmiTicks.get("PercentPrivilegedTime").get(index), 0L) / 10000L; ticks[cpu][TickType.IDLE.getIndex()] = ParseUtil .parseLongOrDefault(wmiTicks.get("PercentIdleTime").get(index), 0L) / 10000L; ticks[cpu][TickType.IRQ.getIndex()] = ParseUtil .parseLongOrDefault(wmiTicks.get("PercentInterruptTime").get(index), 0L) / 10000L; ticks[cpu][TickType.SOFTIRQ.getIndex()] = ParseUtil .parseLongOrDefault(wmiTicks.get("PercentDPCTime").get(index), 0L) / 10000L; // Additional decrement to avoid double counting in the // total array ticks[cpu][TickType.SYSTEM.getIndex()] -= ticks[cpu][TickType.IRQ.getIndex()] + ticks[cpu][TickType.SOFTIRQ.getIndex()]; break; } } } return ticks; } /** * {@inheritDoc} */ @Override public long getSystemUptime() { // GetTickCount64 requires Vista (6.0) or later if (majorVersion >= 6) { return Kernel32.INSTANCE.GetTickCount64() / 1000L; } else { // 32 bit rolls over at ~ 49 days return Kernel32.INSTANCE.GetTickCount() / 1000L; } } /** * {@inheritDoc} */ @Override @Deprecated public String getSystemSerialNumber() { return new WindowsComputerSystem().getSerialNumber(); } }