windows下基于(QPC)实现的微秒级延时

2021-02-14 00:17

阅读:433

1.为什么会写windows下微秒级延时

在上一篇 实现memcpy()函数及过程总结 中测试memcpy的效率中,测试时间的拷贝效率在微秒级别,需要使用微秒级时间间隔计数。

windows下提供QueryPerformanceCounter(查询高性能计数器),QPC是基于硬件计数器,获取高分辨率时间戳。

参考:Acquiring high-resolution time stamps

应用形式:

 1 LARGE_INTEGER start, end;
 2 LARGE_INTEGER Frequency;
 3 QueryPerformanceFrequency(&Frequency);
 4 
 5 QueryPerformanceCounter(&start);
 6 
 7 //运行时间体
 8  
 9 QueryPerformanceCounter(&end);
10  
11 //转换时间(us) double(end.QuadPart - start.QuadPart) * 1000000 / Frequency.QuadPart

上面通过API查询高性能计数器,开始tick,结束tick,转换对应时间间隔。

2.基于QPC实现us延时

 1 //timer.c
 2
 3 #include "timer.h"
 4 
 5 static LARGE_INTEGER start;
 6 static LARGE_INTEGER tick;
 7 static LONGLONG SecondTick;
 8 
 9 double GetMicrosecondTimeInterval(long long StartTick, long long EndTick, long long Frequency)
10 {
11     return (double)(EndTick - StartTick) * 1000000 / Frequency;
12 }
13 
14 /*
15 *    function:us延时初始化
16 *
17 *    parameter:无
18 *
19 *    return value:无
20 *                
21 */
22 void MicrosecondDelayInit(void)
23 {
24     LARGE_INTEGER frequence;
25     QueryPerformanceFrequency(&frequence);
26     SecondTick = frequence.QuadPart;    
27 }
28 
29 /*
30 *    function:MicrosecondDelay();
31 *             实现微秒级延时
32 *    
33 *    parameter:
34 *                n:延时的us数
35 *    
36 *    return value:
37 *                无
38 */
39 
40 void MicrosecondDelay(int n)
41 {
42     QueryPerformanceCounter(&start);
43     double endtick = SecondTick * n/1000000.0 + start.QuadPart;
44     for(;;)
45     {
46         QueryPerformanceCounter(&tick);
47         if (tick.QuadPart >= endtick)
48             break;
49     }
50 }
 1 //timer.h
 2 
 3 #pragma once        //编译器保证头文件只编译一次
 4 
 5 #include  6 #include  7 
 8 #ifdef __cplusplus  
 9 extern "C" {
10 #endif 
11     double GetMicrosecondTimeInterval(long long StartTick, long long EndTick, long long Frequency);
12     void MicrosecondDelayInit(void);
13     void MicrosecondDelay(int n);
14 #ifdef __cplusplus  
15 }
16 #endif 

3.us延时测试

 1 #include  2 #include  3 #include"timer.h"
 4 
 5 int main(void)
 6 {
 7     LARGE_INTEGER Frequency;
 8     LARGE_INTEGER StartingTime, EndingTime;
 9 
10     QueryPerformanceFrequency(&Frequency);
11     MicrosecondDelayInit();
12 
13     QueryPerformanceCounter(&StartingTime);
14     MicrosecondDelay(10);
15     QueryPerformanceCounter(&EndingTime);
16 
17     printf("延时:%lf\n", GetMicrosecondTimeInterval(StartingTime.QuadPart, EndingTime.QuadPart, Frequency.QuadPart));
18     system("pause");
19     return 0;
20 }

测试情况:

1.延时情况能达到us级,多次测试运行,个别情况延时会有出入(出现情况较少)。

  分析原因:代码级影响较小,主要运行是在windows下,windows并不是实时操作系统,毕竟windows操作系统时间分辨率只能达到ms级。

                        延时可以被打断。cpu的频率会在变化,代码执行效率也会有影响。

2.这种延时效果明显好于Sleep的ms级延时。

4.windows下us延时,控制误差

1.硬件上实现us延时(这种情况对于不涉及底层硬件操作的并不现实)

2.既然windows提供给我们QPC(查询高性能计数器

我们延时前获取StartTick,延时结束后再获取EndTick,转换对应对应时间间隔。QueryPerformanceCounter函数2次消耗时间几乎可以忽略。通过打印我们可以看到us延时数。

大多数运行情况,延时函数效果1us内误差。大于1us延时我们可以剔除,保证1us时间误差。(这种做法是我们需要us级延时做测试时采用,保证后面数据结果在特定延时效果下)

5.总结

us延时常用于测试一些性能时使用。windows并未通过us级的延时函数。QPC是基于查询硬件计数器获取时间间隔,能达到us级别。

 

        


评论


亲,登录后才可以留言!