JNI实现对CPU使用率的获取!

测量CPU和内存的占用率常常是检查Java应用程序是否达到特定性能的一个重要环节。尽管Java提供了一些重要的方法用于测量其堆栈大小,但是使用标准的API是无法测量本机Java进程的大小和CPU当前的使用率的。这种测量的结果对于开发人员来说非常重要,它会提供应用程序的实时性能和效率信息。不幸的是,这样的信息只能从操作系统直接获取,而这已经超出了Java标准的可移植能力。 

一个主要的解决方案是使用操作系统自带的本机系统调用,将数据通过JNI(Java Native Interface,Java本机接口)传输给Java。与调用各个平台专用的外部命令(比如ps)并分析输出结果不同,这种方案始终是一种很可靠的方式。以前碰到这样的问题时,我尝试过使用Vladimir Roubtsov自己编写的一个很小的库,它只能在Win32系统下测量进程的CPU占用率。但是,这个库的能力十分有限,所以我需要某种方式能够同时在Windows和Solaris平台上测量CPU和内存的占用率。 

我扩展了这个库的能力,在Windows和Solaris 8平台上实现了所有功能。新的库能够测量纯CPU使用时间、CPU使用的百分比、本机剩余内存和已经使用的内存、Java进程的本机内存大小、系统信息(比如操作系统的名字、补丁程序、硬件信息等)。它由三部分实现: Java通用的部分、Windows实现,以及Solaris实现。依靠操作系统的部分用纯C语言实现。所以,我们将创建一个简单的JNI库,用于同C层里的操作系统进行沟通,并把生成的数据提供给Java应用程序。首先,我们要创建一个SystemInformation类(列表A),为测量和记录CPU的使用率和其他与系统相关的信息提供一个简单的API。这个类是抽象的,因为它公开的是一个完全静态的API。 

package com.vladium.utils; 

