◆Cache

まずZen 2コアの全貌がこちら(Photo02)である。基本的にはZenのものとよく似ているが

・Micro-Op Cacheが大容量化した(4K Micro-Op)
・分岐予測ユニットに、新たにTAGE(TAgged GEometric)が追加された
・AGEN(Address Generation Unit)が3つになった
・Floating Point Unitが256bit化した
・大容量L3キャッシュが搭載された

といった違いがある。これによって、概ねIPCは15%向上した、というのがAMDの説明である。この数字の検証は後で行うとするとして、もう少し詳細に見て行きたい。

  • Photo02: IntelのSkylake/Skylake-SPとか、IceLakeに実装のSunnyCoveに比べるとすっきりしているというか、やはりスクラッチから起こしただけの事はあって、まだ妙な構造になっていないのは流石である。まぁZen 2とか次のZen 3までの範囲は見据えてそもそもZenの設計はなされていると思うのだが。

まずL1/L2キャッシュ(Photo03)について。Zen世代との違いは、

・L1 I-Cacheを64KB/4-Wayから32KB/8-Wayに変更
・TLBの大容量化

が主なポイントである。このTLBであるが、RMMAによれば(Photo04,05)L2 D-TLBの容量が拡大されているのが判る。ではこのキャッシュ周りの性能を見てみたい。

  • Photo03: Faster Virtualization Based SecurityとHardware-enhanced Security mitigationsは後で話が出てくるが、SPECTRE V4への対応を思われる。

  • Photo04: Ryzen 7 1800X(初代Zenコア)のTLB構成。LP EntriesとかLP Associativityは、Big Page(Pageサイズが1GBとかの大きなもの)を利用する場合のエントリである。

  • Photo05: こちらはRyzen 9 3900Xのもの。L2 D-TLBが大容量化&構成変更(LP Assosiativityが2-wayから4-wayに変わった)が行われたのが判る。

  • グラフ1

  • グラフ2

  • グラフ3

まずグラフ1~3はSSE2を利用したD-Cache/RAMのBandwidthである。まずRead(グラフ1)。L1は32Bytes/cycleで、これはどのCPUも概ね同じである。ところがCore i9-9900KはL1 Miss/L2 Hitで24Bytes/cycle程度に落ちるのに、Ryzen 7 2700Xは30Bytes/cycle弱を、Ryzen 9 3900Xはほぼ32Bytes/cycleをそのまま維持しているのが判る。理論上はRyzen 7 2700XもL2が32Bytes/cycleになる筈だが、何かしらのボトルネックがあるようで、これがRyzen 9 3900Xでは解消されたようだ。L3の帯域はRyzenが22Bytes/cycle弱だが、Core i9-9900Kは13Bytes/cycle弱で、ここでの帯域の差はかなり大きい。

次がWrite(グラフ2)で、Ryzen系はL3 Missまでほぼ15~16Bytes/cycleを維持できるのに対し、Core i9-9900KはL2で13Bytes/cycle弱、L3で10Bytes/cycle強まで落ちている。

面白いのがCopy(グラフ3)で、まぁ当然RyzenがCore i9-9900Kを圧倒しているのだが、L2に関してのみRyzen 7 2700XがRyzen 9 3900Xを上回る帯域となっているのは面白い。AGUの使い方の問題であろうか? ただL3になると差が無いというか、Ryzen 9 3900Xの方が微妙に上回っているという結果になっている。

  • グラフ4

  • グラフ5

グラフ4・5はSandraのCache&Memory Bandwidthベンチマークである。グラフ4はMulti Threadでの結果なので、当然Ryzen 9 3900Xが飛び抜けて高い訳だが、同じ8 core/16 Thread同士で比較してもRyzen 7 3700XがCore i9-9900Kを上回るスコアになっており、Ryzen 7 2700Xを大幅に上回る性能となっている。これはSingle Thread性能(グラフ5)でも同じで、第3世代RyzenがほぼCore i9-9900Kと同じBandwidthをL2 Hitまで維持しており、L3も90GB/sec近い帯域を確保している(Core i9-9900KはL3が60GB/sec程度にすぎない)のと好対照である。Ryzen 7 2700XはL2以降ではそれなりの帯域だがL1の範囲での帯域がほぼ半減として良い。

