這是個 nano-second 精度的計時器,所做的僅是計算 MSR 差值。
在 multi-core processors 下,
各 CPU 的 TSC 同步率若不高,計時結果也會有誤差,
故建構 TimeProfile 時,便設法讓行程在單一 CPU 上跑。
設計上很簡便,但存在一些缺點:
1. 當他前幾次執行時,算出來的時間間隔會比較長。
因為 CPU 要花時間將算法的相關指令與資料 load 到 L2 甚至 L1 裡,
並調整諸如分支預測等機制的最佳模式。
2. Process 會因 context switch 被切出去,但 MSR 仍持續累加,
造成計時誤差。為避免此情形,可在檢測算法前,
將 process 與其中的 main thread 之 priority 提高,
待算完後再行回復:
DWORD oldProcess = GetPriorityClass (GetCurrentProcess());
DWORD oldThread = GetThreadPriority (GetCurrentThread());
SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
...........[Algorithm]...........
SetThreadPriority (GetCurrentThread(), oldThread);
SetPriorityClass (GetCurrentProcess(), oldProcess);
但這步驟可能會讓其他 thread 無法順暢執行,
為保持 TimeProfile 的「輕鬆」簡便,便不加上這層考量。
3. 現今許多 CPU 為了省電節能,當處於閒置狀態會降低主頻,
如: Intel 的 EIST、AMD 的 C&Q,
故 TimeProfile 中額外定義了 set_freq,
以便在「需要」時重新讀取 CPU 頻率。
4. 需注意:真正的計時類別尚有許多細節待考慮,
本程式僅是個以簡便為主的粗糙設計。
#include <stdio.h> #include <windows.h> class TimeProfile { unsigned __int64 Hz; unsigned __int64 cycle() //讀取 64-bit 的 { //Model Specific Register (MSR) _asm { xor eax, eax _emit 0x0F //使用 cpuid 讓 CPU 不採無序執行指令 _emit 0xA2 //讓接下來的指令照流水線運行 _emit 0x0F //注意: 586 後的 IA32 才支援 RDTSC _emit 0x31 //結果置於 EDX:EAX } } public: void set_freq() { LARGE_INTEGER freq; QueryPerformanceFrequency (&freq); Hz = freq.QuadPart; } TimeProfile() { set_freq(); //若 multi-core 同步率高, 可不用加下面那行 SetThreadAffinityMask (GetCurrentThread(), 1); } double time; void start() {time = (double) cycle();} void end() {time = double (cycle()-time) /Hz;} };測試碼:
double cal_pi (int i = 50) { double pi = 2; for (; i>0; i--) pi = pi * double(i)/(2*i+1) + 2; return pi; } int main (/* daviddr 081211 */) { TimeProfile tp; double pi; for (int i=1; i<52; i+=5) { tp.start(); pi = cal_pi (i); tp.end(); printf ("\n[%2d] PI = %.15f Time: %.9f", i, pi, tp.time); } return system ("pause"); }從結果可以觀察到:第一次執行時,
因為 CPU 要做些「準備工作」,算出的時間便較長。
[ 1] PI = 2.666666666666667 Time: 0.000004494
[ 6] PI = 3.132156732156732 Time: 0.000001445
[11] PI = 3.141358472520136 Time: 0.000001507
[16] PI = 3.141586396037061 Time: 0.000001674
[21] PI = 3.141592479958224 Time: 0.000001756
[26] PI = 3.141592648659952 Time: 0.000001881
[31] PI = 3.141592653447636 Time: 0.000002006
[36] PI = 3.141592653585648 Time: 0.000002130
[41] PI = 3.141592653589671 Time: 0.000002255
[46] PI = 3.141592653589790 Time: 0.000002379
[51] PI = 3.141592653589793 Time: 0.000002504
沒有留言:
張貼留言