public abstract class SystemInformation 
{ 
// public: ................................................................ 

/** 
* A simple class to represent data snapshots taken by {@link #makeCPUUsageSnapshot}. 
*/ 
public static final class CPUUsageSnapshot 
{ 
public final long m_time, m_CPUTime; 

// constructor is private to ensure that makeCPUUsageSnapshot() 
// is used as the factory method for this class: 
private CPUUsageSnapshot (final long time, final long CPUTime) 
{ 
m_time = time; 
m_CPUTime = CPUTime; 
} 

} // end of nested class 

// Custom exception class for throwing 
public static final class NegativeCPUTime extends Exception { 
} 


/** 
* Minimum time difference [in milliseconds] enforced for the inputs into 
* {@link #getProcessCPUUsage(SystemInformation.CPUUsageSnapshot,SystemInformation.CPUUsageSnapshot)}. 
* The motivation for this restriction is the fact that System.currentTimeMillis() 
* on some systems has a low resolution (e.g., 10ms on win32). The current value 
* is 100 ms. 
*/ 
public static final int MIN_ELAPSED_TIME = 100; 


/** 
* Creates a CPU usage data snapshot by associating CPU time used with system 
* time. The resulting data can be fed into 
* {@link #getProcessCPUUsage(SystemInformation.CPUUsageSnapshot,SystemInformation.CPUUsageSnapshot)}. 
*/ 
public static CPUUsageSnapshot makeCPUUsageSnapshot() throws SystemInformation.NegativeCPUTime 
{ 
long prCPUTime = getProcessCPUTime (); 
if (prCPUTime<0) throw new NegativeCPUTime(); 
return new CPUUsageSnapshot (System.currentTimeMillis (), getProcessCPUTime ()); 
} 

/** 
* Computes CPU usage (fraction of 1.0) between start.m_CPUTime and 
* end.m_CPUTime time points [1.0 corresponds to 100% utilization of 
* all processors]. 
* 
* @throws IllegalArgumentException if start and end time points are less than 
* {@link #MIN_ELAPSED_TIME} ms apart. 
* @throws IllegalArgumentException if either argument is null; 
*/ 
public static double getProcessCPUUsage (final CPUUsageSnapshot start, final CPUUsageSnapshot end) 
{ 
if (start == null) throw new IllegalArgumentException ("null input: start"); 
if (end == null) throw new IllegalArgumentException ("null input: end"); 
if (end.m_time < start.m_time + MIN_ELAPSED_TIME) 
throw new IllegalArgumentException ("end time must be at least " + MIN_ELAPSED_TIME + " ms later than start time"); 

return ((double)(end.m_CPUTime - start.m_CPUTime)) / (end.m_time - start.m_time); 
} 

/** 
* Returns the PID of the current process. The result is useful when you need 
* to integrate a Java app with external tools. 
*/ 
public static native int getProcessID (); 

/** 
* Returns the number of processors on machine 
*/ 
public static native int getCPUs (); 


/** 
* Returns CPU (kernel + user) time used by the current process [in milliseconds]. 
* The returned value is adjusted for the number of processors in the system. 
*/ 
public static native long getProcessCPUTime (); 

/** 
* Returns CPU (kernel + user) time used by the current process [in perecents]. 
* The returned value is either CPU percentage, or zero if this is not supported by OS. 
* Currently it is supported by Solaris8, and not supported by Windows XP 
*/ 
public static native double getProcessCPUPercentage(); 

/** 
* Returns maximum memory available in the system. 
*/ 
public static native long getMaxMem (); 

/** 
* Returns current free memory in the system. 
*/ 
public static native long getFreeMem (); 

/** 
* Returns system name info like "uname" command output 
*/ 
public static native String getSysInfo (); 


/** 
* Returns CPU usage (fraction of 1.0) so far by the current process. This is a total 
* for all processors since the process creation time. 
*/ 
public static native double getProcessCPUUsage (); 

/** 
* Returns current space allocated for the process, in Kbytes. Those pages may or may not be in memory. 
*/ 
public static native long getMemoryUsage(); 

/** 
* Returns current process space being resident in memory, in Kbytes. 
*/ 
public static native long getMemoryResident(); 

/** 
* Sets the system native process PID for which all measurements will be done. 
* If this method is not called then the current JVM pid will act as a default. 
* Returns the native-dependent error code, or 0 in case of success. 
*/ 
public static native int setPid(int pid); 

/** 
* Closes native-dependent process handle, if necessary. 
*/ 
public static native int detachProcess(); 

// protected: ............................................................. 

// package: ............................................................... 

// private: ............................................................... 


private SystemInformation () {} // prevent subclassing 

private static final String SILIB = "silib"; 

static 
{ 
// loading a native lib in a static initializer ensures that it is 
// available done before any method in this class is called: 
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 
} 
} 

} // end of class 


最重要的方法是getProcessCPUTime(),它会返回当前进程的CPU时间(内核和用户)的毫秒数,或者是PID在初始化期间被传送给本机库的进程所消耗的CPU时间。返回的值应该根据系统的处理器的个数进行调整;下面我们来看看这是如何在本机代码里做到的。我们用修改符native来声明这个方法,这意味着它必须在JNI代码里实现。getProcessCPUTime()方法用来给CPU的使用率数据进行快照,方式是将经过测量的CPU时间与当前的系统时间进行关联。这样的数据库快照在makeCPUUsageSnapshot()方法里进行,并输出一个CPUUsageSnapshot容器对象。这样,测量CPU使用率的原理就很容易理解了:我们按照给定的时间间隔进行两次CPU快照,按1.0的分数来计算两个时间点之间的CPU使用率,方式是两点所在的CPU时间差除以两点所在系统时间差。下面就是getProcessCPUUsage()方法的工作原理: 

