废话不多说了,网上存在一种获取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);
}
}