Window下的时间计时

秒计时

1.1 使用time()


函数原型:time_t time(time_t * timer)

功能:返回以格林尼治时间(GMT)为标准,从19701100:00:00到现在的此时此刻所经过的秒数。

: localtime, gmtime, asctime, ctime也可以获得当前系统时间或是标准时间.

注意difftime函数可以计算两个time_t类型的时间的差值例如: difftime(t2, t1), 我们也可以t2 - t1, 但是time()返回的值单位不一定是秒所以使用difftime()更可靠。 

time_t start, end, ttt;  
time(&start);
Sleep(1000);
time(&end);
ttt = difftime(end, start);

毫秒计时

2.1 使用GetTickCount


DWORD GetTickCount(void);

定义: 

For Release configurations, this function returns the number of milliseconds since the device booted, excluding any time that the system was suspended. GetTickCount starts at 0 on boot and then counts up from there.

Release版本中,该函数从0开始计时,返回自设备启动后的毫秒数(不含系统暂停时间)。

For Debug configurations, 180 seconds is subtracted from the the number of milliseconds since the device booted. This allows code that uses GetTickCount to be easily tested for correct overflow handling.

Debug版本中,设备启动后便从计时器中减去180秒。这样方便测试使用该函数的代码的正确溢出处理。

 

Return Values

The number of milliseconds indicates success.

返回值:如正确,返回毫秒数。 

unsigned long lBegin, lEnd;
lBegin = ::GetTickCount();
Sleep(1000);
lEnd = ::GetTickCount();
unsigned long l = lEnd - lBegin;

 

2.2 使用clock


clock_t clock(void); 这个函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间(wal-clock).

unsigned long  tBegin = ::clock();
Sleep(1000);
unsigned long tEnd = ::clock();
unsigned long ll = (tEnd - tBegin) * 1000 / CLK_TCK;
// 通常CLK_TCK就是1000, 为了效率, tEnd - tBegin就是毫秒数了
// 但是也要看CLK_TCK

 

2.3 使用timeGetTime


函数原型:DWORD timeGetTime(VOID);

功能:返回系统时间,以毫秒为单位。系统时间是从系统启动到调用函数时所经过的毫秒数.

注意这个值是32位的,会在02^32之间循环,约49.71并且精度不是很高可用timeBeginPeriodtimeEndPeriod函数提高timeGetTime函数的精度.

没有精度使用又麻烦而且有其他方法获得毫秒级的计时所以这种方法基本上不使用. 

#include "Mmsystem.h"
#pragma comment(lib,"Winmm.lib")
DWORD dwStart, dwEnd;  
dwStart = timeGetTime();
Sleep(1000);
dwEnd = timeGetTime();
DWORD dw = dwEnd - dwStart;

 

2.4 小结


GetTickCountclock的说明中可以知道:

1. 可以使用GetTickCount计算电脑开机持续时间.

2. 可以使用clock计算某个进程的运行持续时间.

3. timeGetTime需要手动添加lib, 而且精度可能会不好所以甚至可以不使用.


微秒计时

3.1 使用QueryPerformanceFrequency

原型:BOOL QueryPerformanceFrequency(LARGE_INTERGER *lpFrequency);

功能:返回硬件支持的高精度计数器的频率(每秒钟的CPU Tick)

 

原型:BOOL QueryPerformanceCounter(LARGE_INTEGER *lpCount);

功能:返回高精度计数器的计数值

 

所以消逝时间 = (EndTick - BeginTick) / TickPreSecond;   (单位是秒精度可以达到微秒(看你的硬件而定))

LARGE_INTEGER llTemp, llBegin1, llEnd1;
::QueryPerformanceFrequency(&llTemp); // 获取CPU时钟频率 3220820 kHZ
 
::QueryPerformanceCounter(&llBegin1); // 获取开始计数值 54826082774
Sleep(100);
::QueryPerformanceCounter(&llEnd1);     // 获取结束计数值 54826404859
 
double d = (llEnd1.QuadPart - llBegin1.QuadPart) / (llTemp.QuadPart * 1000.0);  // 单位是秒, 精确到微秒

说明

1. 调用QueryPerformanceFrequency时, 我的电脑返回的值是3220820, 很明显, 其单位是kHZ(我的CPU主频是3.2GHZ)

2. 也就是说3220820倒数一下, 精度也只能达到微秒级了.

 

纳秒计时

4.1 使用RDTSC读取时间标签计数器

4.1.1 RDTSC 指令

这是X86架构CPU汇编指令

指令: RDTSC (操作码: 0x0F 0x31)

功能将时间标签计数器读入EDX:EAX寄存器中.

说明Pentium以上的CPU中,提供了一条机器指令RDTSC来读取这个时间戳的数字,并将其保存在EDX:EAX寄存器对中。由于EDX:EAX寄存器对恰好是Win32平台下C++语言保存函数返回值的寄存器所以我们可以把这条指令看成是一个普通的函数调用.

inline unsigned __int64 GetRDTSC()  
{   
    __asm RDTSC
}
// 如果编译器不允许直接用RDTSC的话,可以用_emit伪指令直接嵌入该指令的机器码形式0x0F 0x31:
inline unsigned __int64 GetRDTSC()   
{  
    __asm _emit 0x0F
    __asm _emit 0x31
} 
 

GetRDTSC得到CPU跳了多少次如果我们知道跳一次的用时就可以算出持续时间.

跳一次的用时 = 1 / CPU主频 (单位)

 

4.1.2 计算CPU主频


Windows平台下可以使用QueryPerformanceFrequency()函数获得CPU的主频但是在标准C/C++中没有这样的函数.

你可以间接发计算出主频例如:

unsigned __int64 GetCPUHZ()
{
	unsigned __int64 nBegin = GetRDTSC();
	Sleep(1000);
	unsigned __int64 nEnd = GetRDTSC();
	return (nEnd - nBegin);	
}


说明

1. 这个函数的误差在于Sleep(1000)的执行时间不是1可能是1.0002.

2. QueryPerformanceFrequency得到的主频的单位是 kHZ, 也就是说其精度只能达到微秒而不是纳秒.

  

4.1.3 计算持续时间

unsigned __int64 nHZ = GetCPUHZ();
unsigned __int64 nBegin = GetRDTSC();
...
unsigned __int64 nEnd = GetRDTSC();
double dTime = (nEnd - nBegin) * 1.0 / nHZ;// 单位是秒, 精度甚至可以达到纳秒

 

说明:

1. 这里的精度可以达到纳秒但是在纳秒级可能不是很准因为GetCPUHZ() 得到主频有误差.

2. 纳秒计时的粒度最小所以你也可以使用这种方法进行微秒毫秒秒的计时.

 

 

小结

1. 计时与定时不同这里计时可以达到纳秒级但是定时就不能(因为执行一条指令可能至少要100纳秒).

 

你可能感兴趣的:(时间,毫秒计时,秒计时,微秒计时,纳秒计时)