public static double getProcessCPUUsage (final CPUUsageSnapshot start, final CPUUsageSnapshot end) 
{ 
if (start == null) throw new IllegalArgumentException ("null input: start"); 
if (end == null) throw new IllegalArgumentException ("null input: end"); 
if (end.m_time < start.m_time + MIN_ELAPSED_TIME) 
throw new IllegalArgumentException ("end time must be at least " + MIN_ELAPSED_TIME + " ms later than start time"); 

return ((double)(end.m_CPUTime - start.m_CPUTime)) / (end.m_time - start.m_time); 
} 



只要我们知道分母里的快照之间的时间间隔,以及分子里进程花在活动状态上的CPU时间,我们就会得到所测量的时间间隔过程中进程的CPU使用率;1.0就代表所有处理器100%的使用率。 

事实上这种方式可以用在所有版本的UNIX的ps工具和Windows的任务管理器上,这两个都是用于监视特定进程的CPU使用率的程序。很显然,时间间隔越长,我们得到的结果就越平均、越不准确。但是最小时差应该被强制输入getProcessCPUUsage()。这种限制的原因是某些系统上的System.currentTimeMillis()的解析度很低。Solaris 8操作系统提供了一个系统调用,用于从内核表里直接获得CPU使用率。出于这个目的,我们拥有的getProcessCPUPercentage()方法会以百分比的形式返回进程所使用的CPU时间。如果这个特性不被操作系统支持(比如在Windows下),那么JNI库就会根据我们应用程序的设计返回一个负值。 

还有其他一些本机声明要在本机部分实现: 

getCPUs()用来返回机器上处理器的个数 
getMaxMem()用来返回系统上可用的最大物理内存 
getFreeMem()用来返回系统上当前可用内存 
getSysInfo()用来返回系统信息,包括一些硬件和操作系统的详细信息 
getMemoryUsage()用来返回分配给进程的空间,以KB为单位(这些页面文件可能在内存里,也有可能不在内存里) 
getMemoryResident()用来返回当前进程驻留在内存里的空间,以KB为单位。 
所有这些方法对于不同的Java开发人员来说常常都是非常有用的。为了确保本机JNI库被调入内存并在调用任何本机方法之前被初始化,这个库被加载到一个静态初始值里: 

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



在初始化一个.dll(或者.so)库之后,我们可以直接使用本机声明的方法: 


