测量CPU和内存的占用率常常是检查Java应用程序是否达到特定性能的一个重要环节。尽管Java提供了一些重要的方法用于测量其堆栈大小,但是使用标准的API是无法测量本机Java进程的大小和CPU当前的使用率的。这种测量的结果对于开发人员来说非常重要,它会提供应用程序的实时性能和效率信息。不幸的是,这样的信息只能从操作系统直接获取,而这已经超出了Java标准的可移植能力。
一个主要的解决方案是使用操作系统自带的本机系统调用,将数据通过JNI(Java Native Interface,Java本机接口)传输给Java。与调用各个平台专用的外部命令(比如
我扩展了这个库的能力,在Windows和Solaris 8平台上实现了所有功能。新的库能够测量纯CPU使用时间
所以,我们将创建一个简单的JNI库,用于同C层里的操作系统进行沟通,并把生成的数据提供给Java应用程序。首先,我们要创建一个
<PRE>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 <CODE>System.currentTimeMillis()</CODE>
* 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 <CODE>start.m_CPUTime</CODE> and
* <CODE>end.m_CPUTime</CODE> 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
</PRE>
最重要的方法是
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的
还有其他一些本机声明要在本机部分实现:
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./n");
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,
"SYSTEM//CurrentControlSet//Control//ProductOptions",
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,
"SOFTWARE//Microsoft//Windows NT//CurrentVersion//Hotfix//Q246009",
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,"/r/n 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,
"HARDWARE//DESCRIPTION//System//CentralProcessor//0",
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./n Error code: %ld/n Error description: %s/n",errCode,lpMsgBuf);
fflush(stdout);
LocalFree(lpMsgBuf);
return errCode;
}
printf("[CPUmon] Attached to native process./n");
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./n");
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./n Error code: %ld/n Error description: %s/n",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./n Error code: %ld/n Error description: %s/n",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 */