RMMAによる内部解析 - Decode Bandwidth(グラフ92~106)

さて、ここからはRMMAを利用して、もう少しだけ内部構造を見てみたいと思う。なお評価キットのところで説明した通り、RMMAのみWindows 7の環境で測定を行っている。

まずはDecode Bandwidthからである。前にも説明したと思うが、このテストは連続的に同じ命令を延々と実行させ、その実行時間を測定することで、デコード部のスループットを見ようというものだ。15種類の命令が用意されており

  • NOP(1):nop
  • SUB(2):sub eax, eax
  • XOR(2):xor eax, eax
  • TEST(2):test eax, eax
  • XOR/ADD(4):xor eax, eax; add eax, eax
  • CMP #1(2):cmp eax, eax
  • CMP #2(4):cmp ax, 0x00
  • CMP #3(6):cmp eax, 0x00000000
  • CMP #4(6):cmp eax, 0x0000007f
  • CMP #5(6):cmp eax, 0x00007fff
  • CMP #6(6):cmp eax, 0x7fffffff
  • Prefixed CMP #1(8): cmp eax, 0x00000000
  • Prefixed CMP #2(8): cmp eax, 0x0000007f
  • Prefixed CMP #3(8): cmp eax, 0x00007fff
  • Prefixed CMP #4(8): cmp eax, 0x7fffffff

となっている。ここで()内はトータルの命令長である。

結果を見てみるとなかなか楽しい。NOP(グラフ92)で、いきなりピークが5Bytes/cycleになっており、5命令/cycleで実行されることになっている。実のところこれはOp Cacheのトリックによるものだと思われる。

こちらにもあるように、x86のDecodeそのものは4命令/cycleであるが、MicroOp Queueそのものは6 micro-op dispatchが可能(Photo22)と説明されている。

つまり、Decode→Micro-op Queue、あるいはOp Cache→Micro-op Queue自身は6 micro-op/cycleとなっている可能性が高い。そしておそらくこの5bytes/cycleの間、命令はOp Cacheから供給されていると考えられる。

どうやってこれを処理するかだが、Zenに限らず最近のCPUはNOP命令をわざわざ実行ユニットに投入したりせず、スケジューラの中でNOPに相当する部分を空白にして、Retireさせて終わりである。NOPだから何もしないわけで、この方が消費電力効率が良い。

話を戻すと、Photo22を見るとDispatchが最大6、Retireが最大8になっているから、理論上は同時に6命令のNOPを処理できても不思議ではない。もっとも6なり8なりは、Integer 4+AGU 2という組み合わせを前提としているから、本当に5以上の命令がDispatchできるのかは謎だが、結果を見る限り短時間であれば処理可能になっているようだ。ただこれが可能なのは2KB未満程度で、そこから漸減していって10KBあたりでは4Bytes/cycleになることから、ここがOp Cacheの容量に近いように思われる。

8MBを超えると急に落ちるのは、まさにこのあたりでL3 Missが発生するからだ。これそのものは不思議ではない(実際にはL3の容量は16MBだが、SMT環境で16MBを1 Threadで使いきれる設定にはしていないようだ)。

さて、以下同じ調子で見て行くと、SUB(グラフ93)、XOR(グラフ94)、TEST(グラフ95)、XOR/ADD(グラフ96)とほぼ同じグラフである。100KBちょい過ぎで波形が乱れ、500KBあたりまでこれが続くのは、このあたりでL2/L3の排他制御の影響が多少あるのではないかと思う。ただここまではCore i7-7700Kと全く同じカーブになっており、かなり優秀である。

またCMP #1(グラフ97)ではスムーズなのが、CMP #2(グラフ98)だと大分乱れ始めるのは、排他制御の影響が無視できなくなるためだろう。

命令サイズが大きくなるCMP #3~#6(グラフ99~102)ではOp Cacheで4命令/Cycleを維持できるのは7KBあたりまでで、その後は16Bytes/cycleと割り切れない数字になっている。これはL1 I-Cacheの帯域に制限されるためだろう。

その後32KBを過ぎるとL2 Accessになるが、100KB近くになるとL3との排他制御の関係でLatencyが不規則に増え、帯域もちょっと落ちたりする。しかし、基本512KBを過ぎるとL3 Accessになる関係で13Bytes/cycle程度を維持しており、これはわかりやすい。

またPrefixed CMP(グラフ103~106)も動き方はほぼ同じであり、Prefixがあっても最大32Bytes/cycle(つまり4命令/cycle)を7KBあたりまで維持できているのが分かる。

ここから察するに、Op Cacheのサイズは最低でも2K Ops程度はありそうだ。特に4命令/cycleを維持できなくなるのがRYZEN 7 1800XとCore i7-7700K、Core i7-6950Xでみんな同じ位置になっていることから、Op Cacheの容量もほぼ同じ程度にそろえて来たように思える。

これは特にソフトウェアの最適化を考える場合に重要で、このサイズが違ってくると最適化の方法論がちょっと変わってくる。すでに世の中に多く出回っている、IntelのMicroOp Cacheに最適化されたプログラムを同じように高速に動かすためには、容量を同じものにしておくのが重要と判断した可能性もありそうだ。