final SystemInformation.CPUUsageSnapshot m_prevSnapshot = 
SystemInformation.makeCPUUsageSnapshot (); 
Thread.sleep(1000); 
final SystemInformation.CPUUsageSnapshot event = 
SystemInformation.makeCPUUsageSnapshot (); 
final long memorySize = SystemInformation.getMemoryUsage(); 
final long residentSize = SystemInformation.getMemoryResident(); 
long freemem = SystemInformation.getFreeMem()/1024; 
long maxmem = SystemInformation.getMaxMem()/1024; 
double receivedCPUUsage = 100.0 * SystemInformation.getProcessCPUUsage (m_prevSnapshot, event); 
System.out.println("Current CPU usage is "+receivedCPUUsage+"%”); 




现在让我们来分别看看针对Windows和Solaris的JNI本机实现。C头文件silib.h(列表B)能够用JDK里的Javah工具生成,或者手动编写。 

列表B 


/* DO NOT EDIT THIS FILE - it is machine generated */ 
#include 
/* Header for class com_vladium_utils_SystemInformation */ 

#ifndef _Included_com_vladium_utils_SystemInformation 
#define _Included_com_vladium_utils_SystemInformation 
#ifdef __cplusplus 
extern "C" { 
#endif 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getProcessID 
* Signature: ()I 
*/ 
JNIEXPORT jint 
JNICALL Java_com_vladium_utils_SystemInformation_getProcessID (JNIEnv *, jclass); 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getCPUs 
* Signature: ()I 
*/ 
JNIEXPORT jint 
JNICALL Java_com_vladium_utils_SystemInformation_getCPUs (JNIEnv *, jclass); 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getProcessCPUTime 
* Signature: ()J 
*/ 
JNIEXPORT jlong 
JNICALL Java_com_vladium_utils_SystemInformation_getProcessCPUTime (JNIEnv *, jclass); 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getProcessCPUUsage 
* Signature: ()D 
*/ 
JNIEXPORT jdouble 
JNICALL Java_com_vladium_utils_SystemInformation_getProcessCPUUsage (JNIEnv *, jclass); 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getPagefileUsage 
* Signature: ()J 
*/ 
JNIEXPORT jlong 
JNICALL Java_com_vladium_utils_SystemInformation_getPagefileUsage (JNIEnv *, jclass); 

#ifdef __cplusplus 
} 
#endif 
#endif 





Windows 

首先我们来看看Windows的实现(列表C)。 

列表C 

/* ------------------------------------------------------------------------- */ 
/* 
* An implementation of JNI methods in com.vladium.utils.SystemInformation 
* class. The author compiled it using Microsoft Visual C++ and GCC for Win32 but the code 
* should be easy to use with any compiler for win32 platform. 
* 
* For simplicity, this implementaion assumes JNI 1.2+ and omits error handling. 
* 
* Enhanced by Peter V. Mikhalenko (C) 2004, Deutsche Bank [peter@mikhalenko.com] 
* Original source (C) 2002, Vladimir Roubtsov [vlad@trilogy.com] 
*/ 
/* ------------------------------------------------------------------------- */ 

#include 
#include 
#include 
#include 
#include 
#include 

#include "com_vladium_utils_SystemInformation.h" 

static jint s_PID; 
static HANDLE s_currentProcess; 
static int alreadyDetached; 
static int s_numberOfProcessors; 
static SYSTEM_INFO systemInfo; 
static WORD processorArchitecture; 
static DWORD pageSize; 
static DWORD processorType; 
static WORD processorLevel; 
static WORD processorRevision; 

#define INFO_BUFFER_SIZE 32768 
#define BUFSIZE 2048 


/* ------------------------------------------------------------------------- */ 

/* 
* A helper function for converting FILETIME to a LONGLONG [safe from memory 
* alignment point of view]. 
*/ 
static LONGLONG 
fileTimeToInt64 (const FILETIME * time) 
{ 
ULARGE_INTEGER _time; 

_time.LowPart = time->dwLowDateTime; 
_time.HighPart = time->dwHighDateTime; 

return _time.QuadPart; 
} 
/* ......................................................................... */ 

/* 
* This method was added in JNI 1.2. It is executed once before any other 
* methods are called and is ostensibly for negotiating JNI spec versions, but 
* can also be conveniently used for initializing variables that will not 
* change throughout the lifetime of this process. 
*/ 
JNIEXPORT jint JNICALL 
JNI_OnLoad (JavaVM * vm, void * reserved) 
{ 

s_PID = _getpid (); 
s_currentProcess = GetCurrentProcess (); 
externalCPUmon = 0; 
alreadyDetached = 0; 

GetSystemInfo (& systemInfo); 
s_numberOfProcessors = systemInfo.dwNumberOfProcessors; 
processorArchitecture = systemInfo.wProcessorArchitecture; 
pageSize = systemInfo.dwPageSize; 
processorType = systemInfo.dwProcessorType; 
processorLevel = systemInfo.wProcessorLevel; 
processorRevision = systemInfo.wProcessorRevision; 

return JNI_VERSION_1_2; 
} 
/* ......................................................................... */ 

JNIEXPORT void JNICALL 
JNI_OnUnload (JavaVM * vm, void * reserved) 
{ 

if (!alreadyDetached && s_currentProcess!=NULL) { 
CloseHandle(s_currentProcess); 
printf("[JNI Unload] Detached from native process. 
"); 
fflush(stdout); 
} 

} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getCPUs 
* Signature: ()I 
*/ 
JNIEXPORT jint JNICALL 
Java_com_vladium_utils_SystemInformation_getCPUs (JNIEnv * env, jclass cls) 
{ 
return (jint)s_numberOfProcessors; 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getSysInfo 
* Signature: ()S 
*/ 
JNIEXPORT jstring JNICALL 
Java_com_vladium_utils_SystemInformation_getSysInfo (JNIEnv * env, jclass cls) 
{ 
char buf[2048]; 
char buf2[512]; 
*buf=0; 
OSVERSIONINFOEX osvi; 
BOOL bOsVersionInfoEx; 
TCHAR infoBuf[INFO_BUFFER_SIZE]; 
DWORD bufCharCount = INFO_BUFFER_SIZE; 


// Try calling GetVersionEx using the OSVERSIONINFOEX structure. 
// If that fails, try using the OSVERSIONINFO structure. 
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); 
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 
if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) ) 
{ 
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); 
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) ) { 
// Return empty string in case of problems 
goto next_label; 
} 
} 
switch (osvi.dwPlatformId) 
{ 
// Test for the Windows NT product family. 
case VER_PLATFORM_WIN32_NT: 

// Test for the specific product. 
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) 
strcat(buf,"WinServer2003, "); 