ここから判るのは、L1 D-Cache~L3の範囲で確かに第3世代Ryzenは帯域が上がっている(特にL1⇔L2のInterconnectを改善したようだ)事と、L1/L2が32Bytes/cycleでアクセスできるという事だ。L3に関してはPhoto06の様に、基本的には32Bytes/cycleでアクセス可能ではあるのだが、L2/L3がVictim構成な事もあって多少オーバーヘッドがあるのか、それとも16MB L3がCCX外にあるためにオーバーヘッドがあるのかのどちらかであるが、数字を見る限りは前者の可能性の方が高い。

  • Photo06: "Double L1 load/store bandwidth"の結果がグラフ4・5のL1の帯域の差、と考えられる。

ちなみに第3世代RyzenはCPU Chipletの中身が(CCX+16MB L3)×2、という構成になるが、この16MB L3同士のアクセスはあまり高速ではないようだ。これはグラフ1・2共に16MBあたりでスパッと帯域が下がる事からも推察できる。まぁCCXを跨いでのアクセスは以前からも決して高速ではなかったのだが。ちなみにL1 I-CacheのBandwidthについては後程Decoderのところで確認する。

  • グラフ6

  • グラフ7

  • グラフ8

次がLatencyである。グラフ6~8がData Cacheに対するSequential/In-Page Random/Full RandomのRead Accessの際のLatencyであるが、まずはSequential(グラフ6)を見てみよう。L1に関しては第3世代Ryzenは4cycleで、これはRyzen 7 2700Xと変わらない。ところがL2は9~10cycle(Ryzen 7 2700Xは12cycle)、L3は20cycle(Ryzen 7 2700Xは31cycle)で、大幅にLatency短縮が実現されている。実際Core i9-9900Kと比べても遜色ないLatencyである。一般論として、容量が大きくなるとLatencyは大きくなりがちである。Tagの参照に時間が掛かるからだ。にも拘わらず、より容量の小さいCore i9-9900Kと同等のLatencyを実現しているのは、結構優秀と考えて良いと思うし、Ryzen 7 2700Xから大きく改良されたことも明白である。

In-Page Random(グラフ7)も大体同じ傾向で、こちらでは特にRyzen 7 2700Xが8MB以上で急激にLatencyを増やしている(Memory ControllerがうまくIn-Page Randomのハンドリングが出来ていない感じである)のもほぼ半減するなど、かなり第3世代Ryzenは優秀そうだ。それでもCore i9-9900Xよりは大きいが、Infinity Fabric経由でメモリコントローラが別ダイにあることを考慮すればこんなところではないか? という気もする。

Full Random(グラフ8)になると、もうLatencyの値はメモリアクセスになってしまっているのであまり意味が無い(これは本当はcycle値ではなくnsで見るべきで、こちらは後程Memory Controllerの部分で)。ただL2~L3までの範囲で言えば第3世代Ryzenは間違いなく最高速である。

  • グラフ9

  • グラフ10

  • グラフ11

ついでにI-CacheについてもLatencyを確認しておく。といっても、L2以降はUnifiedなので、実質L1 I-Cache(+Micro-Op Cache)の性能差ということになるのだが。まずSequential(グラフ9)だが、2KはMicro-Op Cacheが効いている(これはCore i9-9900Kも同じ)のでLatencyは1cycleだが、唯一Ryzen 7 2700Xのみ2cycleである。ただその先になると第3世代Ryzenも4cycleに増えているが、それでもRyzen 7 2700Xよりは1cycle小さい。

この傾向はIn-Page Random(グラフ10)、Full Random(グラフ11)も同じで、I-Cacheに関してはBandwidthこそ変わらないものの、Latencyを若干とは言え下げていることが確認できた。

  • グラフ12

次にTLB周りについて。まずグラフ12はI-TLB Sizeで、これはForward/Backward/Randomの3種類のアクセス方法で、最大1000エントリまでのアクセス時間を測定したものだが、ご覧の通りForward/Backward/Randomで全然Latencyが変わらなかったので、一つのグラフにまとめている(ちょっと個別の差が見にくいと思うが、アーキテクチャ別の傾向の違いは明確だと思う)。

まずサイズ。Core i9-9900Kの場合、L1 I-TLBが128 Entries/8-way、L2はUnifiedで1536 Entries/12-wayという構成で、それもあって128あたりまでは2cycle程度、Unified L2は20cycle未満といったあたりを維持しており、これに比べるとRyzen系はやや見劣りするのは事実であるが、それでもRyzen 9 3900Xでは400 Entries近くまでは10cycle程度を維持しており、その後の上がり方もRyzen 7 2700Xより大分マシである。

