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

oshi.hardware.platform.unix.openbsd.OpenBsdCentralProcessor Maven / Gradle / Ivy

The newest version!
/**
 * MIT License
 *
 * Copyright (c) 2010 - 2021 The OSHI Project Contributors: https://github.com/oshi/oshi/graphs/contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package oshi.hardware.platform.unix.openbsd;

import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.CP_IDLE;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.CP_INTR;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.CP_NICE;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.CP_SYS;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.CP_USER;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.CTL_HW;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.CTL_KERN;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.HW_CPUSPEED;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.HW_MACHINE;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.HW_MODEL;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.KERN_CPTIME;
import static oshi.jna.platform.unix.openbsd.OpenBsdLibc.KERN_CPTIME2;
import static oshi.util.Memoizer.defaultExpiration;
import static oshi.util.Memoizer.memoize;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sun.jna.Memory; // NOSONAR squid:S1191
import com.sun.jna.Native;

import oshi.annotation.concurrent.ThreadSafe;
import oshi.hardware.common.AbstractCentralProcessor;
import oshi.jna.platform.unix.openbsd.OpenBsdLibc;
import oshi.util.ExecutingCommand;
import oshi.util.ParseUtil;
import oshi.util.platform.unix.openbsd.OpenBsdSysctlUtil;
import oshi.util.tuples.Pair;
import oshi.util.tuples.Triplet;

/**
 * OpenBSD Central Processor implementation
 */
@ThreadSafe
public class OpenBsdCentralProcessor extends AbstractCentralProcessor {
    private final Supplier> vmStats = memoize(OpenBsdCentralProcessor::queryVmStats,
            defaultExpiration());
    private static final Pattern DMESG_CPU = Pattern.compile("cpu(\\d+): smt (\\d+), core (\\d+), package (\\d+)");

    @Override
    protected ProcessorIdentifier queryProcessorId() {
        String cpuVendor = OpenBsdSysctlUtil.sysctl("machdep.cpuvendor", "");
        int[] mib = new int[2];
        mib[0] = CTL_HW;
        mib[1] = HW_MODEL;
        String cpuName = OpenBsdSysctlUtil.sysctl(mib, "");
        // CPUID: first 32 bits is cpufeature, last 32 bits is cpuid
        int cpuid = ParseUtil.hexStringToInt(OpenBsdSysctlUtil.sysctl("machdep.cpuid", ""), 0);
        int cpufeature = ParseUtil.hexStringToInt(OpenBsdSysctlUtil.sysctl("machdep.cpufeature", ""), 0);
        Triplet cpu = cpuidToFamilyModelStepping(cpuid);
        String cpuFamily = cpu.getA().toString();
        String cpuModel = cpu.getB().toString();
        String cpuStepping = cpu.getC().toString();
        long cpuFreq = ParseUtil.parseHertz(cpuName);
        if (cpuFreq < 0) {
            cpuFreq = queryMaxFreq();
        }
        mib[1] = HW_MACHINE;
        String machine = OpenBsdSysctlUtil.sysctl(mib, "");
        boolean cpu64bit = machine != null && machine.contains("64")
                || ExecutingCommand.getFirstAnswer("uname -m").trim().contains("64");
        String processorID = String.format("%08x%08x", cpufeature, cpuid);

        return new ProcessorIdentifier(cpuVendor, cpuName, cpuFamily, cpuModel, cpuStepping, processorID, cpu64bit,
                cpuFreq);
    }

    private static Triplet cpuidToFamilyModelStepping(int cpuid) {
        // family is bits 27:20 | 11:8
        int family = cpuid >> 16 & 0xff0 | cpuid >> 8 & 0xf;
        // model is bits 19:16 | 7:4
        int model = cpuid >> 12 & 0xf0 | cpuid >> 4 & 0xf;
        // stepping is bits 3:0
        int stepping = cpuid & 0xf;
        return new Triplet<>(family, model, stepping);
    }

    @Override
    protected long queryMaxFreq() {
        return queryCurrentFreq()[0];
    }

    @Override
    protected long[] queryCurrentFreq() {
        long[] freq = new long[1];
        int[] mib = new int[2];
        mib[0] = CTL_HW;
        mib[1] = HW_CPUSPEED;
        freq[0] = OpenBsdSysctlUtil.sysctl(mib, 0L) * 1_000_000L;
        return freq;
    }

    @Override
    protected List initProcessorCounts() {
        // Iterate dmesg, look for lines:
        // cpu0: smt 0, core 0, package 0
        // cpu1: smt 0, core 1, package 0
        Map coreMap = new HashMap<>();
        Map packageMap = new HashMap<>();
        for (String line : ExecutingCommand.runNative("dmesg")) {
            Matcher m = DMESG_CPU.matcher(line);
            if (m.matches()) {
                int cpu = ParseUtil.parseIntOrDefault(m.group(1), 0);
                coreMap.put(cpu, ParseUtil.parseIntOrDefault(m.group(3), 0));
                packageMap.put(cpu, ParseUtil.parseIntOrDefault(m.group(4), 0));
            }
        }
        // native call seems to fail here, use fallback
        int logicalProcessorCount = OpenBsdSysctlUtil.sysctl("hw.ncpuonline", 1);
        // If we found more procs in dmesg, update
        if (logicalProcessorCount < coreMap.keySet().size()) {
            logicalProcessorCount = coreMap.keySet().size();
        }
        List logProcs = new ArrayList<>(logicalProcessorCount);
        for (int i = 0; i < logicalProcessorCount; i++) {
            logProcs.add(new LogicalProcessor(i, coreMap.getOrDefault(i, 0), packageMap.getOrDefault(i, 0)));
        }
        return logProcs;
    }