if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 ) 
strcat(buf,"WinXP "); 

if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) 
strcat(buf,"Win2K "); 

if ( osvi.dwMajorVersion <= 4 ) 
strcat(buf,"WinNT "); 

// Test for specific product on Windows NT 4.0 SP6 and later. 
if( bOsVersionInfoEx ) 
{ 
// Test for the workstation type. 
if ( osvi.wProductType == VER_NT_WORKSTATION ) 
{ 
if( osvi.dwMajorVersion == 4 ) 
strcat(buf,"Workstation 4.0 " ); 
else if( osvi.wSuiteMask & VER_SUITE_PERSONAL ) 
strcat(buf,"Home Edition " ); 
else 
strcat(buf,"Professional " ); 
} 

// Test for the server type. 
else if ( osvi.wProductType == VER_NT_SERVER || 
osvi.wProductType == VER_NT_DOMAIN_CONTROLLER ) 
{ 
if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 ) 
{ 
if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) 
strcat(buf,"Datacenter Edition " ); 
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) 
strcat(buf,"Enterprise Edition " ); 
else if ( osvi.wSuiteMask == VER_SUITE_BLADE ) 
strcat(buf,"Web Edition " ); 
else 
strcat(buf,"Standard Edition " ); 
} 

else if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 ) 
{ 
if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) 
strcat(buf,"Datacenter Server " ); 
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) 
strcat(buf,"Advanced Server " ); 
else 
strcat(buf,"Server " ); 
} 

else // Windows NT 4.0 
{ 
if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) 
strcat(buf,"Server 4.0, Enterprise Edition " ); 
else 
strcat(buf,"Server 4.0 " ); 
} 
} 
} 
else // Test for specific product on Windows NT 4.0 SP5 and earlier 
{ 
HKEY hKey; 
char szProductType[BUFSIZE]; 
DWORD dwBufLen=BUFSIZE; 
LONG lRet; 

lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
"SYSTEMCurrentControlSetControlProductOptions", 
0, KEY_QUERY_VALUE, &hKey ); 
if( lRet != ERROR_SUCCESS ) { 
goto next_label; 
} 

lRet = RegQueryValueEx( hKey, "ProductType", NULL, NULL, 
(LPBYTE) szProductType, &dwBufLen); 
if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) ) { 
goto next_label; 
} 

RegCloseKey( hKey ); 

if ( lstrcmpi( "WINNT", szProductType) == 0 ) 
strcat(buf,"Workstation " ); 
if ( lstrcmpi( "LANMANNT", szProductType) == 0 ) 
strcat(buf,"Server " ); 
if ( lstrcmpi( "SERVERNT", szProductType) == 0 ) 
strcat(buf,"Advanced Server " ); 