妙な山の形状をしているのはAssociativityのハンドリングの問題だと思うが、それを多少改善した感がある。ちなみにEntry数そのものはCoffee Lakeの方が多い様に見えるが、Ryzen系はL2 TLBはUnifiedではなくI-TLB/D-TLBが別々なので、トータルのEntry数はRyzen系の方が多い。

  • グラフ13

  • グラフ14

  • グラフ15

  • グラフ16

次いでグラフ13~16がI-TLB Associativityの確認である。本来このテストはFar JumpとNear Jumの両方があるのだが、実際に測定した結果で言えば全く傾向が変わらなかったので、今回はNear Jumpの方だけ掲載している。

まず64 Entriesまで(グラフ13~15)で言えば、Core i9-9900KはL1 I-TLBが8wayで、実際グラフを見るとこれが綺麗に反映されている。一方のRyzen系はL1 D-TLBが64 EntriesのFull Associativityであり、この結果Segment Countが64までの範囲は綺麗にL1にHitするためか、ほぼ一定である。「ほぼ」というのは、Ryzen 7 2700Xだとグラフ14とか15で途中からちょっとLatencyが増える傾向にあり(理由は不明)、これがRyzen 9 3900Xだと綺麗にフラットになっているあたり、細かな改良が施されてたと思われる。

128 Entries(グラフ16)になると流石に飽和するためか、Ryzen系はほぼL2 D-TLBアクセスになっており、こうなるとCore i9-9900Kに水をあけられる格好だが、現実問題こんな使い方になるケースはそれほど多いとも思えない。

  • グラフ17

併せてD-TLBの振る舞いも見ておきたい。まずグラフ17がD-TLB Sizeの結果で、先のグラフ12と比較するとかなり違う傾向になっている。Core i9-9900KもL1 D-TLBは4cycleほどでRyzen系と変わらず。L2 D-TLBで一番Latencyが少ないのがRyzen 9 3900Xで、Ryzen 7 2700Xと比較すると10cycleほど少ない。800 Entriesあたりから次第にLatencyの差は無くなってくるが、このあたりもRyzen 9 3900Xでは手が入っている事を伺わせる。

  • グラフ18

  • グラフ19

  • グラフ20

  • グラフ21

グラフ18~21はD-TLB Associativityだが、16 Entries~64 Entries(グラフ18~20)でRyzen 9 3900Xが完全にフラットなのは見事である。Ryzen 7 2700Xもかなりフラットとは言え、時折スパイクが出ているが、これがRyzen 9 3900Xで綺麗になくなっている。128 Entries(グラフ21)ではさすがにRyzen 9 3900XもL2で42cycleほどになっている(こうなるとEntry数が大きい方が総なめに時間が掛かるため、Latencyが増えるのは致し方ない)が、概してRyzen 2 2700Xから随分細かいところに手が入った、ということがD-TLBでも確認できたと思う。

なおZen 2では新たにキャッシュ管理命令が3種類追加された(Photo07)。具体的には

CLWB:任意のキャッシュラインをWritebackする機能。例えばNVDIMMを利用している環境で、そのNVDIMMを管理しているThreadが、システム中の任意のキャッシュの内容のWritebackを行える様になる(いちいちそのキャッシュを保持しているProcessor Coreに通知を行ってWritebackを行わせる必要が無い)
WBNOINVD:Cache中の全てのModified Page(というか、Modified line)をまとめてWritebackさせる。アクセラレータなどを使う際に、CPUが書き込んだ内容を全てメモリに反映させておかないと、正しくアクセラレータにデータを送り出せない可能性がある。こうした場合にこの命令を使う事で、キャッシュの内容を直ちにメモリに反映させられる。
QOS:名前の通り、キャッシュとメモリの間の通信にQoSの概念を導入するもの。

といったあたりになる。

  • Photo07: ついにキャッシュ制御にまでQoSの概念が入ったか、という感じではある。

なんでこんなものが追加されたか? といえば、恐らくはCCIXへの対応である。CCIXはドライバレスであり、CCIXの先に繋がったアクセラレータはホストのメモリをローカルメモリとして扱えるし、逆もまたしかりである。ドライバレスというのがこの場合問題で、これがドライバがあればデータのやり取りはドライバが介在していたから、ここでWritebackなどの処理を行えば同期が取れた訳だが、ドライバレスということは通常のメモリアクセスしか発生せず、そうなるとメモリとキャッシュの同期を取る手段がない。今回の命令群は、こうした状況に向けたものと思われる。QoSについても、CCIX経由でのメモリアクセスは当然通常のメモリアクセスより遅くなると思われるので、アクセラレータと通信したいThreadに優先的にアクセス帯域を割り当てないと効率が悪い。そうした事に対応したものと考えられる。