Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor PerfCounterQuery classes and fix memory leak #1245

Merged
merged 1 commit into from May 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
* [#1237](https://github.com/oshi/oshi/pull/1237): Update Udev to object oriented style - [@dbwiddis](https://github.com/dbwiddis).
* [#1240](https://github.com/oshi/oshi/pull/1240): Add a driver for proc/pid/statm - [@dbwiddis](https://github.com/dbwiddis).
* [#1241](https://github.com/oshi/oshi/pull/1241): Add code-assert - [@dbwiddis](https://github.com/dbwiddis).
* [#1245](https://github.com/oshi/oshi/pull/1245): Refactor PerfCounterQuery classes and fix memory leak - [@dbwiddis](https://github.com/dbwiddis).
* Your contribution here

4.8.0 / 5.1.0 (5/20/2020)
Expand Down
2 changes: 0 additions & 2 deletions FAQ.md
Expand Up @@ -22,8 +22,6 @@ each class. The following classes are not thread-safe:
- `GlobalConfig` does not protect against multiple threads manipulating the configuration programmatically.
However, these methods are intended to be used by a single thread at startup in lieu of reading a configuration file.
OSHI gives no guarantees on re-reading changed configurations.
- `PerfCounterQuery` and `PerfCounterWildcardQuery` objects should only be used within the context of a single
thread. These are only used internally in OSHI in these single-thread contexts and not intended for user use.
- On non-Windows platforms, the `getSessions()` method on the `OperatingSystem` interface uses native code which is not thread safe. While OSHI's methods employ synchronization to coordinate access from its own threads, users are cautioned that other operating system code may access the same underlying data structures and produce unexpected results, particularly on servers with frequent new logins.

Earlier versions do not guarantee thread safety, but as of version 4.6.0, intended use is thread safe.
Expand Down
Expand Up @@ -73,8 +73,6 @@ private MemoryInformation() {
* @return Page swap counters for memory.
*/
public static Map<PageSwapProperty, Long> queryPageSwaps() {
PerfCounterQuery<PageSwapProperty> memoryPerfCounters = new PerfCounterQuery<>(PageSwapProperty.class, MEMORY,
WIN32_PERF_RAW_DATA_PERF_OS_MEMORY);
return memoryPerfCounters.queryValues();
return PerfCounterQuery.queryValues(PageSwapProperty.class, MEMORY, WIN32_PERF_RAW_DATA_PERF_OS_MEMORY);
}
}
Expand Up @@ -72,8 +72,7 @@ private PagingFile() {
* @return Paging file counters for memory.
*/
public static Map<PagingPercentProperty, Long> querySwapUsed() {
PerfCounterQuery<PagingPercentProperty> pagingPerfCounters = new PerfCounterQuery<>(PagingPercentProperty.class,
PAGING_FILE, WIN32_PERF_RAW_DATA_PERF_OS_PAGING_FILE);
return pagingPerfCounters.queryValues();
return PerfCounterQuery.queryValues(PagingPercentProperty.class, PAGING_FILE,
WIN32_PERF_RAW_DATA_PERF_OS_PAGING_FILE);
}
}
Expand Up @@ -76,11 +76,7 @@ private PhysicalDisk() {
* @return Performance Counters for physical disks.
*/
public static Pair<List<String>, Map<PhysicalDiskProperty, List<Long>>> queryDiskCounters() {
PerfCounterWildcardQuery<PhysicalDiskProperty> physicalDiskPerfCounters = new PerfCounterWildcardQuery<>(
PhysicalDiskProperty.class, PHYSICAL_DISK,
return PerfCounterWildcardQuery.queryInstancesAndValues(PhysicalDiskProperty.class, PHYSICAL_DISK,
WIN32_PERF_RAW_DATA_PERF_DISK_PHYSICAL_DISK_WHERE_NOT_NAME_TOTAL);
Map<PhysicalDiskProperty, List<Long>> values = physicalDiskPerfCounters.queryValuesWildcard();
List<String> instances = physicalDiskPerfCounters.getInstancesFromLastQuery();
return new Pair<>(instances, values);
}
}
Expand Up @@ -40,7 +40,6 @@ public final class ProcessInformation {

private static final String WIN32_PROCESS = "Win32_Process";
private static final String PROCESS = "Process";
private static final String PROCESS_INFORMATION = "Process Information";
private static final String WIN32_PROCESS_WHERE_NOT_NAME_LIKE_TOTAL = "Win32_Process WHERE NOT Name LIKE\"%_Total\"";

/**
Expand Down Expand Up @@ -100,22 +99,16 @@ private ProcessInformation() {
* @return Process counters for each process.
*/
public static Pair<List<String>, Map<ProcessPerformanceProperty, List<Long>>> queryProcessCounters() {
PerfCounterWildcardQuery<ProcessPerformanceProperty> processPerformancePerfCounters = new PerfCounterWildcardQuery<>(
ProcessPerformanceProperty.class, PROCESS, WIN32_PROCESS_WHERE_NOT_NAME_LIKE_TOTAL,
PROCESS_INFORMATION);
Map<ProcessPerformanceProperty, List<Long>> values = processPerformancePerfCounters.queryValuesWildcard();
List<String> instances = processPerformancePerfCounters.getInstancesFromLastQuery();
return new Pair<>(instances, values);
return PerfCounterWildcardQuery.queryInstancesAndValues(ProcessPerformanceProperty.class, PROCESS,
WIN32_PROCESS_WHERE_NOT_NAME_LIKE_TOTAL);
}

/**
* Returns handle counters
*
* @return Process handle counters
* @return Process handle counters for each process.
*/
public static Map<HandleCountProperty, List<Long>> queryHandles() {
PerfCounterWildcardQuery<HandleCountProperty> handlePerfCounters = new PerfCounterWildcardQuery<>(
HandleCountProperty.class, PROCESS, WIN32_PROCESS);
return handlePerfCounters.queryValuesWildcard();
public static Pair<List<String>, Map<HandleCountProperty, List<Long>>> queryHandles() {
return PerfCounterWildcardQuery.queryInstancesAndValues(HandleCountProperty.class, PROCESS, WIN32_PROCESS);
}
}
Expand Up @@ -42,10 +42,7 @@
public final class ProcessorInformation {

private static final String PROCESSOR = "Processor";
private static final String INTERRUPT_COUNT = "Interrupt Count";
private static final String PROCESSOR_FREQUENCY = "Processor Frequency";
private static final String PROCESSOR_INFORMATION = "Processor Information";
private static final String PROCESSOR_TICK_COUNT = "Processor Tick Count";

// For Win7+ ... NAME field includes NUMA nodes
private static final String WIN32_PERF_RAW_DATA_COUNTERS_PROCESSOR_INFORMATION_WHERE_NOT_NAME_LIKE_TOTAL = "Win32_PerfRawData_Counters_ProcessorInformation WHERE NOT Name LIKE\"%_Total\"";
Expand Down Expand Up @@ -162,15 +159,10 @@ private ProcessorInformation() {
* @return Performance Counters for processors.
*/
public static Pair<List<String>, Map<ProcessorTickCountProperty, List<Long>>> queryProcessorCounters() {
PerfCounterWildcardQuery<ProcessorTickCountProperty> processorTickPerfCounters = IS_WIN7_OR_GREATER
? new PerfCounterWildcardQuery<>(ProcessorTickCountProperty.class, PROCESSOR_INFORMATION,
WIN32_PERF_RAW_DATA_COUNTERS_PROCESSOR_INFORMATION_WHERE_NOT_NAME_LIKE_TOTAL,
PROCESSOR_TICK_COUNT)
: new PerfCounterWildcardQuery<>(ProcessorTickCountProperty.class, PROCESSOR,
WIN32_PERF_RAW_DATA_PERF_OS_PROCESSOR_WHERE_NOT_NAME_TOTAL, PROCESSOR_TICK_COUNT);
Map<ProcessorTickCountProperty, List<Long>> values = processorTickPerfCounters.queryValuesWildcard();
List<String> instances = processorTickPerfCounters.getInstancesFromLastQuery();
return new Pair<>(instances, values);
return IS_WIN7_OR_GREATER ? PerfCounterWildcardQuery.queryInstancesAndValues(ProcessorTickCountProperty.class,
PROCESSOR_INFORMATION, WIN32_PERF_RAW_DATA_COUNTERS_PROCESSOR_INFORMATION_WHERE_NOT_NAME_LIKE_TOTAL)
: PerfCounterWildcardQuery.queryInstancesAndValues(ProcessorTickCountProperty.class, PROCESSOR,
WIN32_PERF_RAW_DATA_PERF_OS_PROCESSOR_WHERE_NOT_NAME_TOTAL);
}

/**
Expand All @@ -179,10 +171,8 @@ public static Pair<List<String>, Map<ProcessorTickCountProperty, List<Long>>> qu
* @return Performance Counters for the total of all processors.
*/
public static Map<SystemTickCountProperty, Long> querySystemCounters() {
PerfCounterQuery<SystemTickCountProperty> systemTickPerfCounters = new PerfCounterQuery<>(
SystemTickCountProperty.class, PROCESSOR, WIN32_PERF_RAW_DATA_PERF_OS_PROCESSOR_WHERE_NAME_TOTAL,
"System Tick Count");
return systemTickPerfCounters.queryValues();
return PerfCounterQuery.queryValues(SystemTickCountProperty.class, PROCESSOR,
WIN32_PERF_RAW_DATA_PERF_OS_PROCESSOR_WHERE_NAME_TOTAL);
}

/**
Expand All @@ -191,9 +181,8 @@ public static Map<SystemTickCountProperty, Long> querySystemCounters() {
* @return Interrupts counter for the total of all processors.
*/
public static Map<InterruptsProperty, Long> queryInterruptCounters() {
PerfCounterQuery<InterruptsProperty> interruptsPerfCounters = new PerfCounterQuery<>(InterruptsProperty.class,
PROCESSOR, WIN32_PERF_RAW_DATA_PERF_OS_PROCESSOR_WHERE_NAME_TOTAL, INTERRUPT_COUNT);
return interruptsPerfCounters.queryValues();
return PerfCounterQuery.queryValues(InterruptsProperty.class, PROCESSOR,
WIN32_PERF_RAW_DATA_PERF_OS_PROCESSOR_WHERE_NAME_TOTAL);
}

/**
Expand All @@ -202,11 +191,7 @@ public static Map<InterruptsProperty, Long> queryInterruptCounters() {
* @return Processor frequency counter for each processor.
*/
public static Pair<List<String>, Map<ProcessorFrequencyProperty, List<Long>>> queryFrequencyCounters() {
PerfCounterWildcardQuery<ProcessorFrequencyProperty> processorFrequencyCounters = new PerfCounterWildcardQuery<>(
ProcessorFrequencyProperty.class, PROCESSOR_INFORMATION,
WIN32_PERF_RAW_DATA_COUNTERS_PROCESSOR_INFORMATION_WHERE_NOT_NAME_LIKE_TOTAL, PROCESSOR_FREQUENCY);
Map<ProcessorFrequencyProperty, List<Long>> values = processorFrequencyCounters.queryValuesWildcard();
List<String> instances = processorFrequencyCounters.getInstancesFromLastQuery();
return new Pair<>(instances, values);
return PerfCounterWildcardQuery.queryInstancesAndValues(ProcessorFrequencyProperty.class, PROCESSOR_INFORMATION,
WIN32_PERF_RAW_DATA_COUNTERS_PROCESSOR_INFORMATION_WHERE_NOT_NAME_LIKE_TOTAL);
}
}
Expand Up @@ -72,8 +72,6 @@ private SystemInformation() {
* @return Context switches counter for the total of all processors.
*/
public static Map<ContextSwitchProperty, Long> queryContextSwitchCounters() {
PerfCounterQuery<ContextSwitchProperty> contextSwitchPerfCounters = new PerfCounterQuery<>(
ContextSwitchProperty.class, SYSTEM, WIN32_PERF_RAW_DATA_PERF_OS_SYSTEM);
return contextSwitchPerfCounters.queryValues();
return PerfCounterQuery.queryValues(ContextSwitchProperty.class, SYSTEM, WIN32_PERF_RAW_DATA_PERF_OS_SYSTEM);
}
}
Expand Up @@ -117,7 +117,7 @@ private static List<LogicalProcessor> parseTopology() {
String[] topology = BsdSysctlUtil.sysctl("kern.sched.topology_spec", "").split("\\n|\\r");
/*-
* Sample output:

*
<groups>
<group level="1" cache-level="0">
<cpu count="24" mask="ffffff">0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23</cpu>
Expand All @@ -129,7 +129,7 @@ private static List<LogicalProcessor> parseTopology() {
<cpu count="2" mask="3">0, 1</cpu>
<flags><flag name="THREAD">THREAD group</flag><flag name="SMT">SMT group</flag></flags>
</group>

*
* Opens with <groups>
* <group> level 1 identifies all the processors via bitmask, should only be one
* <group> level 2 separates by physical package
Expand Down
Expand Up @@ -297,7 +297,7 @@ private static String getDriveType(String drive) {

@Override
public long getOpenFileDescriptors() {
Map<HandleCountProperty, List<Long>> valueListMap = ProcessInformation.queryHandles();
Map<HandleCountProperty, List<Long>> valueListMap = ProcessInformation.queryHandles().getB();
List<Long> valueList = valueListMap.get(HandleCountProperty.HANDLECOUNT);
long descriptors = 0L;
if (valueList != null) {
Expand Down