废话不多说了,网上存在一种获取CPU使用率的方法是有bug的。也不知道有多少使用该方法的人没注意这个问题了,反正我是看到有人直接复制了这个代码。
来看一下 FILETIME的结构:
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
这个结构是64位的。ok,上个我调试的截图来证明一下,为什么出错
eax 是32的,shl eax,20h 也是还是他自己。没有任何改变;
注意到 __int64 和 FILETIME都是64位的。所以可以直接转换。
__int64 a = *(__int64*)&time1; //只有一个赋值操作。什么左移,或操作,都不用了。可以少执行几条指令。
ok, 网上的代码一般可以参考,不可直接复制使用的。英文网站的代码,bug比较少。
ok, 展示一份,我参考外文,简化的代码吧。
SmarkLock.hpp
#pragma once #include <wtypes.h> class CSmartLock { public: CSmartLock(CRITICAL_SECTION& ref_cs) { m_cs = ref_cs; EnterCriticalSection(&m_cs); } ~CSmartLock() { LeaveCriticalSection(&m_cs); } private: CRITICAL_SECTION m_cs; };
CPU.hpp
#pragma once #include "SmarkLock.hpp" #include <wtypes.h> #define DELAY_DIFF 200 #define DATA_COUNT (1000/DELAY_DIFF) class CDelay { public: inline void Mark(){ m_mark = ::GetTickCount(); } inline int MSec(){ return (::GetTickCount() - m_mark) & 0x7FFFFFFF; } private: DWORD m_mark; }; class CCPU { public: CCPU(); ~CCPU(); int GetUsage(); private: static CDelay s_delay; static int s_count; static int s_index; static int s_lastCpu; static int s_cpu[DATA_COUNT]; static __int64 s_time; static __int64 s_idleTime; static __int64 s_kernelTime; static __int64 s_userTime; CRITICAL_SECTION m_lock; }; CDelay CCPU::s_delay; int CCPU::s_count = 0; int CCPU::s_index = 0; int CCPU::s_lastCpu = 0; int CCPU::s_cpu[DATA_COUNT]; __int64 CCPU::s_time = 0; __int64 CCPU::s_idleTime = 0; __int64 CCPU::s_kernelTime = 0; __int64 CCPU::s_userTime = 0; CCPU::CCPU() { ::InitializeCriticalSection(&m_lock); s_delay.Mark(); } CCPU::~CCPU() { ::DeleteCriticalSection(&m_lock); } int CCPU::GetUsage() { __int64 sTime; int sLastCpu; #define LOCK_START { CSmartLock lock(m_lock); #define LOCK_END } LOCK_START sTime = s_time; sLastCpu = s_lastCpu; LOCK_END if (s_delay.MSec() <= DELAY_DIFF) return sLastCpu; __int64 time; __int64 idleTime; __int64 kernelTime; __int64 userTime; GetSystemTimeAsFileTime((LPFILETIME)&time); GetSystemTimes( (LPFILETIME)&idleTime, (LPFILETIME)&kernelTime, (LPFILETIME)&userTime ); if (0 == sTime) { LOCK_START s_time = time; s_idleTime = idleTime; s_kernelTime = kernelTime; s_userTime = userTime; s_lastCpu = 0; sLastCpu = s_lastCpu; LOCK_END s_delay.Mark(); return sLastCpu; } int iCpu; LOCK_START __int64 usr = userTime - s_userTime; __int64 ker = kernelTime - s_kernelTime; __int64 idl = idleTime - s_idleTime; __int64 sys = (usr + ker); if (0 == sys) iCpu = 0; else iCpu = (int)((sys - idl) * 100 / sys); s_time = time; s_idleTime = idleTime; s_kernelTime = kernelTime; s_userTime = userTime; s_cpu[(s_index++) % DATA_COUNT] = iCpu; s_count++; if (s_count > DATA_COUNT) s_count = DATA_COUNT; int i; iCpu = 0; for (i = 0; i < s_count; i++) iCpu += s_cpu[i]; iCpu /= s_count; s_lastCpu = iCpu; sLastCpu = s_lastCpu; LOCK_END s_delay.Mark(); return sLastCpu; }
test.cpp
#include "CPU.hpp" #include <stdio.h> void main() { CCPU testCpu; while (true) { static int count = 0; Sleep(DELAY_DIFF); count++; int iCpu = testCpu.GetUsage(); if (count%(1000/DELAY_DIFF) == 0) printf("%d\n", iCpu); } }