Java (Windows) - By process id, get memory usage, disk usage, network usage
Asked Answered
A

2

5

I've been investigating the best approach to achieve the following data for a specific process:

  1. CPU usage
  2. Memory usage
  3. Disk usage
  4. Network usage

I decided to go with OSHI (Operating system & hardware information) API. Unfortunate for me , this API isn't giving me the desired info out of the box, it requires some basic knowledge of how to calculate , for example the cpu usage per process.

My Question is: How can I get the memory, disk, network usage by process id ?

using the following example of cpu usage data per prcoess

For example:

To get the actual CPU usage of a claculator.exe running process:

import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.software.os.OSProcess;
import oshi.software.os.OperatingSystem;

public class processCPUusage {
    public static void main(String[] args) throws InterruptedException {
        OSProcess process;
        long currentTime,previousTime = 0,timeDifference;
        double cpu;
        int pid = 7132;
        SystemInfo si = new SystemInfo();
        OperatingSystem os = si.getOperatingSystem();
        CentralProcessor processor = si.getHardware().getProcessor();
        int cpuNumber = processor.getLogicalProcessorCount();
        boolean processExists = true;
        while (processExists) {
            process = os.getProcess(pid); // calculator.exe process id
            if (process != null) {
                // CPU
                currentTime = process.getKernelTime() + process.getUserTime();

                if (previousTime != -1) {
                    // If we have both a previous and a current time
                    // we can calculate the CPU usage
                    timeDifference = currentTime - previousTime;
                    cpu = (100d * (timeDifference / ((double) 1000))) / cpuNumber;
                    System.out.println(cpu);
                }     

                previousTime = currentTime;

                Thread.sleep(1000);
            } else {
                processExists = false;
            }
        }
    }
}

The framework I'm using https://github.com/oshi/oshi/tree/master/src/site/markdown demonstrates the desired functionality but lacks proper examples

  • Language: Java 8
  • Build tool: Maven 2
  • OS: Windows 10*

OSHI library + slf4j

    <dependency>
        <groupId>com.github.dblock</groupId>
        <artifactId>oshi-core</artifactId>
        <version>3.4.0</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.5</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.5</version>
    </dependency>
Airspace answered 10/6, 2017 at 15:5 Comment(0)
K
4

The original answer in 2017 below is now out of date. The OSProcess class now has many more methods that mostly answer the original request.

The answer by Shikari is good for manual calculations. I'll also note the presence of a method getProcessCpuLoadBetweenTicks() on the OSProcess object starting in version 5.x that will do the CPU calculation for you.

Previous answer below:


I am the one who implemented the OSProcess class in OSHI that you are referencing, and have been communicating with you in an Issue on that project.

While OSHI does not currently provide all the functionality in the OSProcess interface, it does provide you access methods to the WMI classes which will provide you all the information you seek. If you take a look at the WindowsOperatingSystem class which implements the getProcess() method you're using, you can copy/modify the code using WMIUtil to directly fetch the bits of information that you need.

OSHI currently fetches from the Win32_Process WMI class but as I've mentioned on the issue, it might be better to get information instead from Win32_PerfRawData_PerfProc_Process (which provides the raw data you can use for direct calculations) or Win32_PerfFormattedData_PerfProc_Process. In these classes you can find:

CPU usage

  • ElapsedTime
  • PercentPrivilegedTime
  • PercentProcessorTime
  • PercentUserTime

(Note while the name says "Percent" the raw data actually includes incrementing "ticks")

Memory usage

  • VirtualBytes
  • WorkingSet

Disk usage, Network usage

  • IOReadBytesPerSec;
  • IOWriteBytesPerSec;

In these classes, both Disk and Network are combined in the totals. (Again, for the "raw data" ignore the "per sec" part, it will give increasing total amounts of data).

I do not think Windows keeps track of the difference in Disk vs. Network IO on a per-process basis.

Steps you should take:

  1. Define a comma-separated string with the WMI field names you want

  2. Define a ValueType array with types matching the field names, in the same order

  3. Execute Map<String, List<Object>> procs = WmiUtil.selectObjectsFrom(null, "Win32_PerfRawData_PerfProc_Process", processProperties, String.format("WHERE IdProcess=%d", pid), processPropertyTypes);

  4. Fetch each value you want using procs.get("FieldNameHere").get(0)

Kandrakandy answered 11/6, 2017 at 17:59 Comment(0)
H
3

Main Method

public static void main(String[] args) {
            int pid=8924;
            for (int i = 0; i < 10; i++) {
                diskUtilizationPerProcess(pid);
                memoryUtilizationPerProcess(pid);
                cpuUtilizationPerProcess(pid);
                Util.sleep(5000);
            }
        }

Disk/IO :

public static  void diskUtilizationPerProcess(int pid) {
        /**
         * ByteRead : Returns the number of bytes the process has read from disk.
         * ByteWritten : Returns the number of bytes the process has written to disk.
         */
        OSProcess process;
        SystemInfo si = new SystemInfo();
        OperatingSystem os = si.getOperatingSystem();
        process = os.getProcess(pid);
        System.out.println("\nDisk I/O Usage :");
        System.out.println("I/O Reads: "+process.getBytesRead());
        System.out.println("I/O Writes: "+process.getBytesWritten());
    }

Cpu Usage :

public static void cpuUtilizationPerProcess(int processId) {
        /**
         * User Time : Returns the number of milliseconds the process has executed in user mode.
         * Kernel Time : Returns the number of milliseconds the process has executed in kernel/system mode.
         */
        SystemInfo systemInfo = new SystemInfo();
        CentralProcessor processor = systemInfo.getHardware().getProcessor();
        int cpuNumber = processor.getLogicalProcessorCount();
        //int processId = systemInfo.getOperatingSystem().getProcessId();
        OSProcess process = systemInfo.getOperatingSystem().getProcess(processId);
        long currentTime = process.getKernelTime() + process.getUserTime();
        long timeDifference = currentTime - previousTime;
        double processCpu = (100 * (timeDifference / 5000d)) / cpuNumber;
        previousTime = currentTime;
        System.out.println("\nCPU Usage :");
        System.out.println("CPU : "+(int)processCpu+"%");
    }

Memory Usage

public static void memoryUtilizationPerProcess(int pid) {
        /**
         * Resident Size : how much memory is allocated to that process and is in RAM
         */
        OSProcess process;
        SystemInfo si = new SystemInfo();
        OperatingSystem os = si.getOperatingSystem();
        process = os.getProcess(pid);
        System.out.println("\nMemory Usage :");
        System.out.println("Resident Size: "+process.getResidentSetSize());
    }
Hotchkiss answered 18/9, 2020 at 19:17 Comment(1)
Process id is passed in main method. U can check your process id from your task manager. I have used OSHI API to calculate OS Windows Info.Hotchkiss

© 2022 - 2024 — McMap. All rights reserved.