All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
oshi.driver.windows.registry.ThreadPerformanceData Maven / Gradle / Ivy
/*
* Copyright 2020-2023 The OSHI Project Contributors
* SPDX-License-Identifier: MIT
*/
package oshi.driver.windows.registry;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sun.jna.platform.win32.WinBase.FILETIME;
import oshi.annotation.concurrent.Immutable;
import oshi.annotation.concurrent.ThreadSafe;
import oshi.driver.windows.perfmon.PerfmonDisabled;
import oshi.driver.windows.perfmon.ThreadInformation;
import oshi.driver.windows.perfmon.ThreadInformation.ThreadPerformanceProperty;
import oshi.util.Util;
import oshi.util.tuples.Pair;
import oshi.util.tuples.Triplet;
/**
* Utility to read thread data from HKEY_PERFORMANCE_DATA information with backup from Performance Counters or WMI
*/
@ThreadSafe
public final class ThreadPerformanceData {
private static final String THREAD = "Thread";
private ThreadPerformanceData() {
}
/**
* Query the registry for thread performance counters
*
* @param pids An optional collection of thread IDs to filter the list to. May be null for no filtering.
* @return A map with Thread ID as the key and a {@link PerfCounterBlock} object populated with performance counter
* information if successful, or null otherwise.
*/
public static Map buildThreadMapFromRegistry(Collection pids) {
// Grab the data from the registry.
Triplet>, Long, Long> threadData = HkeyPerformanceDataUtil
.readPerfDataFromRegistry(THREAD, ThreadPerformanceProperty.class);
if (threadData == null) {
return null;
}
List> threadInstanceMaps = threadData.getA();
long perfTime100nSec = threadData.getB(); // 1601
long now = threadData.getC(); // 1970 epoch
// Create a map and fill it
Map threadMap = new HashMap<>();
// Iterate instances.
for (Map threadInstanceMap : threadInstanceMaps) {
int pid = ((Integer) threadInstanceMap.get(ThreadPerformanceProperty.IDPROCESS)).intValue();
if ((pids == null || pids.contains(pid)) && pid > 0) {
int tid = ((Integer) threadInstanceMap.get(ThreadPerformanceProperty.IDTHREAD)).intValue();
String name = (String) threadInstanceMap.get(ThreadPerformanceProperty.NAME);
long upTime = (perfTime100nSec - (Long) threadInstanceMap.get(ThreadPerformanceProperty.ELAPSEDTIME))
/ 10_000L;
if (upTime < 1) {
upTime = 1;
}
long user = ((Long) threadInstanceMap.get(ThreadPerformanceProperty.PERCENTUSERTIME)).longValue()
/ 10_000L;
long kernel = ((Long) threadInstanceMap.get(ThreadPerformanceProperty.PERCENTPRIVILEGEDTIME))
.longValue() / 10_000L;
int priority = ((Integer) threadInstanceMap.get(ThreadPerformanceProperty.PRIORITYCURRENT)).intValue();
int threadState = ((Integer) threadInstanceMap.get(ThreadPerformanceProperty.THREADSTATE)).intValue();
int threadWaitReason = ((Integer) threadInstanceMap.get(ThreadPerformanceProperty.THREADWAITREASON))
.intValue();
// Start address is pointer sized when fetched from registry, so this could be
// either Integer (uint32) or Long depending on OS bitness
Object addr = threadInstanceMap.get(ThreadPerformanceProperty.STARTADDRESS);
long startAddr = addr.getClass().equals(Long.class) ? (Long) addr
: Integer.toUnsignedLong((Integer) addr);
int contextSwitches = ((Integer) threadInstanceMap.get(ThreadPerformanceProperty.CONTEXTSWITCHESPERSEC))
.intValue();
threadMap.put(tid, new PerfCounterBlock(name, tid, pid, now - upTime, user, kernel, priority,
threadState, threadWaitReason, startAddr, contextSwitches));
}
}
return threadMap;
}
/**
* Query PerfMon for thread performance counters
*
* @param pids An optional collection of process IDs to filter the list to. May be null for no filtering.
* @return A map with Thread ID as the key and a {@link PerfCounterBlock} object populated with performance counter
* information.
*/
public static Map buildThreadMapFromPerfCounters(Collection pids) {
return buildThreadMapFromPerfCounters(pids, null, -1);
}
/**
* Query PerfMon for thread performance counters
*
* @param pids An optional collection of process IDs to filter the list to. May be null for no filtering.
* @param procName Limit the matches to processes matching the given name.
* @param threadNum Limit the matches to threads matching the given thread. Use -1 to match all threads.
* @return A map with Thread ID as the key and a {@link PerfCounterBlock} object populated with performance counter
* information.
*/
public static Map buildThreadMapFromPerfCounters(Collection pids,
String procName, int threadNum) {
if (PerfmonDisabled.PERF_PROC_DISABLED) {
return Collections.emptyMap();
}
Map threadMap = new HashMap<>();
Pair, Map>> instanceValues = Util.isBlank(procName)
? ThreadInformation.queryThreadCounters()
: ThreadInformation.queryThreadCounters(procName, threadNum);
long now = System.currentTimeMillis(); // 1970 epoch
List instances = instanceValues.getA();
Map> valueMap = instanceValues.getB();
List tidList = valueMap.get(ThreadPerformanceProperty.IDTHREAD);
List pidList = valueMap.get(ThreadPerformanceProperty.IDPROCESS);
List userList = valueMap.get(ThreadPerformanceProperty.PERCENTUSERTIME); // 100-nsec
List kernelList = valueMap.get(ThreadPerformanceProperty.PERCENTPRIVILEGEDTIME); // 100-nsec
List startTimeList = valueMap.get(ThreadPerformanceProperty.ELAPSEDTIME); // filetime
List priorityList = valueMap.get(ThreadPerformanceProperty.PRIORITYCURRENT);
List stateList = valueMap.get(ThreadPerformanceProperty.THREADSTATE);
List waitReasonList = valueMap.get(ThreadPerformanceProperty.THREADWAITREASON);
List startAddrList = valueMap.get(ThreadPerformanceProperty.STARTADDRESS);
List contextSwitchesList = valueMap.get(ThreadPerformanceProperty.CONTEXTSWITCHESPERSEC);
int nameIndex = 0;
for (int inst = 0; inst < instances.size(); inst++) {
int pid = pidList.get(inst).intValue();
if (pids == null || pids.contains(pid)) {
int tid = tidList.get(inst).intValue();
String name = Integer.toString(nameIndex++);
long startTime = startTimeList.get(inst);
int lowerStartTimeLimit = (int) (startTime >> 32);
int higherStartTimeLimit = (int) (startTime & 0xffffffffL);
startTime = FILETIME.filetimeToDate(lowerStartTimeLimit, higherStartTimeLimit).getTime();
if (startTime > now) {
startTime = now - 1;
}
long user = userList.get(inst) / 10_000L;
long kernel = kernelList.get(inst) / 10_000L;
int priority = priorityList.get(inst).intValue();
int threadState = stateList.get(inst).intValue();
int threadWaitReason = waitReasonList.get(inst).intValue();
long startAddr = startAddrList.get(inst).longValue();
int contextSwitches = contextSwitchesList.get(inst).intValue();
// if creation time value is less than current millis, it's in 1970 epoch,
// otherwise it's 1601 epoch and we must convert
threadMap.put(tid, new PerfCounterBlock(name, tid, pid, startTime, user, kernel, priority, threadState,
threadWaitReason, startAddr, contextSwitches));
}
}
return threadMap;
}
/**
* Class to encapsulate data from the registry performance counter block
*/
@Immutable
public static class PerfCounterBlock {
private final String name;
private final int threadID;
private final int owningProcessID;
private final long startTime;
private final long userTime;
private final long kernelTime;
private final int priority;
private final int threadState;
private final int threadWaitReason;
private final long startAddress;
private final int contextSwitches;
public PerfCounterBlock(String name, int threadID, int owningProcessID, long startTime, long userTime,
long kernelTime, int priority, int threadState, int threadWaitReason, long startAddress,
int contextSwitches) {
this.name = name;
this.threadID = threadID;
this.owningProcessID = owningProcessID;
this.startTime = startTime;
this.userTime = userTime;
this.kernelTime = kernelTime;
this.priority = priority;
this.threadState = threadState;
this.threadWaitReason = threadWaitReason;
this.startAddress = startAddress;
this.contextSwitches = contextSwitches;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the threadID
*/
public int getThreadID() {
return threadID;
}
/**
* @return the owningProcessID
*/
public int getOwningProcessID() {
return owningProcessID;
}
/**
* @return the startTime
*/
public long getStartTime() {
return startTime;
}
/**
* @return the userTime
*/
public long getUserTime() {
return userTime;
}
/**
* @return the kernelTime
*/
public long getKernelTime() {
return kernelTime;
}
/**
* @return the priority
*/
public int getPriority() {
return priority;
}
/**
* @return the threadState
*/
public int getThreadState() {
return threadState;
}
/**
* @return the threadWaitReason
*/
public int getThreadWaitReason() {
return threadWaitReason;
}
/**
* @return the startMemoryAddress
*/
public long getStartAddress() {
return startAddress;
}
/**
* @return the contextSwitches
*/
public int getContextSwitches() {
return contextSwitches;
}
}
}