2012-05-09 63 views
1

私は、プログラムのCPUサイクルを測定するためにrdtscとcpuid命令(揮発性インラインアセンブリ命令を使用)を使用しています。 rdtsc命令は、スピード最適化-o2 -fomit-frame-pointer)とWindows(スピード最適化オプションCコンパイラを使用してMicrosoft Visual Studio 2008(VC 9.0と思う))を使って、Linux上の私のプログラムに現実的な結果をもたらします。rdtscでのgcc最適化の問題

最近、私は多くのテーブルルックアップとこのようなものを使用する新しいプログラムを実装しました。しかし、Linux上でgccを最適化したこのプログラムのrdtsc測定値は、私が期待しているよりも誤った測定(非常に少ないCPUサイクル数)になります。 Windows上で実行されている同じプログラムのrdtsc測定値(上記で述べた最適化とコンパイラでコンパイルされたもの)は現実的であり、期待に合致しています。

私の質問は、gccの最適化は、上記の動作を生成するいくつかの場所の揮発性アセンブリの命令を移動する方法はありますか?タイマーの

私のコードは以下のとおりである:

#define TIMER_VARS             \ 
    uint32 start_lo, start_hi;          \ 
    uint32 ticks_lo, ticks_hi 

#define TIMER_START()            \ 
    __asm__ __volatile__            \ 
    ("rdtsc"              \ 
    : "=a" (start_lo), "=d" (start_hi) /* a = eax, d = edx*/  \ 
    : /* no input parameters*/         \ 
    : "%ebx", "%ecx", "memory") 

#define TIMER_STOP()            \ 
    __asm__ __volatile__            \ 
    ("rdtsc"              \ 
    "\n  subl %2, %%eax"         \ 
    "\n  sbbl %3, %%edx"         \ 
    : "=&a" (ticks_lo), "=&d" (ticks_hi)       \ 
    : "g" (start_lo), "g" (start_hi)        \ 
    : "%ebx", "%ecx", "memory") 

いくつかのボディは、この上でいくつかのアイデアを提案することができれば、私は非常に感謝するでしょう。

おかげで、

+1

シングルコアとマルチコアのマシンの動作に違いがあります(マルチコアマシンは時々クロックを同期させます)。また、tdtscがキャッシュやTLBをドロップすることもありますが、インテルとAMDの違い、チップ間に違いがあります染料版。また、rdtscは、トラップによって処理される可能性のある制限された命令です(可能性があります)。 (私はVMがそういうことをするだろうと思う)コンパイラにはほとんど影響がないと思う。コンパイラアセンブリの出力を確認してください。 – wildplasser

+0

Intelシングルコアプロセッサ搭載のマシンでこの問題に直面しています。 – Junaid

+0

私はタイマーのコードを追加しました。これがもう一つの手がかりを与えるかもしれないかもしれない。 – Junaid

答えて

2

任意のロード/ストア/他の動作を横切って移動されることから、インラインrdtsc機能を防止するためには、両方が__asm__ __volatile__としてASMを書き込み、クロバーリスト内"memory"を含むべきです。後者をせずに、GCCはasmを削除したり、asmの結果を必要とする可能性のある命令(または入力を変更する)を渡すことはできませんが、無関係な操作に関しても移動できます。 "memory" clobberは、GCCがメモリ内容(アドレスが漏洩している可能性のある変数)がasm全体に渡って同じであると仮定することができないため、移動するのがはるかに難しくなることを意味します。しかし、GCCはでもまだは、アドレスが決して取られなかったローカル変数を変更する命令に渡って(as "memory"ではないので)asmを動かすことができるかもしれません。

ああ、ワイルドプラッサーのコメントでは、は、これに多くの時間を無駄にする前に、asmの出力を確認してください。

+0

私は明白な障壁を考えていませんでした。また、命令の障壁のために、CPUはパイプラインを排水しなければならず、パフォーマンスが低下します。それはHeisentickerです... – wildplasser

+0

ええ、それは避けることはかなり不可能です。 –

+0

はい、インラインアセンブリ命令は '__asm__ __volatile__'で書かれています。あなたの提案通り、私はclobberリストに ''メモリ ''を追加しましたが、それはまた助けにはなりませんでした。 – Junaid

1

それがある場合、私は正しい(た)知りませんが、私は一度使用したコードは以下のとおりであった:

#define rdtscll(val) \ 
     __asm__ __volatile__("rdtsc" : "=A" (val)) 

typedef unsigned unsigned long long Ull; 

static inline Ull myget_cycles (void) 
{ 
Ull ret; 

rdtscll(ret); 
return ret; 
} 

私はそれがAMDよりもインテルの「遅く」だった覚えています。 YMMV。

+0

rdtsc単独では実行中にCPUがCPUの順序を変更しないため、ソリューションが正しく測定されていないことに注意してください。 rdtscの前にlfenceまたはcpuid命令を使用するか、より新しいCPUでrdtscpを使用してください。ウィキペディアにそれが正しく記述されていることを確認してください。 – tothphu

+0

@tothphu:あなたは完全に正しいです。並べ替えを恐れている場合はcpuidが必要です。リオーダリングに問題がない場合(例えば、関数呼び出しが介在しているため)、cpuidを省略することができます)。 – wildplasser