在单元测试中,有一部分的内容就是计算各个函数计算时间,这样可以知道性能瓶颈在哪里。所以,如何对软件进行性能计时一直是我关注的一个话题。就我目前的认知来说,不同的环境对软件性能其实要求是不一样的,所以有的软件可能是秒级,有的是毫秒级的,而有的则是cpu周期级别的。下面,我们就可以一一开始介绍了。
(1)秒级
利用秒对软件进行度量其实是很少的,但是它可以为我们提供一种基本的思路。在软件计算前,我们计算当前的基本时间,在服务结束后,我们再计算一下当前的时间,中间的差值就是实际运行的时间。所用的基本函数就是_strtime,
(2)毫秒
对于绝大多数软件来说,可以通过毫秒函数获得实际业务运行的时间。对于vxWorks操作系统来说,这个函数是tickGet,而在windows系统里面,这个函数是GetTickCount,使用起来的都非常得方便。
(3)时钟周期
就像前面说过的,毫秒级的度量对于大多数函数来说足够了。但是对于系统级别的应用,特别是在系统切换的度量上面,考虑实际指令究竟花费了多长时间,毫秒级的函数肯定不好使了。在intel芯片上就存在这样的指令,即为rdtsc。调用了这个指令,对应的指令周期就可以保存下来。整个周期数值是一个64位数,高位记录在edx,低位记录在eax。
(4)多核时钟周期
前面说到的时钟周期计算基本上都是建立在单核的领域,但是现在很多电脑配置都是多核的cpu处理器,而且对于不同core的cpu来说,不同的cpu其实它的时钟周期是不一样的,所以这里就涉及到如果对多核的cpu进行周期计算的问题。好在windows已经为我们考虑到了这个问题,我们可以通过设置SetThreadAffinityMask这个函数帮我们把线程绑定在某一个cpu之上,这样就不会有什么差错了。编写完程序之后,大家可以通过taskmgr程序看看结果,就会有不一样的认识。
示例代码:
#include <stdio.h>
#include <windows.h>
void test1()
{
unsigned int lower;
unsigned int higher;
__asm
{
push eax
push edx
rdtsc
mov lower, eax
mov higher, edx
pop edx
pop eax
}
printf("cpu cycle = 0x%08x%08x\n", higher, lower);
}
void test2()
{
unsigned int before;
unsigned int after;
__asm
{
push eax
rdtsc
mov before, eax
rdtsc
mov after, eax
pop eax
}
printf("single instuct time = 0x%08x\n", after - before);
}
int main(int argc, char* argv[])
{
char buffer[16];
int value;
SetThreadAffinityMask(GetCurrentThread(), 2);
_strtime(buffer);
printf("%s\n",buffer);
value = GetTickCount();
printf("interval = %d\n", GetTickCount() - value);
test1();
test2();
return 1;
}