sprintf(buf2, "%d.%d ", (int)osvi.dwMajorVersion, (int)osvi.dwMinorVersion ); 
strcat(buf,buf2); 
} 

// Display service pack (if any) and build number. 

if( osvi.dwMajorVersion == 4 && 
lstrcmpi( osvi.szCSDVersion, "Service Pack 6" ) == 0 ) 
{ 
HKEY hKey; 
LONG lRet; 

// Test for SP6 versus SP6a. 
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
"SOFTWAREMicrosoftWindows NTCurrentVersionHotfixQ246009", 
0, KEY_QUERY_VALUE, &hKey ); 
if( lRet == ERROR_SUCCESS ) { 
sprintf(buf2, "SP 6a (Build %d), ", (int)(osvi.dwBuildNumber & 0xFFFF) ); 
strcat(buf,buf2); 
} 
else // Windows NT 4.0 prior to SP6a 
{ 
sprintf(buf2, "%s (Build %d), ", 
osvi.szCSDVersion, 
(int)(osvi.dwBuildNumber & 0xFFFF)); 
strcat(buf,buf2); 
} 

RegCloseKey( hKey ); 
} 
else // not Windows NT 4.0 
{ 
sprintf(buf2, "%s (Build %d), ", 
osvi.szCSDVersion, 
(int)(osvi.dwBuildNumber & 0xFFFF)); 
strcat(buf,buf2); 
} 


break; 

// Test for the Windows Me/98/95. 
case VER_PLATFORM_WIN32_WINDOWS: 

if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) 
{ 
strcat(buf,"Win95 "); 
if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' ) 
strcat(buf,"OSR2 " ); 
} 

if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) 
{ 
strcat(buf,"Win98 "); 
if ( osvi.szCSDVersion[1] == 'A' ) 
strcat(buf,"SE " ); 
} 

if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) 
{ 
strcat(buf,"WinME "); 
} 
break; 

case VER_PLATFORM_WIN32s: 

strcat(buf,"Win32s "); 
break; 
} 

next_label: 

strcat(buf," 
on "); 
// Get and display the name of the computer. 
bufCharCount = INFO_BUFFER_SIZE; 
if( !GetComputerName( infoBuf, &bufCharCount ) ) 
goto next_label_2; 
strcat(buf, infoBuf ); 

next_label_2: 
strcat(buf," ("); 
if (!(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS && osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)) { 
// Win95 does not keep CPU info in registry 
LONG lRet; 
HKEY hKey; 
char szOrigCPUType[BUFSIZE]; 
int i=0; 
DWORD dwBufLen=BUFSIZE; 
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE, 
"HARDWAREDESCRIPTIONSystemCentralProcessor", 
0, KEY_QUERY_VALUE, &hKey ); 
if( lRet != ERROR_SUCCESS ) { 
goto next_label_3; 
} 

lRet = RegQueryValueEx( hKey, "ProcessorNameString", NULL, NULL, 
(LPBYTE) szOrigCPUType, &dwBufLen); 
if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) ) { 
goto next_label_3; 
} 
RegCloseKey( hKey ); 
if (strlen(szOrigCPUType)>0) { 
while(szOrigCPUType[i]==' ' && szOrigCPUType[i]!=0) i++; 
strcat(buf,szOrigCPUType+i); 
} else goto next_label_3; 
} else { 
next_label_3: 
if (processorArchitecture==PROCESSOR_ARCHITECTURE_UNKNOWN) strcat(buf,"unknown_arch"); 
else if (processorArchitecture==PROCESSOR_ARCHITECTURE_INTEL) { 
strcat(buf,"Intel "); 
sprintf(buf2,"level %d ",processorLevel); 
strcat(buf,buf2); 
} else if (processorArchitecture==PROCESSOR_ARCHITECTURE_IA64) strcat(buf,"IA64 "); 
else if (processorArchitecture==PROCESSOR_ARCHITECTURE_MIPS) strcat(buf,"MIPS "); 
else if (processorArchitecture==PROCESSOR_ARCHITECTURE_ALPHA) strcat(buf,"Alpha "); 
else if (processorArchitecture==PROCESSOR_ARCHITECTURE_PPC) strcat(buf,"PowerPC "); 
else if (processorArchitecture==PROCESSOR_ARCHITECTURE_SHX) strcat(buf,"SHX "); 
else if (processorArchitecture==PROCESSOR_ARCHITECTURE_ALPHA64) strcat(buf,"Alpha64 "); 
else strcat(buf,"unknown_arch "); 
} 

