イベント
[GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」
ただ,Ryzenが,あらゆる点でIntelの競合製品を上回るというわけでもなく,4Gamerのレビューでも「メモリ周りの弱点があり,そこでは最適化が不足しているのではないか」という考察が出ている。
RyzenはAMD史上最も広範に拡張命令をサポートする
まずは,Ryzenがサポートする命令セットの話題から。
Ryzenのマイクロアーキテクチャに関する話の中で,Mitchell氏はRyzenがサポートする命令セットの一例を示した。それによるとRyzenは,第7世代のAPU「Bristol Ridge」でもサポートしていなかった,多数のIntel製拡張命令セットに対応したという。たとえば,加算を連続して行うことを考慮してフラグの扱いを変えた加算命令「ADX」は,IntelがBroadwell世代で導入したものだが,AMDもRyzenでこれをサポートした。
Intelの拡張命令に対応した一方で,Ryzenは,AMD固有の拡張命令である「FMA4」「TBM」「XOP」をサポートしない。「AMDのCPUでしか使えない」という理由で,ソフトウェアデベロッパからの支持を集められなかったということなのだろう。Mitchell氏によると,これらの命令セットはサポートが「打ち切られた」とのことなので,今後のAMD製CPUでもサポートされることはないはずだ。ユーザー(≒開発者)の側に立った拡張命令サポートポリシー変更と言えそうである。
もう1つ,興味深かった話題が,Ryzenのキャッシュについての話だ。
Ryzenでは,コアごとにL1命令キャッシュを容量64KB,L1データキャッシュを容量32KB,L2キャッシュを容量512KB備えたうえで,4基を束ねて容量8MBの共有L3キャッシュとセットの「CPU Complex」(以下,CCX)とする構造を採用している。8コアモデルとなる「Ryzen 7」だと,2基のCCXを1つのダイに統合するので,L3キャッシュ容量は合計16MBという計算だ。
4Gamerのレビューでは,Ryzen 7 1800Xのキャッシュシステムについて,「競合と比べて帯域幅に優れる一方,遅延では劣る」という評価を与えたのだが,Mitchell氏は講演の中で,Ryzenのキャッシュは競合よりも極めて優れていると主張していた。
その根拠は,「L1,L2,L3キャッシュのいずれも,遅延が競合よりも小さい」(Mitchell氏)ためであるという。
Mitchell氏が示しているデータと,4Gamerのテスト結果が異なる理由は,正直分からない。4Gamerがテストに用いた「Sandra 2016 SP1」では,Ryzenのキャッシュシステムが持つ性能を正しく計測できていない,という可能性もある。ただ,これまでのCPUと同じく,Ryzenでも性能の計測には「RDPMC」という命令を使うそうなので,ベンチマークテスト側の問題ではないように思えるのも確かだ。
Ryzenで最高性能を得るための電源設定とは
Ryzenで注目された機能の1つに,「Extended Frequency Range」(以下,XFR)というものがある。これは,組み合わせるCPUクーラーの冷却能力が高く,
ところがMitchell氏は,従前の話と異なる説明をセッションで行った。いわく「Ryzen 7が最大ブーストクロックを超えて動作するには,8基あるCPUコアのうち,6基以上がC6ステートまで落ちることが条件」とのことだ。C6ステートとは,「Deep Power Down」とも呼ばれるアイドルステートのことで,つまり,複数のCPUコアにそこそこの負荷がかかり続けるゲームのようなアプリケーションの場合,XFRの動作条件を満たして最大ブーストクロックを超えるのは,かなり難しいということになる。
また,Ryzenの性能は,OS側の電源管理設定とも密接に関連しているという。Mitchell氏によると,Windows 10における「電源プラン」(Power plan,スライドではPower scheme)を『高パフォーマンス』に設定すると,全CPUコアのPステートが最高(※P0 state)に固定され,OSのスケジューラも「消費電力との兼ね合いを考慮せずに,全CPUコアを使用する」状態になるそうだ(※PステートとCステートは独立して制御されるので,「P0固定」であってもC6ステートに入ることはある)。また,CPUの負荷が低い状態のときに,止めても支障のないCPUコアを停止させる「Core Parking」機能も無効になるという。
一方,電源プランを「バランス」に設定すると,Core Parkingが有効になり,
ちなみに,Ryzen 7 1800XのレビューにあたってはAMDから「電源プランの設定を高パフォーマンスにするように」との指示があった。これは,Core Parkingによる遅延がベンチマークスコアに影響する可能性を排除するためというわけだ。
もっとも,これはAMD製CPUに限った話ではなく,Intel製CPUでも同様に起こりうる現象なので,その点では特別な話ではない。
DirectX 12であっても,マルチスレッド動作が必ずしも有利にはなるわけではない
講演の後半はRyzenへの最適化についての説明が行われたのだが,なかでも興味深かったのが,DirectX 12の話だ。内容の一部は,西川善司氏がレポートしたDirectX 12に関するセッションと被るが,要は,単純にDirectX 12を利用するだけでは,CPUの性能を引き出せないという話である。
DirectX 12はスレッド単位でGPUのキューを扱えるため,マルチスレッドの効率が上がると言われてきた。AMDもそうアピールしてきたが,Mitchellは「必ずしもそうではない」と言う。
下に示したスライドはMicrosoftのサンプルコードを使って,Draw Context――簡単に言えば「描画スレッド」――の数と性能をグラフ化したものだ。それによると,たとえばDraw数(=描画するオブジェクトの数)が「1025」の場合,Draw Context数は「2〜3」でピークになり,それ以上増やしても,逆に性能は低下してしまうのだという。
Draw数を10倍の「10250」にすると,Draw Context数を増やすことで性能は向上していくが,今度は「7」程度がピークとなり,それ以上増やしても性能は向上しないことが読み取れる。
余談だが,筆者が講演後にサンプルコードを見たところ,Draw Context数は,「stdafx.h」に「NumContexts」という定数で設定してあるのを確認できた。興味のある開発者は,いろいろと値を変えて実行してみると参考になるかもしれない。
さてMitchell氏は,をスライドに示されている数,「Draw数を300で割った値と,(論理)CPUコア数から1引いた値を比較して,小さいほうの値をDraw Context数として使うのがいい」という解決策を提示していた。ただ,これだとRyzen 7においてSimultaneous Mutli-Threading(SMT)が有効,かつDraw数が十分に大きい場合はDraw Context数として15が選択されるので,必ずしも最大性能が得られるわけではない。むしろ,Draw Context数を物理プロセッサ数−1で抑えたほうがいいのでは,という気もする。
また,氏の説明はあくまでもDirectX 12が対象で,DirectX 11以前でどうなのかは別の話だ。もっとも,Ryzenに限らず4コアを超えるCPUでゲームの性能があまり上がらないという,4Gamerの過去の検証結果とも整合する話題ではある。
そのほかにも細かな注意点としてMitchell氏は「キャッシュに事前にデータを先読みしておくprefetch系の命令は使わないほうがいい」ことを挙げていた。Ryzenの場合,CPUのキャッシュシステムが十分に高効率であるため,「下手にprefetchを使ってしまうと,ループの展開が行われない」(Mitchell氏)のだという。
簡単に説明しよう。例としてMitchell氏が挙げたサンプルコードは,回数が固定のループ処理を行うものだ。通常の場合,回数が固定されているループはコンパイラが展開して,キャッシュペナルティが起きやすい条件分岐命令の数を減らす。ところが,ここにprefetch命令を入れると,コンパイラがループを展開しなくなるので,条件分岐がループの回数分発生して遅くなるというわけである。
ちなみに,prefetch系の命令セットは,AMDが1998年にリリースしたCPU「K6-2」で初めて採用された拡張命令セット「3DNow!」に含まれていたものだった。それがIntel製CPUにも取り込まれて,Windows 8以降になると,Windowsが動作するために必須の命令セットになったという経緯がある。3DNow!の登場から19年経って,AMDが提案した命令セットを避けるよう指導するというのは面白い。
Mitchell氏によると,AMD製のプロファイラである「CodeXL」のRyzen対応版は,GDC 2017終了後,2週間以内にリリースするとのこと。Ryzenでは命令単位の解析が行えるようになるそうなので,興味がある開発者は,GitHubの関連ページをチェックしてみるといいだろう。
AMDのRyzen 公式Webページ
GDC 2017記事一覧
- 関連タイトル:
Ryzen(Zen,Zen+)
- この記事のURL: