web-dev-qa-db-ja.com

マイクロフュージョンとアドレッシングモード

Intel®ArchitectureCodeAnalyzer (IACA)を使用して、(私にとって)予期しない何かを見つけました。

[base+index]アドレス指定を使用した次の命令

addps xmm1, xmmword ptr [rsi+rax*1]

iACAによるとマイクロヒューズはありません。ただし、このように[base+offset]を使用すると

addps xmm1, xmmword ptr [rsi]

IACAはそれがヒューズをすることを報告します。

Intel最適化リファレンスマニュアル のセクション2-11は、「すべてのデコーダーで処理できるマイクロ融合マイクロオペレーションの例」として以下を示しています。

FADD DOUBLE PTR [RDI + RSI*8]

および Agner Fogの最適化アセンブリマニュアル は、[base+index]アドレス指定を使用したマイクロオペレーションフュージョンの例も示しています。たとえば、セクション12.2「Core2の同じ例」を参照してください。それで、正解は何ですか?

46
Z boson

デコーダーとuop-cacheでは、アドレッシングモードはマイクロフュージョンに影響を与えません(ただし、即値オペランドを持つ命令はRIP相対アドレッシングモードをマイクロフューズできません)。

ただし、uopとアドレッシングモードの組み合わせによっては、ROB(アウトオブオーダーコア)でマイクロフュージョンを維持できないため、Intel SnBファミリCPUは、問題が発生する前のある時点で、必要に応じて「ラミネート解除」されます。ステージの名前を変更します。問題のスループット、および順序が正しくないウィンドウサイズ(ROBサイズ)の場合、ラミネーション解除後の融合ドメインuopカウントが重要です。

Intelの最適化マニュアルセクション2.5.2.4:Micro-op Queue and the Loop Stream Detector(LSD)で、Sandybridgeのラミネーション解除について説明していますが、 t以降のマイクロアーキテクチャの変更について説明します。

UPDATE:Intelのマニュアルには、Haswellのラミネート解除について説明する詳細なセクションがあります。セクション2.4.5剥離を参照してください。また、SandyBridgeの簡単な説明はセクション2.5.2.4にあります。


ルール、SnB、HSW、SKLの実験からわかるように:

  • SnB(そして私はIvBも想定しています):インデックス付きアドレッシングモードは常にラミネートされておらず、他のモードはマイクロフュージョンのままです。 IACAは(ほとんど?)正しいです。
  • HSW、SKL:これらは、2つのオペランドがあり、dstレジスタを読み取り-変更-書き込みとして扱う場合にのみ、インデックス付きALU命令をマイクロヒューズで保持します。ここで、「オペランド」にはフラグが含まれています。これは、adccmovがマイクロヒューズしないことを意味します。ほとんどのVEXエンコード命令も、一般に3つのオペランドがあるため、融合しません(したがって、_paddb xmm0, [rdi+rbx]_は融合しますが、_vpaddb xmm0, xmm0, [rdi+rbx]_は融合しません)。最後に、_pabsb xmm0, [rax + rbx]_などの最初のオペランドが書き込み専用である場合がある2オペランド命令も、融合しません。 IACAは間違っており、SnBルールを適用しています。

関連:ポート7(Haswell以降)の専用ストアアドレスユニットが処理できるのは、単純な(インデックス付けされていない)アドレッシングモードだけなので、ストアのインデックス付きアドレッシングモードを回避することは依然として役立つ可能性があります。 (これに対する良いトリックは、単一のレジスタでdstをアドレス指定することですが、srcはdst+(initial_src-initial_dst)でアドレス指定します。その後、ループ内でdstレジスタをインクリメントするだけで済みます。)

一部の命令は(デコーダー/ uopキャッシュ内であっても)マイクロヒューズをまったく行わないことに注意してください。例えば_shufps xmm, [mem], imm8_または_vinsertf128 ymm, ymm, [mem], imm8_は、レジスタソースバージョンが1 uopしかない場合でも、Skylakeを介したSnBでは常に2uopです。これは、imm8制御オペランドと通常のdest/src1、src2レジスタ/メモリオペランドを使用する命令で一般的ですが、他にもいくつかの場合があります。例えば_PSRLW/D/Q xmm,[mem]_(メモリオペランドからのベクトルシフトカウント)はマイクロヒューズを行わず、PMULLDも行いません。