strcat(buf,")"); 

jstring retval = (*env)->NewStringUTF(env,buf); 
return retval; 
} 
/* ......................................................................... */ 


/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getProcessID 
* Signature: ()I 
*/ 
JNIEXPORT jint JNICALL 
Java_com_vladium_utils_SystemInformation_getProcessID (JNIEnv * env, jclass cls) 
{ 
return s_PID; 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: setPid 
* Signature: ()I 
*/ 
JNIEXPORT jint JNICALL 
Java_com_vladium_utils_SystemInformation_setPid (JNIEnv * env, jclass cls, jint pid) 
{ 
DWORD errCode; 
LPVOID lpMsgBuf; 
s_PID = pid; 
s_currentProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); 
if (s_currentProcess==NULL) { 
errCode = GetLastError(); 
FormatMessage( 
FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM, 
NULL, 
errCode, 
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
(LPTSTR) &lpMsgBuf, 
0, NULL ); 

printf("[CPUmon] Could not attach to native process. 
Error code: %ld 
Error description: %s 
",errCode,lpMsgBuf); 
fflush(stdout); 
LocalFree(lpMsgBuf); 
return errCode; 
} 
printf("[CPUmon] Attached to native process. 
"); 
fflush(stdout); 
return 0; 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: detachProcess 
* Signature: ()I 
*/ 
JNIEXPORT jint JNICALL 
Java_com_vladium_utils_SystemInformation_detachProcess (JNIEnv * env, jclass cls) 
{ 
if (!alreadyDetached && s_currentProcess!=NULL) { 
CloseHandle(s_currentProcess); 
alreadyDetached = 1; 
printf("[CPUmon] Detached from native process. 
"); 
fflush(stdout); 
} 
return 0; 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getProcessCPUTime 
* Signature: ()J 
*/ 
JNIEXPORT jlong JNICALL 
Java_com_vladium_utils_SystemInformation_getProcessCPUTime (JNIEnv * env, jclass cls) 
{ 
FILETIME creationTime, exitTime, kernelTime, userTime; 
DWORD errCode; 
LPVOID lpMsgBuf; 

BOOL resultSuccessful = GetProcessTimes (s_currentProcess, & creationTime, & exitTime, & kernelTime, & userTime); 
if (!resultSuccessful) { 
errCode = GetLastError(); 
FormatMessage( 
FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM, 
NULL, 
errCode, 
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
(LPTSTR) &lpMsgBuf, 
0, NULL ); 

printf("[CPUmon] An error occured while trying to get CPU time. 
Error code: %ld 
Error description: %s 
",errCode,lpMsgBuf); 

fflush(stdout); 
LocalFree(lpMsgBuf); 
return -1; 
} 

return (jlong) ((fileTimeToInt64 (& kernelTime) + fileTimeToInt64 (& userTime)) / 
(s_numberOfProcessors * 10000)); 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getMaxMem 
* Signature: ()J 
*/ 
JNIEXPORT jlong JNICALL 
Java_com_vladium_utils_SystemInformation_getMaxMem (JNIEnv * env, jclass cls) 
{ 
MEMORYSTATUS stat; 
GlobalMemoryStatus (&stat); 
return (jlong)(stat.dwTotalPhys/1024); 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getFreeMem 
* Signature: ()J 
*/ 
JNIEXPORT jlong JNICALL 
Java_com_vladium_utils_SystemInformation_getFreeMem (JNIEnv * env, jclass cls) 
{ 
MEMORYSTATUS stat; 
GlobalMemoryStatus (&stat); 
return (jlong)(stat.dwAvailPhys/1024); 
} 
/* ......................................................................... */ 


/* define min elapsed time (in units of 10E-7 sec): */ 
#define MIN_ELAPSED_TIME (10000) 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getProcessCPUUsage 
* Signature: ()D 
*/ 
JNIEXPORT jdouble JNICALL 
Java_com_vladium_utils_SystemInformation_getProcessCPUUsage (JNIEnv * env, jclass cls) 
{ 
FILETIME creationTime, exitTime, kernelTime, userTime, nowTime; 
LONGLONG elapsedTime; 
DWORD errCode; 
LPVOID lpMsgBuf; 

BOOL resultSuccessful = GetProcessTimes (s_currentProcess, & creationTime, & exitTime, & kernelTime, & userTime); 
if (!resultSuccessful) { 
errCode = GetLastError(); 
FormatMessage( 
FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM, 
NULL, 
errCode, 
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
(LPTSTR) &lpMsgBuf, 
0, NULL ); 

printf("[CPUmon] An error occured while trying to get CPU time. 
Error code: %ld 
Error description: %s 
",errCode,lpMsgBuf); 
fflush(stdout); 
LocalFree(lpMsgBuf); 
return -1.0; 
} 
GetSystemTimeAsFileTime (& nowTime); 

/* 
NOTE: win32 system time is not very precise [~10ms resolution], use 
sufficiently long sampling intervals if you make use of this method. 
*/ 

elapsedTime = fileTimeToInt64 (& nowTime) - fileTimeToInt64 (& creationTime); 

if (elapsedTime < MIN_ELAPSED_TIME) 
return 0.0; 
else 
return ((jdouble) (fileTimeToInt64 (& kernelTime) + fileTimeToInt64 (& userTime))) / 
(s_numberOfProcessors * elapsedTime); 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getProcessCPUPercentage 
* Signature: ()D 
*/ 
JNIEXPORT jdouble JNICALL 
Java_com_vladium_utils_SystemInformation_getProcessCPUPercentage (JNIEnv * env, jclass cls) 
{ 
// Not implemented on Windows 
return (jdouble)(-1.0); 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getMemoryUsage 
* Signature: ()J 
*/ 
JNIEXPORT jlong JNICALL 
Java_com_vladium_utils_SystemInformation_getMemoryUsage (JNIEnv * env, jclass cls) 
{ 
PROCESS_MEMORY_COUNTERS pmc; 

if ( GetProcessMemoryInfo( s_currentProcess, &pmc, sizeof(pmc)) ) 
{ 
return (jlong)(pmc.PagefileUsage/1024); 
} else { 
return (jlong)(0); 
} 
} 
/* ......................................................................... */ 

/* 
* Class: com_vladium_utils_SystemInformation 
* Method: getMemoryResident 
* Signature: ()J 
*/ 
JNIEXPORT jlong JNICALL 
Java_com_vladium_utils_SystemInformation_getMemoryResident (JNIEnv * env, jclass cls) 
{ 
PROCESS_MEMORY_COUNTERS pmc; 

if ( GetProcessMemoryInfo( s_currentProcess, &pmc, sizeof(pmc)) ) 
{ 
return (jlong)(pmc.WorkingSetSize/1024); 
} else { 
return (jlong)(0); 
} 
} 


#undef MIN_ELAPSED_TIME 

/* ------------------------------------------------------------------------- */ 
/* end of file */ 




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值