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級別。