Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Profiling CPU usage from within a Java application

Roll your own CPU usage monitor using simple JNI

  • Print
  • Feedback

Page 2 of 2

Getting back to Java, loading the native library (silib.dll on Win32) is best accomplished via the static initializer in the SystemInformation class:

    private static final String SILIB = "silib";
    
    static
    {
        try
        {
            System.loadLibrary (SILIB);
        }
        catch (UnsatisfiedLinkError e)
        {
            System.out.println ("native lib '" + SILIB + "' not found in 'java.library.path': "
            + System.getProperty ("java.library.path"));
            
            throw e; // re-throw
        }
    }


Note that getProcessCPUTime() returns CPU time used since the creation of the JVM process. By itself, this data is not particularly useful for profiling. I need more utility Java methods to record data snapshots at various times and report CPU usage between any two time points:

    public static final class CPUUsageSnapshot
    {
        private CPUUsageSnapshot (long time, long CPUTime)
        {
            m_time = time;
            m_CPUTime = CPUTime;
        }
        
        public final long m_time, m_CPUTime;
        
    } // end of nested class
    
    public static CPUUsageSnapshot makeCPUUsageSnapshot ()
    {
        return new CPUUsageSnapshot (System.currentTimeMillis (), getProcessCPUTime ());
    }
    
    public static double getProcessCPUUsage (CPUUsageSnapshot start, CPUUsageSnapshot end)
    {
        return ((double)(end.m_CPUTime - start.m_CPUTime)) / (end.m_time - start.m_time);
    }


The "CPU monitor API" is nearly ready for use! As a final touch, I create a singleton thread class, CPUUsageThread, which automatically takes data snapshots at regular intervals (0.5 seconds by default) and reports them to a set of CPU usage event listeners (the familiar Observer pattern). The CPUmon class is a demo listener that simply prints the CPU usage to System.out:

    public static void main (String [] args) throws Exception
    {
        if (args.length == 0)
            throw new IllegalArgumentException ("usage: CPUmon <app_main_class> <app_main_args...>");
        
        CPUUsageThread monitor = CPUUsageThread.getCPUThreadUsageThread ();
        CPUmon _this = new CPUmon ();
        
        Class app = Class.forName (args [0]);
        Method appmain = app.getMethod ("main", new Class [] {String[].class});
        String [] appargs = new String [args.length - 1];
        System.arraycopy (args, 1, appargs, 0, appargs.length);
        
        monitor.addUsageEventListener (_this);
        monitor.start ();
        appmain.invoke (null, new Object [] {appargs});
    }


Additionally, CPUmon.main() "wraps" another Java main class with the sole purpose of starting CPUUsageThread before launching the original application.

As a demonstration, I ran CPUmon with the SwingSet2 Swing demo from JDK 1.3.1 (don't forget to install silib.dll into a location covered by either the PATH OS environment variable or the java.library.path Java property):

>java -Djava.library.path=. -cp silib.jar;(my JDK install dir)\demo\jfc\SwingSet2\SwingSet2.jar CPUmon SwingSet2
[PID: 339] CPU usage: 46.8%
[PID: 339] CPU usage: 51.4%
[PID: 339] CPU usage: 54.8%
(while loading, the demo uses nearly 100% of one of the two CPUs on my machine)
...
[PID: 339] CPU usage: 46.8%
[PID: 339] CPU usage: 0%
[PID: 339] CPU usage: 0%
(the demo finished loading all of its panels and is mostly idle)
...
[PID: 339] CPU usage: 100%
[PID: 339] CPU usage: 98.4%
[PID: 339] CPU usage: 97%
(I switched to the ColorChooserDemo panel which ran a CPU-intensive
animation that used both of my CPUs)
...
[PID: 339] CPU usage: 81.4%
[PID: 339] CPU usage: 50%
[PID: 339] CPU usage: 50%
(I used Windows NT Task Manager to adjust the CPU affinity for the
"java" process to use a single CPU)
...


Of course, I can watch the same usage numbers via the task manager, but the point here is that I now have a programmatic way to record the same data. It will come in handy for long-running tests and server application diagnostics. The complete library (available in Resources) adds a few other useful native methods, including one for getting the process PID (for integration with external tools).

About the author

Vladimir Roubtsov has programmed in a variety of languages for more than 12 years, including Java since 1995. Currently, he develops enterprise software as a senior developer for Trilogy in Austin, Texas. When coding for fun, Vladimir develops software tools based on Java byte code or source code instrumentation.
  • Print
  • Feedback

Resources