程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> 在Java應用程序中使用JNI來監視CPU詳解

在Java應用程序中使用JNI來監視CPU詳解

編輯:JAVA編程入門知識

  怎樣在Java中得到CPU的使用情況呢?這兒同時有一個好消息和一個壞消息。

  壞消息是不能使用純Java的方法得到CPU的使用。沒有這方面的直接的API。一個建議的替代方法是通過Runtime.exec()確定JVM的進程ID(PID),調用外部的、平台相關的命令,例如ps,然後在運行結果中解析出感愛好的PID。但是,這種方法並不理想。

  好消息是,可以采用一個更為可靠的方案:跳出Java,寫幾行C代碼,然後通過JNI進行整合。下面我將向你展示編寫一個Win32平台的簡單的JNI庫是多麼簡單。

  一般來說,JNI有點復雜。但是,假如你僅僅單向調用--從Java調用本地代碼,並且僅使用基本型進行通訊--事情還是很簡單的。有許多JNI方面的學習資料,所以這兒就不介紹JNI的基礎了。僅介紹實現步驟。

  一、在Java中聲明JNI方法

  開始,創建一個聲明了本地方法的類com.vladium.utils.SystemInformation,該方法返回當前進程已使用的CPU的毫秒數。

  public staticnative long getProcessCPUTime();

  使用JDK內置的javah工具產生將來本地代碼實現使用的C頭。

  JNIEXPORT jlong JNICALL

  Java_com_vladium_utils_SystemInformation_getProcessCPUTime (JNIEnv * env, jclass cls)

  二、本地方法實現

  在大多數的Win32平台上,該方法可以使用GetProcessTimes()系統調用實現,差不多僅需要3行代碼就可以了:

  

JNIEXPORT jlong JNICALL 
Java_com_vladium_utils_SystemInformation_getProcessCPUTime(JNIEnv * env, jclass cls) 
{ 
 FILETIME creationTime, exitTime, kernelTime, userTime; 
     
 GetProcessTimes (s_currentProcess, & creationTime, & exitTime, & kernelTime, 
& userTime); 
  
 return (jlong) ((fileTimeToInt64 (& kernelTime) + fileTimeToInt64 (& userTime)) / 
(s_numberOfProcessors * 10000)); 
}

  該方法首先累加用於執行當前進程的核心和用戶代碼耗費的時間,除以處理器的數目,並把結果轉換到毫秒。fileTimeToInt64()是一個輔助函數,用於把FILETIME結構的數據轉換為64位的整數。s_currentProcess 和 s_numberOfProcessors是全局變量,當JVM裝載本地庫時即初始化。

  

static HANDLE s_currentProcess; 
static int s_numberOfProcessors; 
  
JNIEXPORT jint JNICALL 
JNI_OnLoad (JavaVM * vm, void * reserved) 
{ 
    SYSTEM_INFO systemInfo; 
         
    s_currentProcess = GetCurrentProcess (); 
  
    GetSystemInfo (& systemInfo); 
    s_numberOfProcessors = systemInfo.dwNumberOfProcessors; 
  
    return JNI_VERSION_1_2; 
}

  注重,假如你在UNIX平台上實現getProcessCPUTime(),你應該以getrusage系統調用開始。

  三、調用本地方法

  回到Java中,在SystemInformation類中,裝載本地庫(silib.dll on Win32)最好通過靜態初始化代碼塊完成。

  

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 
        } 
    }

  注重,getProcessCPUTime()返回自JVM進程創建以來使用的CPU時間。就這個數據本身而言,對於這兒並沒有太多的用處。還需要更有用的Java方法來記錄不同的時刻的數據快照(data snapshots),並報告任何兩個時間點之間CPU的使用。

  

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); 
   }

  
   四、一個簡單的CPU監視程序

  “CPU監視API”基本就完成了!最後,創建了一個singleton的線程類CPUUsageThread,它自動地每過一個時間間隔(默認是0.5秒)就拍下一個數據快照,並報告給所有的CPU使用事件的監聽者(Observer模式)。

  

public void run () 
    { 
        while (! isInterrupted ()) 
        { 
           final SystemInformation.CPUUsageSnapshot snapshot = 
SystemInformation.makeCPUUsageSnapshot (); 
            notifyListeners (snapshot); 
             
            try 
            { 
                sleep (sleepTime); 
            } 
            catch (InterruptedException e) 
            { 
                return; 
            } 
        } 
    }

  CPUmon類是一個示例的監聽器,僅簡單地把CPU的使用情況打印輸出到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}); 
    }

  另外,為了能夠在啟動要監視的應用程序之前開始CPUUsageThread,CPUmon.main()包裝了另一個Java主類。

  作為演示,運行CPUmon和JDK1.3.1的SwingSet2示例程序(不要忘了把silib.dll安裝到OS的PATH環境變量或者java.library.path系統屬性所覆蓋的路徑下):

  >java -Djava.library.path=. -cp silib.jar;(my JDK install dir)demojfcSwingSet2SwingSet2.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)

  ...

  當然,也可以通過任務治理器查看到CPU使用信息,這兒的要點是現在我們可以以編程方式記錄該信息。對於長時間運行測試和服務器應用診斷程序,會派上用場。


 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved