//.h#ifndef _CPUUSAGE_H #define _CPUUSAGE_H #include <windows.h> #include <WINPERF.H> #include <comdef.h> // for using bstr_t class #include <atlbase.h>#include "stdafx.h" #pragma pack(push,8) #pragma pack(pop) #define SYSTEM_OBJECT_INDEX 2 // 'System' object #define PROCESS_OBJECT_INDEX 230 // 'Process' object #define PROCESSOR_OBJECT_INDEX 238 // 'Processor' object #define TOTAL_PROCESSOR_TIME_COUNTER_INDEX 240 // '% Total processor time' counter (valid in WinNT under 'System' object) #define PROCESSOR_TIME_COUNTER_INDEX 6 // '% processor time' counter (for Win2K/XP) #define TOTALBYTES 100*1024 #define BYTEINCREMENT 10*1024 class CCpuUsage { public: CCpuUsage(); virtual ~CCpuUsage(); // Methods int GetCpuUsage(); int GetCpuUsage(LPCTSTR pProcessName); BOOL EnablePerformaceCounters(BOOL bEnable = TRUE); // Attributes private: bool m_bFirstTime; LONGLONG m_lnOldValue ; LARGE_INTEGER m_OldPerfTime100nSec; }; template <class T> class CPerfCounters { public: CPerfCounters() { } ~CPerfCounters() { } T GetCounterValue(PERF_DATA_BLOCK **pPerfData, DWORD dwObjectIndex, DWORD dwCounterIndex, LPCTSTR pInstanceName = NULL) { QueryPerformanceData(pPerfData, dwObjectIndex, dwCounterIndex); PPERF_OBJECT_TYPE pPerfObj = NULL; T lnValue = {0}; // Get the first object type. pPerfObj = FirstObject( *pPerfData ); // Look for the given object index for( DWORD i=0; i<(*pPerfData)->NumObjectTypes; i++ ) { if (pPerfObj->ObjectNameTitleIndex == dwObjectIndex) { lnValue = GetCounterValue(pPerfObj, dwCounterIndex, pInstanceName); break; } pPerfObj = NextObject( pPerfObj ); } return lnValue; } protected: class CBuffer { public: CBuffer(UINT Size) { m_Size = Size; m_pBuffer = (LPBYTE) malloc( Size*sizeof(BYTE) ); } ~CBuffer() { free(m_pBuffer); } void *Realloc(UINT Size) { m_Size = Size; m_pBuffer = (LPBYTE) realloc( m_pBuffer, Size ); return m_pBuffer; } void Reset() { memset(m_pBuffer,NULL,m_Size); } operator LPBYTE () { return m_pBuffer; } UINT GetSize() { return m_Size; } public: LPBYTE m_pBuffer; private: UINT m_Size; }; // // The performance data is accessed through the registry key // HKEY_PEFORMANCE_DATA. // However, although we use the registry to collect performance data, // the data is not stored in the registry database. // Instead, calling the registry functions with the HKEY_PEFORMANCE_DATA key // causes the system to collect the data from the appropriate system // object managers. // // QueryPerformanceData allocates memory block for getting the // performance data. // // void QueryPerformanceData(PERF_DATA_BLOCK **pPerfData, DWORD dwObjectIndex, DWORD dwCounterIndex) { // // Since i want to use the same allocated area for each query, // i declare CBuffer as static. // The allocated is changed only when RegQueryValueEx return ERROR_MORE_DATA // static CBuffer Buffer(TOTALBYTES); DWORD BufferSize = Buffer.GetSize(); LONG lRes; char keyName[8]; sprintf(keyName,"%d %d",dwObjectIndex, dwCounterIndex); Buffer.Reset(); while( (lRes = RegQueryValueEx( HKEY_PERFORMANCE_DATA, keyName, NULL, NULL, Buffer, &BufferSize )) == ERROR_MORE_DATA ) { // Get a buffer that is big enough. BufferSize += BYTEINCREMENT; Buffer.Realloc(BufferSize); } *pPerfData = (PPERF_DATA_BLOCK) Buffer.m_pBuffer; } // // GetCounterValue gets performance object structure // and returns the value of given counter index . // This functions iterates through the counters of the input object // structure and looks for the given counter index. // // For objects that have instances, this function returns the counter value // of the instance pInstanceName. // T GetCounterValue(PPERF_OBJECT_TYPE pPerfObj, DWORD dwCounterIndex, LPCTSTR pInstanceName) { PPERF_COUNTER_DEFINITION pPerfCntr = NULL; PPERF_INSTANCE_DEFINITION pPerfInst = NULL; PPERF_COUNTER_BLOCK pCounterBlock = NULL; // Get the first counter. pPerfCntr = FirstCounter( pPerfObj ); // Look for the index of '% Total processor time' for( DWORD j=0; j < pPerfObj->NumCounters; j++ ) { if (pPerfCntr->CounterNameTitleIndex == dwCounterIndex) break; // Get the next counter. pPerfCntr = NextCounter( pPerfCntr ); } if( pPerfObj->NumInstances == PERF_NO_INSTANCES ) { pCounterBlock = (PPERF_COUNTER_BLOCK) ((LPBYTE) pPerfObj + pPerfObj->DefinitionLength); } else { pPerfInst = FirstInstance( pPerfObj ); // Look for instance pInstanceName _bstr_t bstrInstance; _bstr_t bstrInputInstance = pInstanceName; for( int k=0; k< pPerfObj->NumInstances; k++ ) { bstrInstance = (wchar_t *)((PBYTE)pPerfInst + pPerfInst->NameOffset); if (!stricmp((LPCTSTR)bstrInstance, (LPCTSTR)bstrInputInstance)) { pCounterBlock = (PPERF_COUNTER_BLOCK) ((LPBYTE) pPerfInst + pPerfInst->ByteLength); break; } // Get the next instance. pPerfInst = NextInstance( pPerfInst ); } } if (pCounterBlock) { T *lnValue = NULL; lnValue = (T*)((LPBYTE) pCounterBlock + pPerfCntr->CounterOffset); return *lnValue; } return -1; } /***************************************************************** * * * Functions used to navigate through the performance data. * * * *****************************************************************/ PPERF_OBJECT_TYPE FirstObject( PPERF_DATA_BLOCK PerfData ) { return( (PPERF_OBJECT_TYPE)((PBYTE)PerfData + PerfData->HeaderLength) ); } PPERF_OBJECT_TYPE NextObject( PPERF_OBJECT_TYPE PerfObj ) { return( (PPERF_OBJECT_TYPE)((PBYTE)PerfObj + PerfObj->TotalByteLength) ); } PPERF_COUNTER_DEFINITION FirstCounter( PPERF_OBJECT_TYPE PerfObj ) { return( (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj + PerfObj->HeaderLength) ); } PPERF_COUNTER_DEFINITION NextCounter( PPERF_COUNTER_DEFINITION PerfCntr ) { return( (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr + PerfCntr->ByteLength) ); } PPERF_INSTANCE_DEFINITION FirstInstance( PPERF_OBJECT_TYPE PerfObj ) { return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj + PerfObj->DefinitionLength) ); } PPERF_INSTANCE_DEFINITION NextInstance( PPERF_INSTANCE_DEFINITION PerfInst ) { PPERF_COUNTER_BLOCK PerfCntrBlk; PerfCntrBlk = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst + PerfInst->ByteLength); return( (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfCntrBlk + PerfCntrBlk->ByteLength) ); } };#endif//.cpp/////////////////////////////////////////////////////////////////// // // GetCpuUsage uses the performance counters to retrieve the // system cpu usage. // The cpu usage counter is of type PERF_100NSEC_TIMER_INV // which as the following calculation: // // Element Value // ======= =========== // X CounterData // Y 100NsTime // Data Size 8 Bytes // Time base 100Ns // Calculation 100*(1-(X1-X0)/(Y1-Y0)) // // where the denominator (Y) represents the total elapsed time of the // sample interval and the numerator (X) represents the time during // the interval when the monitored components were inactive. // // // Note: // ==== // On windows NT, cpu usage counter is '% Total processor time' // under 'System' object. However, in Win2K/XP Microsoft moved // that counter to '% processor time' under '_Total' instance // of 'Processor' object. // Read 'INFO: Percent Total Performance Counter Changes on Windows 2000' // Q259390 in MSDN. // /////////////////////////////////////////////////////////////////// #include "stdafx.h"#include "cpu.h"typedef enum { WINNT, WIN2K_XP, WIN9X, UNKNOWN }PLATFORM; PLATFORM GetPlatform() { OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx(&osvi)) return UNKNOWN; switch (osvi.dwPlatformId) { case VER_PLATFORM_WIN32_WINDOWS: return WIN9X; case VER_PLATFORM_WIN32_NT: if (osvi.dwMajorVersion == 4) return WINNT; else return WIN2K_XP; } return UNKNOWN; } CCpuUsage::CCpuUsage() { m_bFirstTime = true; m_lnOldValue = 0; memset(&m_OldPerfTime100nSec, 0, sizeof(m_OldPerfTime100nSec)); } CCpuUsage::~CCpuUsage() { } BOOL CCpuUsage::EnablePerformaceCounters(BOOL bEnable) { if (GetPlatform() != WIN2K_XP) return TRUE; CRegKey regKey; if (regKey.Open(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\PerfOS\\Performance") != ERROR_SUCCESS) return FALSE; regKey.SetValue(!bEnable, "Disable Performance Counters"); regKey.Close(); if (regKey.Open(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\PerfProc\\Performance") != ERROR_SUCCESS) return FALSE; regKey.SetValue(!bEnable, "Disable Performance Counters"); regKey.Close(); return TRUE; } // // GetCpuUsage returns the system-wide cpu usage. // Since we calculate the cpu usage by two samplings, the first // call to GetCpuUsage() returns 0 and keeps the values for the next // sampling. // Read the comment at the beginning of this file for the formula. // int CCpuUsage::GetCpuUsage() { static PLATFORM Platform = GetPlatform(); if (m_bFirstTime) EnablePerformaceCounters(); // Cpu usage counter is 8 byte length. CPerfCounters<LONGLONG> PerfCounters; char szInstance[256] = {0}; // Note: // ==== // On windows NT, cpu usage counter is '% Total processor time' // under 'System' object. However, in Win2K/XP Microsoft moved // that counter to '% processor time' under '_Total' instance // of 'Processor' object. // Read 'INFO: Percent Total Performance Counter Changes on Windows 2000' // Q259390 in MSDN. DWORD dwObjectIndex; DWORD dwCpuUsageIndex; switch (Platform) { case WINNT: dwObjectIndex = SYSTEM_OBJECT_INDEX; dwCpuUsageIndex = TOTAL_PROCESSOR_TIME_COUNTER_INDEX; break; case WIN2K_XP: dwObjectIndex = PROCESSOR_OBJECT_INDEX; dwCpuUsageIndex = PROCESSOR_TIME_COUNTER_INDEX; strcpy(szInstance,"_Total"); break; default: return -1; } int CpuUsage = 0; LONGLONG lnNewValue = 0; PPERF_DATA_BLOCK pPerfData = NULL; LARGE_INTEGER NewPerfTime100nSec = {0}; lnNewValue = PerfCounters.GetCounterValue(&pPerfData, dwObjectIndex, dwCpuUsageIndex, szInstance); NewPerfTime100nSec = pPerfData->PerfTime100nSec; if (m_bFirstTime) { m_bFirstTime = false; m_lnOldValue = lnNewValue; m_OldPerfTime100nSec = NewPerfTime100nSec; return 0; } LONGLONG lnValueDelta = lnNewValue - m_lnOldValue; double DeltaPerfTime100nSec = (double)NewPerfTime100nSec.QuadPart - (double)m_OldPerfTime100nSec.QuadPart; m_lnOldValue = lnNewValue; m_OldPerfTime100nSec = NewPerfTime100nSec; double a = (double)lnValueDelta / DeltaPerfTime100nSec; double f = (1.0 - a) * 100.0; CpuUsage = (int)(f + 0.5); // rounding the result if (CpuUsage == 0) return 0; return CpuUsage; } int CCpuUsage::GetCpuUsage(LPCTSTR pProcessName) { static PLATFORM Platform = GetPlatform(); if (m_bFirstTime) EnablePerformaceCounters(); // Cpu usage counter is 8 byte length. CPerfCounters<LONGLONG> PerfCounters; char szInstance[256] = {0}; DWORD dwObjectIndex = PROCESS_OBJECT_INDEX; DWORD dwCpuUsageIndex = PROCESSOR_TIME_COUNTER_INDEX; strcpy(szInstance,pProcessName); int CpuUsage = 0; LONGLONG lnNewValue = 0; PPERF_DATA_BLOCK pPerfData = NULL; LARGE_INTEGER NewPerfTime100nSec = {0}; lnNewValue = PerfCounters.GetCounterValue(&pPerfData, dwObjectIndex, dwCpuUsageIndex, szInstance); NewPerfTime100nSec = pPerfData->PerfTime100nSec; if (m_bFirstTime) { m_bFirstTime = false; m_lnOldValue = lnNewValue; m_OldPerfTime100nSec = NewPerfTime100nSec; return 0; } LONGLONG lnValueDelta = lnNewValue - m_lnOldValue; double DeltaPerfTime100nSec = (double)NewPerfTime100nSec.QuadPart - (double)m_OldPerfTime100nSec.QuadPart; m_lnOldValue = lnNewValue; m_OldPerfTime100nSec = NewPerfTime100nSec; double a = (double)lnValueDelta / DeltaPerfTime100nSec; CpuUsage = (int) (a*100); if (CpuUsage == 0) return 0; return CpuUsage; }