windows下基於(QPC)實現的微秒級延時


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 <windows.h>
 6 #include <stdio.h>
 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 <stdio.h>
 2 #include <Windows.h>
 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(查詢高性能計數器 <1us),配合着使用我們自己實現的us級延時。

我們延時前獲取StartTick,延時結束后再獲取EndTick,轉換對應對應時間間隔。QueryPerformanceCounter函數2次消耗時間幾乎可以忽略。通過打印我們可以看到us延時數。

大多數運行情況,延時函數效果1us內誤差。大於1us延時我們可以剔除,保證1us時間誤差。(這種做法是我們需要us級延時做測試時采用,保證后面數據結果在特定延時效果下)

5.總結

us延時常用於測試一些性能時使用。windows並未通過us級的延時函數。QPC是基於查詢硬件計數器獲取時間間隔,能達到us級別。

 

        


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM