お気に入りタイトル/ワード

タイトル/ワード名(記事数)

最近記事を読んだタイトル/ワード

タイトル/ワード名(記事数)

LINEで4Gamerアカウントを登録
[GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」
特集記事一覧
注目のレビュー
注目のムービー

メディアパートナー

印刷2017/03/09 00:00

イベント

[GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

画像集 No.003のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」
 AMDの新世代CPU「Ryzen」が発売となり,秋葉原のPCパーツショップでは,売れ行きも好調なようだ。価格対性能比に優れる点も,さまざまなテストで明らかになってきた。
 ただ,Ryzenが,あらゆる点でIntelの競合製品を上回るというわけでもなく,4Gamerのレビューでも「メモリ周りの弱点があり,そこでは最適化が不足しているのではないか」という考察が出ている。

Ken Mitchell氏(Developer Technology Engineer,AMD)
画像集 No.002のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」
 GDC 2017の4日めにAMDが行った講演「Optimizing for AMD Ryzen CPU」はまさに,Ryzenに向けたソフトウェア最適化に関するものだ。講演を担当したのは,AMDのエンジニアであるKen Mitchell(ケン・ミッチェル)氏。氏はRyzenが採用する「Zen」マイクロアーキテクチャの概要説明も行ったが,そのあたりは西川善司氏による解説記事を参照してもらうとして,本稿では最適化周りに絞ってレポートしてみたい。


RyzenはAMD史上最も広範に拡張命令をサポートする


 まずは,Ryzenがサポートする命令セットの話題から。
 Ryzenのマイクロアーキテクチャに関する話の中で,Mitchell氏はRyzenがサポートする命令セットの一例を示した。それによるとRyzenは,第7世代のAPU「Bristol Ridge」でもサポートしていなかった,多数のIntel製拡張命令セットに対応したという。たとえば,加算を連続して行うことを考慮してフラグの扱いを変えた加算命令「ADX」は,IntelがBroadwell世代で導入したものだが,AMDもRyzenでこれをサポートした。

Ryzenおよび歴代のAMD製CPUが,拡張命令セットの何に対応/非対応であるかを示したスライド。緑色になっている命令が対応するもので,Ryzenは最も多くの拡張命令をサポートしていることが分かる
画像集 No.004のサムネイル画像 / [GDC 2017]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という計算だ。

4コアを1つのCPUモジュールとしたRyzenの基本構造。キャッシュの配置がよく分かる
画像集 No.005のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

 4Gamerのレビューでは,Ryzen 7 1800Xのキャッシュシステムについて,「競合と比べて帯域幅に優れる一方,遅延では劣る」という評価を与えたのだが,Mitchell氏は講演の中で,Ryzenのキャッシュは競合よりも極めて優れていると主張していた。
 その根拠は,「L1,L2,L3キャッシュのいずれも,遅延が競合よりも小さい」(Mitchell氏)ためであるという。

Ryzenにおける各キャッシュの容量と構成,遅延を示したスライド。最上段の「uop」はCPUコア内部のμOPキャッシュで,「L1D」はL1データキャッシュ,「L1I」はL1命令キャッシュのこと。L1の遅延は4クロックサイクルで,決して遅いわけではない
画像集 No.006のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

Ryzenと第6世代Coreプロセッサ(Skylake)のキャッシュ遅延を比較したスライド。L2では競合のほうが若干低遅延であるものの,L3はRyzenのほうが低遅延であるという
画像集 No.007のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

 Mitchell氏が示しているデータと,4Gamerのテスト結果が異なる理由は,正直分からない。4Gamerがテストに用いた「Sandra 2016 SP1」では,Ryzenのキャッシュシステムが持つ性能を正しく計測できていない,という可能性もある。ただ,これまでのCPUと同じく,Ryzenでも性能の計測には「RDPMC」という命令を使うそうなので,ベンチマークテスト側の問題ではないように思えるのも確かだ。

CPUのマイクロアーキテクチャと性能計測に使う命令の区分を示したスライド。「DF:Data Fabric」とは,メモリコントローラやI/Oを仲介する部分で,ここからCPUコア側(スライド左)における性能はRDPMC命令で監視できるという。ちなみに,メモリコントローラやI/Oハブコントローラについては,機密保持契約を結ばないと,情報を開示できないそうだ
画像集 No.008のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」


Ryzenで最高性能を得るための電源設定とは


 Ryzenで注目された機能の1つに,「Extended Frequency Range」(以下,XFR)というものがある。これは,組み合わせるCPUクーラーの冷却能力が高く,TDP(Thermal Design Power,熱設計消費電力)上の余裕がある場合には,仕様上の最大ブーストクロックを超えたクロックでの動作を可能とする機能であると,AMDは説明してきた。

 ところがMitchell氏は,従前の話と異なる説明をセッションで行った。いわく「Ryzen 7が最大ブーストクロックを超えて動作するには,8基あるCPUコアのうち,6基以上がC6ステートまで落ちることが条件」とのことだ。C6ステートとは,「Deep Power Down」とも呼ばれるアイドルステートのことで,つまり,複数のCPUコアにそこそこの負荷がかかり続けるゲームのようなアプリケーションの場合,XFRの動作条件を満たして最大ブーストクロックを超えるのは,かなり難しいということになる。

Ryzen 7 1800Xの動作クロックパターンを示したスライド。ACPI P-stateに,3.6GHz,3.2GHz,2.2GHzという3段階の動作クロックが,P3 state時には,C-stateに応じた4段階のブーストクロックがある。全コアがアクティブな状態におけるブーストクロックは3.7GHzで,ベースクロックより100MHz高いだけ。一般的なシングルスレッドアプリケーション実行時のブーストクロックは最大4.0GHzとなっている
画像集 No.009のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

 また,Ryzenの性能は,OS側の電源管理設定とも密接に関連しているという。Mitchell氏によると,Windows 10における「電源プラン」(Power plan,スライドではPower scheme)を『高パフォーマンス』に設定すると,全CPUコアのPステートが最高(※P0 state)に固定され,OSのスケジューラも「消費電力との兼ね合いを考慮せずに,全CPUコアを使用する」状態になるそうだ(※PステートとCステートは独立して制御されるので,「P0固定」であってもC6ステートに入ることはある)。また,CPUの負荷が低い状態のときに,止めても支障のないCPUコアを停止させる「Core Parking」機能も無効になるという。

コントロールパネルの「電源オプション」とRyzenにおける動作クロックの関係を列挙したスライド。スライドの右側にある,「Windows 10なら1ms以下の精度で動作クロックの制御ができる」という話は,Intel CPUでも同様である
画像集 No.010のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

 一方,電源プランを「バランス」に設定すると,Core Parkingが有効になり,Core Parking状態のCPUコアを避けて電力効率を上げるようにOSのスケジューラは挙動を変える。この状態だと,CPUにかかる負荷が高くなってCore Parking状態を解除しようとしても,「トップスピードに切り替わるのには30msほどかかる」と,Mitchell氏は指摘していた。
 ちなみに,Ryzen 7 1800XのレビューにあたってはAMDから「電源プランの設定を高パフォーマンスにするように」との指示があった。これは,Core Parkingによる遅延がベンチマークスコアに影響する可能性を排除するためというわけだ。
 もっとも,これはAMD製CPUに限った話ではなく,Intel製CPUでも同様に起こりうる現象なので,その点では特別な話ではない。

動作クロックとBIOSやWindows 10の設定に関する注意書き。BIOSでP-stateを「P0」(最高)にし,「Core Performance Boost」と「Global C-state Control」は「Disable」(無効)に,そしてWindows 10の電源設定を「高パフォーマンス」にすべしとのこと。ちなみに,CPU内部の電力制御用マイクロコントローラ「System Management Unit」(SMU)は,P0 stateに固定しても電力を制御すると書かれている点は,ちょっと興味深い
画像集 No.011のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」


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数が多ければ,描画スレッド数に応じて性能は向上するが,それでも7スレッド程度でピークになり,それ以上はむしろ逆効果であるという
画像集 No.012のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

 余談だが,筆者が講演後にサンプルコードを見たところ,Draw Context数は,「stdafx.h」に「NumContexts」という定数で設定してあるのを確認できた。興味のある開発者は,いろいろと値を変えて実行してみると参考になるかもしれない。

サンプルコードを実行した画面
画像集 No.013のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

 さて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系の命令は使う必要がないと説明するスライド
画像集 No.014のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

prefetchすると,むしろ効率が悪くなるコード例。「work()」は固定ループで,prefetchがない場合はコンパイラがループを展開するが,prefetchを入れるとループが展開されず,結果として遅いという違いが出る
画像集 No.015のサムネイル画像 / [GDC 2017]AMDの技術者が語る,「Ryzenに向けた最適化のコツ」

 ちなみに,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:
4Gamer.net最新情報
プラットフォーム別新着記事
総合新着記事
企画記事
スペシャルコンテンツ
注目記事ランキング
集計:11月28日〜11月29日