前言
目前有各种计时函数,
- 一般的处理都是先调用计时函数, 记下当前时间
start
- 然后运行自己的代码
- 再调用计时函数, 记下处理后的时间
end
- 再
end
和start
做差, 就可以得到程序的执行时间
但是各种计时函数的精度不一样.
序号 | 函数 | 类型 | 精度级别 | 时间 |
---|---|---|---|---|
1 | time | C系统调用 | 低 | <1s |
2 | clcok windows, linux均可用, 推荐 | C系统调用 | 低 | <10ms |
3 | timeGetTime | Windows API | 中 | <1ms |
4 | QueryPerformanceCounter windows下最好的方法 | Windows API | 高 | <0.1ms |
5 | GetTickCount | Windows API | 中 | <1ms |
6 | RDTSC (实际不可用) | 指令 | 高 | <0.1ms |
7 | gettimeofday linux下最好的方法 | linux环境下C系统调用 | 高 | <0.1ms |
time
time()
获取当前的系统时间, 返回的结果是一个time_t
类型, 其值表示从"CUT(Coordinated Universal Time)
时间1970年1月1日00:00:00(称为UNIX系统的Epoch时间)"到"当前时刻的秒数".
精度: 低, <1s
调用Sleep(50), 让程序暂停50ms, 测得运行时间为 0ms, 表明精度的低
1 |
|
clock
clock()
函数返回从"开启这个程序进程"到"程序中调用clock()
函数"时之间的CPU时钟计时单元(clock tick)数, 在MSDN中称之为挂钟时间(wal-clock)
常量CLOCKS_PER_SEC
, 它用来表示一秒钟会有多少个时钟计时单元
精度: 低, <10ms
1 |
|
timeGetTime
timeGetTime()
函数以毫秒级的系统时间. 该时间为从系统开启算起所经过的时间, 是windows api
精度: 中, <1ms
1 |
|
QueryPerformanceCounter
QueryPerformanceCounter()
这个函数返回高精确度性能计数器的值, 它可以以微秒为单位计时. 但是QueryPerformanceCounter()
确切的精确计时的最小单位是与系统有关的, 所以, 必须要查询系统以得到QueryPerformanceCounter()
返回的嘀哒声的频率. QueryPerformanceFrequency()
提供了这个频率值, 返回每秒嘀哒声的个数.
精度: 高, <0.1ms
1 |
|
GetTickCount
GetTickCount()
返回(retrieve)从操作系统启动到现在所经过(elapsed)的毫秒数, 它的返回值是DWORD
精度: 中, <1ms
1 |
|
RDTSC
RDTSC
指令, 在Intel Pentium以上级别的CPU中, 有一个称为"时间戳(Time Stamp)"的部件, 它以64位无符号整型数的格式, 记录了自CPU上电以来所经过的时钟周期数。由于目前的CPU主频都非常高, 因此这个部件可以达到纳秒级的计时精度。这个精确性是上述几种方法所无法比拟的. 在Pentium以上的CPU中, 提供了一条机器指令RDTSC(Read Time Stamp Counter)来读取这个时间戳的数字, 并将其保存在EDX:EAX寄存器对中. 由于EDX:EAX寄存器对恰好是Win32平台下C语言保存函数返回值的寄存器, 所以我们可以把这条指令看成是一个普通的函数调用, 因为RDTSC不被C的内嵌汇编器直接支持, 所以我们要用_emit伪指令直接嵌入该指令的机器码形式0X0F、0X31
然而真相
多核时代不宜再用 x86 的 RDTSC 指令测试指令周期和时间
- 不能保证同一块主板上每个核的 TSC 是同步的;
- CPU 的时钟频率可能变化, 例如笔记本电脑的节能功能;
- 乱序执行导致 RDTSC 测得的周期数不准, 这个问题从 Pentium Pro 时代就存在。
1 |
|
gettimeofday
gettimeofday()
linux环境下的计时函数, int gettimeofday(struct timeval* tv , struct timezone* tz)
, gettimeofday()
会把目前的时间有tv
所指的结构返回, 当地时区的信息则放到tz
所指的结构中.
精度: 高, <0.1ms
1 |
|