    /**
     * Get number of context switches
     *
     * @return The context switches
     */
    @Override
    protected long queryContextSwitches() {
        return vmStats.get().getA();
    }

    /**
     * Get number of interrupts
     *
     * @return The interrupts
     */
    @Override
    protected long queryInterrupts() {
        return vmStats.get().getB();
    }

    private static Pair queryVmStats() {
        long contextSwitches = 0L;
        long interrupts = 0L;
        List vmstat = ExecutingCommand.runNative("vmstat -s");
        for (String line : vmstat) {
            if (line.endsWith("cpu context switches")) {
                contextSwitches = ParseUtil.getFirstIntValue(line);
            } else if (line.endsWith("interrupts")) {
                interrupts = ParseUtil.getFirstIntValue(line);
            }
        }
        return new Pair<>(contextSwitches, interrupts);
    }

    /**
     * Get the system CPU load ticks
     *
     * @return The system CPU load ticks
     */
    @Override
    protected long[] querySystemCpuLoadTicks() {
        long[] ticks = new long[TickType.values().length];
        int[] mib = new int[2];
        mib[0] = CTL_KERN;
        mib[1] = KERN_CPTIME;
        Memory m = OpenBsdSysctlUtil.sysctl(mib);
        // array of 5 or 6 native longs
        long[] cpuTicks = cpTimeToTicks(m, false);
        if (cpuTicks.length >= 5) {
            ticks[TickType.USER.getIndex()] = cpuTicks[CP_USER];
            ticks[TickType.NICE.getIndex()] = cpuTicks[CP_NICE];
            ticks[TickType.SYSTEM.getIndex()] = cpuTicks[CP_SYS];
            int offset = cpuTicks.length > 5 ? 1 : 0;
            ticks[TickType.IRQ.getIndex()] = cpuTicks[CP_INTR + offset];
            ticks[TickType.IDLE.getIndex()] = cpuTicks[CP_IDLE + offset];
        }
        return ticks;
    }

    /**
     * Get the processor CPU load ticks
     *
     * @return The processor CPU load ticks
     */
    @Override
    protected long[][] queryProcessorCpuLoadTicks() {
        long[][] ticks = new long[getLogicalProcessorCount()][TickType.values().length];
        int[] mib = new int[3];
        mib[0] = CTL_KERN;
        mib[1] = KERN_CPTIME2;
        for (int cpu = 0; cpu < getLogicalProcessorCount(); cpu++) {
            mib[2] = cpu;
            Memory m = OpenBsdSysctlUtil.sysctl(mib);
            // array of 5 or 6 longs
            long[] cpuTicks = cpTimeToTicks(m, true);
            if (cpuTicks.length >= 5) {
                ticks[cpu][TickType.USER.getIndex()] = cpuTicks[CP_USER];
                ticks[cpu][TickType.NICE.getIndex()] = cpuTicks[CP_NICE];
                ticks[cpu][TickType.SYSTEM.getIndex()] = cpuTicks[CP_SYS];
                int offset = cpuTicks.length > 5 ? 1 : 0;
                ticks[cpu][TickType.IRQ.getIndex()] = cpuTicks[CP_INTR + offset];
                ticks[cpu][TickType.IDLE.getIndex()] = cpuTicks[CP_IDLE + offset];
            }
        }
        return ticks;
    }

    /**
     * Parse memory buffer returned from sysctl kern.cptime or kern.cptime2 to an
     * array of 5 or 6 longs depending on version.
     * 

* Versions 6.4 and later have a 6-element array while earlier versions have * only 5 elements. Additionally kern.cptime uses a native-sized long (32- or * 64-bit) value while kern.cptime2 is always a 64-bit value. * * @param m * A buffer containing the array. * @param force64bit * True if the buffer is filled with 64-bit longs, false if native * long sized values * @return The array */ private static long[] cpTimeToTicks(Memory m, boolean force64bit) { long longBytes = force64bit ? 8L : Native.LONG_SIZE; int arraySize = m == null ? 0 : (int) (m.size() / longBytes); if (force64bit && m != null) { return m.getLongArray(0, arraySize); } long[] ticks = new long[arraySize]; for (int i = 0; i < arraySize; i++) { ticks[i] = m.getNativeLong(i * longBytes).longValue(); } return ticks; } /** * 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. The way in which the load average is calculated is * operating system specific but is typically a damped time-dependent average. * If the load average is not available, a negative value is returned. This * method is designed to provide a hint about the system load and may be queried * frequently. *

* The load average may be unavailable on some platforms (e.g., Windows) where * it is expensive to implement this method. * * @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. */ @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]; int retval = OpenBsdLibc.INSTANCE.getloadavg(average, nelem); if (retval < nelem) { Arrays.fill(average, -1d); } return average; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy