2016-03-05 107 views

回答

4

非常舊的CPU的RDTSC是準確的。

問題
但是新的CPU有問題。
工程師們認爲RDTSC對於講述時間會很有幫助。
但是,如果CPU節制頻率RDTSC是無用的告訴時間。
上述braindead工程師決定通過讓TSC始終以相同的頻率運行,即使CPU速度變慢來「解決」這個問題。

這具有TSC可用於告訴已過時(掛鐘)時間的'優勢'。但是它使得TSC 無用 對分析的用處不大。

如何判斷你的CPU不破
如果你可以告訴你的CPU是通過讀取TSC_invariant位在CPUID罰款。

設置AEX爲80000007H並讀取EDX的第8位。
如果它是0,那麼你的CPU很好。
如果它是1,那麼你的CPU壞了,你需要確保你的配置文件,而全速運行CPU。

function IsTimerBroken: boolean; 
{$ifdef CPUX86} 
asm 
    //Make sure RDTSC measure CPU cycles, not wall clock time. 
    push ebx 
    mov eax,$80000007 //Has TSC Invariant support? 
    cpuid 
    pop ebx 
    xor eax,eax  //Assume no 
    and edx,$10  //test TSC_invariant bit 
    setnz al   //if set, return true, your PC is broken. 
end; 
{$endif} 
    //Make sure RDTSC measure CPU cycles, not wall clock time. 
{$ifdef CPUX64} 
asm 
    mov r8,rbx 
    mov eax,$80000007 //TSC Invariant support? 
    cpuid 
    mov rbx,r8 
    xor eax,eax 
    and edx,$10 //test bit 8 
    setnz al 
end; 
{$endif} 

如何解決亂序執行的問題
參見:http://www.intel.de/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf

使用下面的代碼:

function RDTSC: int64; 
{$IFDEF CPUX64} 
asm 
    {$IFDEF AllowOutOfOrder} 
    rdtsc 
    {$ELSE} 
    rdtscp  // On x64 we can use the serializing version of RDTSC 
    push rbx  // Serialize the code after, to avoid OoO sneaking in 
    push rax  // later instructions before the RDTSCP runs. 
    push rdx  // See: http://www.intel.de/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf 
    xor eax,eax 
    cpuid 
    pop rdx 
    pop rax 
    pop rbx 
    {$ENDIF} 
    shl rdx,32 
    or rax,rdx 
    {$ELSE} 
{$IFDEF CPUX86} 
asm 
    {$IFNDEF AllowOutOfOrder} 
    xor eax,eax 
    push ebx 
    cpuid   // On x86 we can't assume the existance of RDTSP 
    pop ebx  // so use CPUID to serialize 
    {$ENDIF} 
    rdtsc 
    {$ELSE} 
error! 
{$ENDIF} 
{$ENDIF} 
end; 

如何破碎的CPU上運行RDTSC
訣竅是強制CPU以100%運行。
這通常通過多次運行示例代碼來完成。
我通常使用1.000.000開始。
然後,我會將那100萬次運行10次,並採取這些嘗試的最低時間。

與理論計時比較表明,這給出非常準確的結果。

+0

TSC還有一個特性位,它在hlt睡眠狀態期間不會停止,這也使得它不能用作時間源。 Linux/proc/cpuinfo調用這個'nonstop_tsc'。由於亂序執行,使用'rdtsc'來定時極短的指令序列也是有問題的。 'rdtscp'可以提供幫助,但其他用途可能需要一個完整的序列化指令來確保'rdtsc'指令不能通過其他insn,而其他insns不會通過它。爲了分析,使用perf計數器。 –

+0

@PeterCordes Perf計數器吸。這就是爲什麼我們需要'rdtsc'爲什麼它被打破對我來說是一個謎。它會殺死英特爾添加一個與主時鐘運行/不同步的額外定時器嗎? – Johan

+0

我通常沒有把我的microbenchmark放入一個足夠大的循環來使用perf計數器的問題。對於非常短的序列,您可以使用IACA或手動計數(使用Agner Fog的表格和uarch指南)來估計吞吐量/延遲/融合域計數。我想這將是一個真正的週期櫃檯,我不能不同意。 IDK實施起來會花多少錢。可能不是很。但是,如果我不得不選擇低開銷的高精度時間源,那麼我會選擇它。 –