参照 Agner Fogのブログのこの投稿 多くのレジスタを読み取るときのHSW/SKLの問題スループット制限に関する議論:インデックス付きアドレッシングモードを使用した多くのマイクロフュージョンレジスタオペランドが少ない同じ命令と比較して、速度が低下する可能性があります。1レジスタアドレッシングモードとイミディエート。原因はまだわかりませんが、何らかのレジスタ読み取り制限があると思われます。 、おそらくPRFから多くのコールドレジスタを読み取ることに関連しています。


テストケース、実際の測定値からの数値:デコーダー内のこれらすべてのマイクロヒューズ、AFAIK、後でラミネートされていない場合でも。

_# store
mov        [rax], edi  SnB/HSW/SKL: 1 fused-domain, 2 unfused.  The store-address uop can run on port7.
mov    [rax+rsi], edi  SnB: unlaminated.  HSW/SKL: stays micro-fused.  (The store-address can't use port7, though).
mov [buf +rax*4], edi  SnB: unlaminated.  HSW/SKL: stays micro-fused.

# normal ALU stuff
add    edx, [rsp+rsi]  SnB: unlaminated.  HSW/SKL: stays micro-fused.  
# I assume the majority of traditional/normal ALU insns are like add
_

HSW/SKLがラミネート解除する必要がある可能性のある3つの入力命令

_vfmadd213ps xmm0,xmm0,[rel buf] HSW/SKL: stays micro-fused: 1 fused, 2 unfused.
vfmadd213ps xmm0,xmm0,[rdi]     HSW/SKL: stays micro-fused
vfmadd213ps xmm0,xmm0,[0+rdi*4] HSW/SKL: un-laminated: 2 uops in fused & unfused-domains.
     (So indexed addressing mode is still the condition for HSW/SKL, same as documented by Intel for SnB)

# no idea why this one-source BMI2 instruction is unlaminated
# It's different from ADD in that its destination is write-only (and it uses a VEX encoding)
blsi   edi, [rdi]       HSW/SKL: 1 fused-domain, 2 unfused.
blsi   edi, [rdi+rsi]   HSW/SKL: 2 fused & unfused-domain.


adc         eax, [rdi] same as cmov r, [rdi]
cmove       ebx, [rdi]   Stays micro-fused.  (SnB?)/HSW: 2 fused-domain, 3 unfused domain.  
                         SKL: 1 fused-domain, 2 unfused.

# I haven't confirmed that this micro-fuses in the decoders, but I'm assuming it does since a one-register addressing mode does.

adc   eax, [rdi+rsi] same as cmov r, [rdi+rsi]
cmove ebx, [rdi+rax]  SnB: untested, probably 3 fused&unfused-domain.
                      HSW: un-laminated to 3 fused&unfused-domain.  
                      SKL: un-laminated to 2 fused&unfused-domain.
_

Broadwellはadc/cmovのSkylakeのように動作すると思います。

HSWがメモリソースADCとCMOVをラミネート解除するのは奇妙です。たぶん、IntelはHaswellの出荷期限に達する前に、SnBからそれを変更することに取り掛かっていなかったのだろう。

Agnerのinsnテーブルには、_cmovcc r,m_と_adc r,m_はHSW/SKLでまったくマイクロヒューズしないと書かれていますが、それは私の実験とは一致しません。私が測定しているサイクルカウントは、4 uops /クロック発行のボトルネックの場合、融合ドメインuop発行カウントと一致します。うまくいけば、彼はそれを再確認し、テーブルを修正するでしょう。

メモリ宛先整数ALU

_add        [rdi], eax  SnB: untested (Agner says 2 fused-domain, 4 unfused-domain (load + ALU  + store-address + store-data)
                       HSW/SKL: 2 fused-domain, 4 unfused.
add    [rdi+rsi], eax  SnB: untested, probably 4 fused & unfused-domain
                       HSW/SKL: 3 fused-domain, 4 unfused.  (I don't know which uop stays fused).
                  HSW: About 0.95 cycles extra store-forwarding latency vs. [rdi] for the same address used repeatedly.  (6.98c per iter, up from 6.04c for [rdi])
                  SKL: 0.02c extra latency (5.45c per iter, up from 5.43c for [rdi]), again in a tiny loop with dec ecx/jnz


adc     [rdi], eax      SnB: untested
                        HSW: 4 fused-domain, 6 unfused-domain.  (same-address throughput 7.23c with dec, 7.19c with sub ecx,1)
                        SKL: 4 fused-domain, 6 unfused-domain.  (same-address throughput ~5.25c with dec, 5.28c with sub)
adc     [rdi+rsi], eax  SnB: untested
                        HSW: 5 fused-domain, 6 unfused-domain.  (same-address throughput = 7.03c)
                        SKL: 5 fused-domain, 6 unfused-domain.  (same-address throughput = ~5.4c with sub ecx,1 for the loop branch, or 5.23c with dec ecx for the loop branch.)
_

はい、そうです、_adc [rdi],eax_/_dec ecx_/jnzは、代わりにaddを使用した同じループよりも速く実行されます SKLではadc。明らかにSKLは同じアドレスの繰り返しの書き換えを好まないため、異なるアドレスを使用しようとはしませんでした(ストア転送の待ち時間が予想よりも長くなります。 同じアドレスへの繰り返しのストア/リロードが遅いことに関するこの投稿も参照してください) SKLで予想されるよりも

メモリ宛先adcは非常に多くのuopsです。これは、Intel P6ファミリ(および明らかにSnBファミリ)がマルチuop命令のすべてのuopに対して同じTLBエントリを保持できないため、 この問題を回避するには、追加のuopが必要です。ロードと追加が完了し、ストアに障害が発生したが、CFが​​既に更新されているため、insnを再起動できない場合 。 Andy Glew(@krazyglew)からの興味深い一連のコメント。

おそらく、デコーダーでの融合とラミネーション解除により、_adc [base+idx], reg_の単一の命令から4つ以上の融合ドメインuopsを生成するために マイクロコードROMが必要 から私たちを救うことができます。


SnBファミリーがラミネートを解除する理由

Sandybridgeは、内部uop形式を簡素化して、電力とトランジスタを節約しました(ROBに入力/出力データを保持する代わりに、物理レジスタファイルの使用に大きな変更を加えました)。 SnBファミリCPUは、アウトオブオーダーコアの融合ドメインuopに対して限られた数の入力レジスタのみを許可します。 SnB/IvBの場合、その制限は2入力(フラグを含む)です。 HSW以降の場合、uopの制限は3入力です。メモリ宛先addadcがそれを最大限に活用しているかどうか、またはIntelがいくつかの指示でHaswellをドアから出さなければならなかったかどうかはわかりません

Nehalem以前では、非融合ドメインuopに対して2入力の制限がありますが、ROBは、3つの入力レジスタ(非メモリレジスタのオペランド、ベース、およびインデックス)でマイクロ融合uopを追跡できるようです。


したがって、インデックス付きストアとALU + load命令は、効率的にデコードでき(グループの最初のuopである必要はありません)、uopキャッシュに余分なスペースを取りませんが、それ以外の場合、マイクロフュージョンの利点はチューニングのために本質的に失われますタイトなループ。 「ラミネーション解除」は、4-fused-domain-uops-per-cycleの発行/リタイア幅のアウトオブオーダーコアの前に発生します。融合ドメインパフォーマンスカウンター(uops_issued/uops_retired.retire_slots)は、ラミネーション解除後に融合ドメインuopsをカウントします。

Intelによる名前変更者の説明(セクション2.3.3.1:名前変更者)は、実際にラミネート解除を行うのは問題/名前変更の段階であることを示しているため、ラミネート解除を目的としたuopsは引き続き28/56/64融合ドメインuop発行キュー/ループバッファー(別名IDQ)でマイクロ融合されます。

TODO:これをテストします。ループバッファにかろうじて収まるはずのループを作成します。発行前にuopの1つがラミネート解除されるように何かを変更し、それがまだループバッファー(LSD)から実行されているかどうか、またはすべてのuopがuopキャッシュ(DSB)から再フェッチされているかどうかを確認します。 uopsがどこから来たのかを追跡するためのパフォーマンスカウンターがあるので、これは簡単なはずです。

より難しいTODO:uopキャッシュからの読み取りとIDQへの追加の間にラミネーション解除が発生した場合は、uopキャッシュの帯域幅を削減できるかどうかをテストします。または、問題の段階でラミネート解除が発生した場合、問題のスループットに悪影響を与える可能性がありますか? (つまり、最初の4を発行した後に残ったuopsをどのように処理しますか。)


(LUTコードの調整に基づく推測については、この回答の以前のバージョンを参照してください。vpgatherddに関する注記はpinsrwループの約1.7倍です。)

SnBの実験的テスト

HSW/SKL数は、i5-4210Uおよびi7-6700kで測定されました。どちらもHTが有効になっています(ただし、システムはアイドル状態であるため、スレッドはコア全体をそれ自体に持っていました)。 _ocperf.py_を使用して、SKL上のLinux4.10とHSW上のLinux4.8の両方のシステムで同じ静的バイナリを実行しました。 (HSWラップトップは私のSKLデスクトップの/ homeをNFSマウントしました。)

SnB数は、動作しなくなったi5-2500kで、以下に説明するように測定されました。

Uopsとサイクルのパフォーマンスカウンターでテストすることで確認されました。

Linuxのperfコマンドで使用するために Intel SandybridgeのPMUイベントの表 を見つけました。 (残念ながら、標準のperfには、uopsなどのほとんどのハードウェア固有のPMUイベントの記号名がありません。) 最近の回答 に使用しました。

_ocperf.py_は、これらのuarch固有のPMUイベントの記号名を提供します なので、テーブルを検索する必要はありません。また、同じシンボリック名が複数のアーチで機能します。私が最初にこの答えを書いたとき、私はそれを知りませんでした。

Uopマイクロフュージョンをテストするために、IntelCPUのサイクルあたり4uopsのフューズドドメイン制限でボトルネックになっているテストプログラムを作成しました。実行ポートの競合を回避するために、これらのuopの多くはnopsであり、実行ポートにディスパッチされないことを除いて、uopキャッシュに残り、他のuopと同じようにパイプラインを通過します。 。 (_xor x, same_、または削除された移動は同じになります。)

テストプログラム:_yasm -f elf64 uop-test.s && ld uop-test.o -o uop-test_

_GLOBAL _start
_start:
    xor eax, eax
    xor ebx, ebx
    xor edx, edx
    xor edi, edi
    lea rsi, [rel mydata]   ; load pointer
    mov ecx, 10000000
    cmp dword [rsp], 2      ; argc >= 2
    jge .loop_2reg

ALIGN 32
.loop_1reg:
    or eax, [rsi + 0]
    or ebx, [rsi + 4]
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_1reg
;   xchg r8, r9     ; no effect on flags; decided to use NOPs instead

    jmp .out

ALIGN 32
.loop_2reg:
    or eax, [rsi + 0 + rdi]
    or ebx, [rsi + 4 + rdi]
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_2reg

.out:
    xor edi, edi
    mov eax, 231    ;  exit(0)
    syscall

SECTION .rodata
mydata:
db 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
_

また、ループが4 uopsの倍数でない場合、ループバッファーからのuop帯域幅はサイクルごとに一定の4ではないこともわかりました。 (つまり、abcabc、...; abcabcab、...ではありません)。 Agner Fogのmicroarchドキュメントは、残念ながら、ループバッファのこの制限について明確ではありませんでした。 HSW/SKLの詳細については、 opカウントがプロセッサ幅の倍数ではないループを実行するとパフォーマンスが低下しますか? を参照してください。この場合、SnBはHSWよりも悪い可能性がありますが、確信がなく、SnBハードウェアがまだ機能していません。

マクロ融合(比較と分岐)を画像から除外したかったので、nopと分岐の間にdecsを使用しました。 4 nopsを使用したので、マイクロフュージョンを使用すると、ループは8 uopsになり、1回の反復ごとに2サイクルでパイプラインを埋めます。

ループの他のバージョンでは、マイクロヒューズを使用しない2オペランドアドレッシングモードを使用すると、ループは10個の融合ドメインuopsになり、3サイクルで実行されます。

3.3GHz Intel Sandybridge(i5 2500k)の結果。テスト前にcpufreqガバナーにクロック速度を上げるために何もしませんでした。サイクルは、メモリと対話していないときのサイクルです。 16進数で入力する必要のあるパフォーマンスカウンターイベントの注釈を追加しました。

1-regアドレッシングモードのテスト:コマンドライン引数なし

_$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test

Performance counter stats for './uop-test':

     11.489620      task-clock (msec)         #    0.961 CPUs utilized
    20,288,530      cycles                    #    1.766 GHz
    80,082,993      instructions              #    3.95  insns per cycle
                                              #    0.00  stalled cycles per insn
    60,190,182      r1b1  ; UOPS_DISPATCHED: (unfused-domain.  1->umask 02 -> uops sent to execution ports from this thread)
    80,203,853      r10e  ; UOPS_ISSUED: fused-domain
    80,118,315      r2c2  ; UOPS_RETIRED: retirement slots used (fused-domain)
   100,136,097      r1c2  ; UOPS_RETIRED: ALL (unfused-domain)
       220,440      stalled-cycles-frontend   #    1.09% frontend cycles idle
       193,887      stalled-cycles-backend    #    0.96% backend  cycles idle

   0.011949917 seconds time elapsed
_

2-regアドレッシングモードのテスト:コマンドラインargを使用

_$ perf stat -e task-clock,cycles,instructions,r1b1,r10e,r2c2,r1c2,stalled-cycles-frontend,stalled-cycles-backend ./uop-test x

 Performance counter stats for './uop-test x':

         18.756134      task-clock (msec)         #    0.981 CPUs utilized
        30,377,306      cycles                    #    1.620 GHz
        80,105,553      instructions              #    2.64  insns per cycle
                                                  #    0.01  stalled cycles per insn
        60,218,693      r1b1  ; UOPS_DISPATCHED: (unfused-domain.  1->umask 02 -> uops sent to execution ports from this thread)
       100,224,654      r10e  ; UOPS_ISSUED: fused-domain
       100,148,591      r2c2  ; UOPS_RETIRED: retirement slots used (fused-domain)
       100,172,151      r1c2  ; UOPS_RETIRED: ALL (unfused-domain)
           307,712      stalled-cycles-frontend   #    1.01% frontend cycles idle
         1,100,168      stalled-cycles-backend    #    3.62% backend  cycles idle

       0.019114911 seconds time elapsed
_

したがって、両方のバージョンで80Mの命令が実行され、実行ポートに60Mのuopsがディスパッチされました。 (メモリソースを使用したorは、パイプラインの残りの部分でマイクロフュージョンされているかどうかに関係なく、orのALUと、ロードのロードポートにディスパッチします。nopは実行ポートにまったくディスパッチしません。)同様に、ここでは4,000万のnopsがカウントされるため、どちらのバージョンも1億の非融合ドメインuopsを廃止します。

違いは、fused-domainのカウンターにあります。

  1. 1レジスタアドレスバージョンは、8000万の融合ドメインuopsのみを発行および廃止します。これは、命令の数と同じです。各insnは1つの融合ドメインuopに変わります。
  2. 2レジスタアドレスバージョンは、1億の融合ドメインuopsを発行します。これは、融合されていないドメインのuopsの数と同じであり、マイクロ融合が発生しなかったことを示しています。

ブランチの予測ミスにより、発行後、リタイア前にuopsがキャンセルされた場合にのみ、UOPS_ISSUEDとUOPS_RETIRED(リタイアメントスロットが使用されます)の違いが見られると思います。

そして最後に、パフォーマンスへの影響は現実的です。非融合バージョンは1.5倍のクロックサイクルを要しました。これは、ほとんどの実際のケースと比較してパフォーマンスの違いを誇張しています。ループは整数サイクルで実行する必要があり、2つの追加のuopsが2から3にプッシュします。多くの場合、追加の2つの融合ドメインuopsはあまり違いがありません。また、コードが4-fused-domain-uops-per-cycle以外の何かによってボトルネックになっている場合、潜在的に違いはありません。

それでも、ループ内で多くのメモリ参照を行うコードは、_[base + immediate offset]_アドレッシングを使用する代わりに、単純な_[base + index]_アドレッシングで使用される複数のポインターを適度に展開およびインクリメントして実装すると、より高速になる可能性があります。モード。

さらなるもの

RIP-即時のマイクロヒューズはできません。 Agner Fogのテストによると、これはデコーダー/ uop-cacheでも当てはまるため、(ラミネートされていないのではなく)そもそも融合することはありません。

IACAはこれを誤解し、これらのマイクロヒューズの両方が次のように主張しています。

_cmp dword  [abs mydata], 0x1b   ; fused counters != unfused counters (micro-fusion happened, and wasn't un-laminated).  Uses 2 entries in the uop-cache, according to Agner Fog's testing
cmp dword  [rel mydata], 0x1b   ; fused counters ~= unfused counters (micro-fusion didn't happen)
_

RIP-relは、即時がない場合にマイクロヒューズを実行します(そして融合を維持します)。

_or  eax, dword  [rel mydata]    ; fused counters != unfused counters, i.e. micro-fusion happens
_

マイクロフュージョンは命令のレイテンシーを増加させません。他の入力の準備が整う前に、負荷が発生する可能性があります。

_ALIGN 32
.dep_Fuse:
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    or eax, [rsi + 0]
    dec ecx
    jg .dep_Fuse
_

eax depチェーンがあるため、このループは反復ごとに5サイクルで実行されます。 _or eax, [rsi + 0 + rdi]_または_mov ebx, [rsi + 0 + rdi] / or eax, ebx_のシーケンスよりも速くはありません。 (unfusedバージョンとmovバージョンはどちらも同じ数のuopsを実行します。)スケジューリング/ depチェックはunfused-domainで行われます。新しく発行されたuopsは、ROBだけでなくスケジューラー(別名リザベーションステーション(RS))にも入ります。それらは、ディスパッチ(実行ユニットに送信されることもあります)後にスケジューラーを離れますが、リタイアするまでROBに留まります。したがって、ロードレイテンシを非表示にするためのアウトオブオーダーウィンドウは、少なくともスケジューラサイズです( Sandybridgeでは54のunfused-domain uops、Haswellでは6 、Skylakeでは97)。

マイクロフュージョンには、ベースとオフセットが同じレジスタであるためのショートカットがありません。 _or eax, [mydata + rdi+4*rdi]_(rdiがゼロになっている)のループは、_or eax, [rsi+rdi]_のループと同じ数のuopsとサイクルを実行します。このアドレッシングモードは、固定アドレスから始まる奇数サイズの構造体の配列を反復処理するために使用できます。これはおそらくほとんどのプログラムで使用されることはないので、Intelがこの特殊なケースの2レジスタモードをマイクロヒューズに許可することにトランジスタを費やさなかったのは当然のことです。 (そしてIntelは、レジスターとスケールファクターが必要な場合、とにかく「インデックス付きアドレッシングモード」としてそれを文書化します。)


cmp/jccまたはdec/jccのマクロ融合 unfused-domainでも単一のuopとして残るuopを作成します。 _dec / nop / jge_は引き続き単一サイクルで実行できますが、1つではなく3つのuopsです。

37
Peter Cordes

注:私がこの回答を書いたので、PeterはHaswellとSkylakeもテストし、その結果を上記の受け入れられた回答に統合しました(特に、以下のSkylakeに起因する改善のほとんどは実際にHaswellに登場)。 CPU全体の動作の概要については、 その回答 が表示されます。この回答(間違いではありませんが)は、ほとんど歴史的に興味深いものです。

私のテストでは、少なくともSkylake1、Sandybridgeとは異なり、プロセッサは複雑なアドレッシングモードでも完全に融合します。

つまり、1-argおよび2-argバージョンのPeterによって上記に投稿されたコードは、同じサイクル数で実行され、同じ数のuopsがディスパッチされてリタイアされます。

私の結果:

./uop-testのパフォーマンスカウンター統計:

     23.718772      task-clock (msec)         #    0.973 CPUs utilized          
    20,642,233      cycles                    #    0.870 GHz                    
    80,111,957      instructions              #    3.88  insns per cycle        
    60,253,831      uops_executed_thread      # 2540.344 M/sec                  
    80,295,685      uops_issued_any           # 3385.322 M/sec                  
    80,176,940      uops_retired_retire_slots # 3380.316 M/sec                  

   0.024376698 seconds time elapsed

./uop-test xのパフォーマンスカウンター統計:

     13.532440      task-clock (msec)         #    0.967 CPUs utilized          
    21,592,044      cycles                    #    1.596 GHz                    
    80,073,676      instructions              #    3.71  insns per cycle        
    60,144,749      uops_executed_thread      # 4444.487 M/sec                  
    80,162,360      uops_issued_any           # 5923.718 M/sec                  
    80,104,978      uops_retired_retire_slots # 5919.478 M/sec                  

   0.013997088 seconds time elapsed

./uop-test x xのパフォーマンスカウンター統計:

     16.672198      task-clock (msec)         #    0.981 CPUs utilized          
    27,056,453      cycles                    #    1.623 GHz                    
    80,083,140      instructions              #    2.96  insns per cycle        
    60,164,049      uops_executed_thread      # 3608.645 M/sec                  
   100,187,390      uops_issued_any           # 6009.249 M/sec                  
   100,118,409      uops_retired_retire_slots # 6005.112 M/sec                  

   0.016997874 seconds time elapsed

SkylakeでUOPS_RETIRED_ANY命令は見つかりませんでした。明らかに、融合ドメインである「リタイアされたスロット」の人だけでした。

最終テスト(uop-test x x)は、Peterが提案するバリアントであり、RIP相対cmpを即時で使用します。これは、マイクロフューズしないことが知られています。

.loop_riprel
    cmp dword [rel mydata], 1
    cmp dword [rel mydata], 2
    dec ecx
    nop
    nop
    nop
    nop
    jg .loop_riprel

結果は、サイクルごとに余分な2 uopsが、発行されたuopsとリタイアされたカウンターによって取得されることを示しています(したがって、テストでは、融合が発生するかどうかを区別できます)。

他のアーキテクチャでのさらなるテストは大歓迎です!コードを見つけることができます(上記のPeterからコピー) github内


[1] ...そしておそらくSkylakeとSandybridgeの間にある他のいくつかのアーキテクチャ。PeterはSBのみをテストし、私はSKLのみをテストしたからです。

10
BeeOnRope

Intel Sandy Bridge、Ivy Bridge、Haswell、Broadwellのテスト結果を確認しました。 Skylakeでのテストにはまだアクセスできません。結果は次のとおりです。

  • 2つのレジスタアドレス指定と3つの入力依存関係を持つ命令は大丈夫です。 32ビット(または2 * 16ビット)以下のデータが含まれている限り、マイクロオペレーションキャッシュのエントリは1つだけです。
  • HaswellとBroadwellで融合された乗算と加算の命令を使用して、4つの入力依存関係を持つ命令を作成することができます。これらの命令は引き続き単一のマイクロオペレーションに融合し、マイクロオペレーションキャッシュ内のエントリを1つだけ取得します。
  • 32ビットを超えるデータ(たとえば、32ビットアドレスと8ビットイミディエートデータ)を含む命令は引き続き融合できますが、マイクロオペレーションキャッシュ内の2つのエントリを使用します(32ビットを16ビット符号付き整数に圧縮できる場合を除く)
  • オフセットとイミディエート定数の両方が非常に小さい場合でも、リップ相対アドレス指定とイミディエート定数を使用した命令は融合していません。
  • テストした4台のマシンですべての結果は同じです。
  • テストは、マイクロオペレーションキャッシュに収まるほど十分に小さいループのパフォーマンス監視カウンターを使用して、独自のテストプログラムで実行されました。

結果は他の要因による可能性があります。私はIACAを使おうとはしていません。

6
A Fog

Uopキャッシュのない古いIntelプロセッサは融合を実行できるため、これがuopキャッシュの欠点である可能性があります。今はこれをテストする時間がありませんが、次回更新するときにuopfusionのテストを追加します テストスクリプト 。 FMAの指示を試しましたか?これらは、融合されていないuopで3つの入力依存関係を許可する唯一の命令です。

6
A Fog