CPAPは、Agner Foghによる文書から取られています。AgnerFoghには、Intelからの2つの文書(最適化ガイドおよびアーキテクチャソフトウェア開発マニュアル)とともに、多くの有用で興味深いトピックが含まれています。
そもそも、マイクロ秒以内に実行することが期待されるコマンドがあります。 たとえば、IN、OUT、RSM(SMMからの戻り)。 VMEXITは近年劇的に加速しており、新しいプロセッサではマイクロ秒の何分の1かが続きます。 定義により可能な限り実行されるMWAITがあります。 一般に、リング0には多数の「重い」命令があり、すべてマイクロコード(WRMSR、CPUID、制御レジスタの設定など)で構成されています。 以下に示す例は、リング3の特権で、つまり通常のプログラムで実行できます。 Cでのプログラミングも必要ありません。一部の一般的な言語の仮想マシンでは、これらの操作を含むコードを生成できます。 これらは特別なプロセッサコマンドではなく、通常の命令であり、場合によっては特別な条件になります。
これらは長時間実行されるため、当然のことながら、かなり「ホットな」コードで検出されない限り、正常なプロファイラーは通常の時間プロファイルでそれらを検出します。 そのような場合に排他的に応答する別個のパフォーマンスカウンター(PMUレジスタ)がまだあり、それらの助けを借りて、たとえ絶対的な時間があまりかからなくても(理由だけで)大規模なプログラムでこれらの操作を見つけることができます。 このための最も一般的なツールは、 VtuneとLinux perfです。 PCMを使用することもできますが、命令の場所は表示されません。
悪役数4。 ほぼ700クロックサイクルを実行できるx86コマンド(実際にはx87)はFYl2Xです。 第2オペランドを乗算した2進数の対数を計算します。 SSEには類似物が存在しないため、自然界にまだ存在しています。 特別なカウンターはありません。
悪役3番。 おそらく少し人工的な例ですが、頻繁に使用されます。 幸いなことに、主にドライバーで。
MFENCEチーム(またはそのサブセット-LFENCE、SFENCE。ところで、LFENCE + SFENCE!= MFENCE)。 MFENCEの前にメモリまたはPCIe書き込みを伴う長い操作、たとえば、非一時的な操作(MOVNTI、MOVNTPS、MASKMOVDQUなど)、またはオペランドが書き込みスルー/書き込み結合メモリ領域にある操作が実行された場合、「フェンス」自体ほぼ1マイクロ秒以上かかります。 この状況にはパフォーマンスカウンターがありますが、プロセッサコアにはありませんが、「アンコア」では、PCMを介して操作する方が簡単です。
悪役ナンバー2。 これは非常に単純なコードです。
double fptest = 3000000000.0f; // floatと同じ。 // TSC1 int inttest = 2 + fptest; // TSC2 時間= TSC2-TSC1;
時間とほぼ等しいと思いますか? (このコードがx87にコンパイルされるか、スカラーSSEにコンパイルされるかは関係ありません)。 この単一の命令は1〜2マイクロ秒で実行されます。 これはいわゆる非正規化操作であり、マイクロコードの長いシーケンスによって処理される特殊なケースです。 PMUレジスタ-FP_ASSIST.ALLというパフォーマンスカウンターを簡単に取得できます。 ところで、1つ(または数十個)の命令を実行するときにTSCの差を測定することは、ほとんど常に無意味であることは明らかです。 このケースは例外です。長いマイクロコードを測定します。
主な悪役。
静的な符号なしchar配列[128]; for(int i = 0; i <64; i ++)if((int)(array + i)%64 == 63)break; lock =(unsigned int *)(array + i); for(i = 0; i <1024; i ++)*(lock)++; //プライム // TSC1 asm volatile( 「xaddl%1、(%0)\ nをロック」 ://出力なし : "r"(ロック)、 "r"(1)); //またはWindowsでは、単にInterlockedIncrement(ロック); // TSC2 時間= TSC2-TSC1;
さて、ボーナス-ヒットパレードの他の参加者とは異なり、このコードは、他のすべてのカーネルも数千小節の間、スモークブレークのために停止します。
これは、Vtune、perf、PCMなどを使用しても捕捉されます。 カウンターLOCK_CYCLES.SPLIT_LOCK_UC_LOCK_DURATIONを使用します。 例はとてつもないように思えるかもしれませんが、この1年で、クライアントでこの問題に2回遭遇しました。 いずれかの場合、.netで書かれた巨大なプログラムを初期化するときに、LOCK_CYCLES.SPLIT_LOCK_UC_LOCK_DURATIONがスケールを外れました。 そのとき、私はそれを理解していませんでした。ランタイムまたはクライアントコードがミューテックスを見つけられなかったのですが、パフォーマンスが大幅に低下しました-別のカーネルで実行されている別の独立したプログラムが30倍遅くなりました。
誰かがさらに遅い命令を知っていますか? (REP MOVは提供しません)。