3DS の GPU にはプロファイル機能が搭載されており、ハードウェア性能のベンチマークやパフォーマンスのチューニングに利用することができます。
プロファイル機能には以下のものがあります。
機能 | 説明 |
---|---|
ビジーカウンタ |
一定期間内に各モジュールのビジー信号が出力された回数を比較し、最も多くビジーが出力されたモジュールを判定します。 指定回数の計測を繰り返し、モジュールごとに、最も多くビジーが出力されたと判定された回数をカウントします。 |
シェーダ実行クロック数カウンタ | 4 基あるシェーダプロセッサのプログラムカウンタの遷移数やストールしたクロック数をカウントします。 |
頂点キャッシュ入力頂点数カウンタ | ポスト頂点キャッシュに入力された頂点数をカウントします。 |
入出力ポリゴン数カウンタ | トライアングルセットアップのモジュールに入力された頂点とポリゴンの数と出力されたポリゴンの数をカウントします。 |
入力フラグメント数カウンタ | パーフラグメントオペレーションのモジュールに入力されたフラグメントの数をカウントします。 |
メモリアクセス数カウンタ | VRAM や頂点バッファなどのメモリにアクセスした回数をカウントします。 |
プロファイル機能で呼び出す関数はコマンドリストの実行中に呼び出さないでください。呼び出してもエラーにはなりませんが、GPU が不正な動作をする可能性があります。
9.1. プロファイル機能の開始と停止
プロファイル機能の中には、以下の関数で開始と停止をアプリケーションで明示的に指示しなければならないものがあります。
void nngxStartProfiling(GLenum item); void nngxStopProfiling(GLenum item);
item
には、開始または停止を指示するプロファイル機能を以下の定義値から指定します。下記以外の定義値を指定した場合、nngxStartProfiling()
は GL_ERROR_80A2_DMP
のエラーを、nngxStopProfiling()
は GL_ERROR_80A3_DMP
のエラーをそれぞれ生成します。
定義値 | プロファイル機能 |
---|---|
NN_GX_PROFILING_BUSY
|
ビジーカウンタ(必ずパラメータ設定で計測期間を指定してください) |
NN_GX_PROFILING_VERTEX_CACHE
|
頂点キャッシュ入力頂点数カウンタ(使用時は消費電力が上がる可能性があります。使用しない場合は必ず停止してください) |
9.2. プロファイル機能のパラメータ
以下の関数で、一部のプロファイル機能のパラメータを設定することができます。
void nngxSetProfilingParameter(GLenum pname, GLuint param);
pname
に指定する定義値によって、param
に指定する値が以下のように異なります。
pname に指定する定義値 | param に指定する値 |
---|---|
NN_GX_PROFILING_BUSY_SAMPLING_TIME
|
ビジーカウンタの 1 回あたりの計測時間(GPU クロック数)を 0 以外の 16 ビット値で指定します。 |
NN_GX_PROFILING_BUSY_SAMPLING_TIME_MICRO_SECOND
|
GPU クロック数に変換したときに 16 ビット値に納まっていなければならないため、指定可能な値の範囲は 1~244 です。 |
NN_GX_PROFILING_BUSY_SAMPLING_TIME_NANO_SECOND
|
GPU クロック数に変換したときに 16 ビット値に納まっていなければならないため、指定可能な値の範囲は 1~244537 です。 |
NN_GX_PROFILING_BUSY_SAMPLING_COUNT
|
ビジーカウンタの計測回数を 16 ビット値で指定します。 0 を指定した場合、ビジーカウンタは明示的に停止を指示されるまで動作を継続し(1 回あたり 0 以外が指定された場合、ビジーカウンタは明示的に停止を指示されるか、開始から(計測時間×計測回数)クロック経った時点で停止します。 1 以上の値を設定し、かつ計測終了を待ってから結果を取得した場合、ビジーカウンタの計測結果における各モジュールの値の合計は計測回数に一致します。 |
エラー | 原因 |
---|---|
GL_ERROR_80A5_DMP
|
pname に不正な値を指定した |
GL_ERROR_80A6_DMP
|
param に不正な値を指定した |
計測時間から GPU クロック数への変換は 268 MHz(268,000,000 Hz)で行われます。
パラメータの初期値は不定のため、必ず関連するパラメータすべての値を設定してください。
9.3. プロファイル結果の取得
以下の関数で、プロファイル結果を取得することができます。
void nngxGetProfilingResult(GLenum item, GLuint* result);
item
には、結果を取得するプロファイル機能を指定します。不正な値を指定した場合、GL_ERROR_80A4_DMP
のエラーが生成されます。
result
には、指定されたプロファイル機能の結果が格納されます。プロファイル機能によって、結果を格納するために必要なバッファのサイズが異なることに注意してください。
各プロファイル機能の結果を取得する際の item
の指定や result
に格納される結果の詳細については、以降の項で説明します。
明示的に開始と停止を指示しなければならないプロファイル機能以外は常時動作しています。これらのプロファイル機能のカウンタはハードウェアの起動時にリセットされますので、プロファイル結果を取得する場合は、計測期間の開始時と終了時で取得した結果の差分値を利用してください。
プロファイル機能のカウンタはオーバーフローすると 0 に戻ってカウントを続けます。
9.3.1. ビジーカウンタ
ビジーカウンタの結果を取得するには、item
に NN_GX_PROFILING_BUSY
を指定します。result
には、要素数が NN_GX_PROFILING_RESULT_BUFSIZE_BUSY
の GLuint
型の配列を指定してください。
ビジーカウンタは nngxStartProfiling()
で開始されたときにカウンタを 0 にリセットし、停止されるまで一定期間ごとにビジーが出力された回数を比較し、最も多くビジーが出力された回数をカウントします。また、計測結果を取得するごとにカウンタは 0 にリセットされます。そのため、プロファイル機能を開始後、停止させずに結果を取得した場合、前回結果を取得したときからの計測結果を取得することになります。
各モジュールの結果は 16 ビット値で格納されています。下表にデータの格納順とモジュールの対応を示します。
データ | モジュール |
---|---|
result[0] のビット [ 31 : 16 ] | シェーダプロセッサ 0(ジオメトリプロセッサと共用) |
result[0] のビット [ 15 : 0 ] | コマンドバッファおよび頂点アレイロードモジュール |
result[1] のビット [ 31 : 16 ] | ラスタライゼーションモジュール |
result[1] のビット [ 15 : 0 ] | トライアングルセットアップ |
result[2] のビット [ 31 : 16 ] | フラグメントライティング |
result[2] のビット [ 15 : 0 ] | テクスチャユニット |
result[3] のビット [ 31 : 16 ] | パーフラグメントオペレーションモジュール |
result[3] のビット [ 15 : 0 ] | テクスチャコンバイナ |
ビジーカウンタの結果は、ビジーが最も多く出力された回数であり、ビジー信号が出力された回数そのものではありません。
ビジーカウンタの計測を開始すると、1 回あたりの計測時間内での各モジュールのビジー信号の出力回数を比較し、最もビジー信号の出力回数が多かったモジュールのカウンタを 1 カウントアップします。この計測は指定された計測回数分繰り返し行われます。なお、1 回あたりの計測時間内に複数のモジュールでビジー信号の出力回数が同じ値で最大となった場合、それらの中で最前段にあるモジュールのカウンタがカウントアップされます。また、すべてのモジュールのビジー信号出力回数が 0 だった場合は、最前段にある「コマンドバッファおよび頂点アレイロードモジュール」のカウンタがカウントアップされます。そのため、計測回数を 1 回以上に設定し、かつ計測が終了してから結果を取得した場合、各モジュールの計測結果の値の合計は、計測回数に一致します。
計測結果のうちで最も値が大きいモジュールが、最も長い期間ボトルネックになったと予測することができます。そのモジュールを中心に最適化を行い、パフォーマンスのチューニングを行ってください。
9.3.1.1. トライアングルセットアップ/ラスタライゼーションモジュールのボトルネック解析
ビジーカウンタの結果から、トライアングルセットアップ(以降 TS)およびラスタライゼーションモジュール(以降 RAS)がボトルネックになっている可能性について解析できます。
TS はポリゴン数、RAS はポリゴン数および生成されるピクセル数の影響を受けます。そのため、以下のような特性があります。
- 処理するポリゴン数、ポリゴンの座標、生成されるピクセル数が変わらない限り、頂点データをロードして生成されたポリゴンか、ジオメトリシェーダで生成されたポリゴンかは TS、RAS の性能に影響しません。
- 処理するポリゴン数、ポリゴンの座標、生成されるピクセル数が変わらない限り、ドロー関数が何回呼び出されて描画されているかは TS、RAS の性能に影響しません。
- 頂点の属性数(テクスチャ座標の個数など)の増減は、TS、RAS の性能に影響しません。
TS、 RAS がボトルネックと予想される場合、頂点シェーダに nop を数~数十個挿入して性能が変わるかどうか、および画面全体にシザリングを有効にした状態で性能が変わるかどうかの 2 つのケースを確認し、どちらも性能が変わらない場合、TS、RAS がボトルネックである可能性が高まります。TS の処理負荷を下げるには、ポリゴン数を減らす必要があります。方法としては、描画オブジェクトの LOD を使用する、CPU 側でオブジェクトのクリップを行う、などが挙げられます。TS の負荷が下がれば、RAS の負荷も下がります。
9.3.2. シェーダ実行クロック数カウンタ
シェーダ実行クロック数カウンタの結果を取得するには、item
に取得するシェーダプロセッサに対応する定義値 NN_GX_PROFILING_VERTEX_SHADERn
(n
は 0~3 のプロセッサ番号)を指定します。result
には、要素数が NN_GX_PROFILING_RESULT_BUFSIZE_VERTEX_SHADERn
(n
は 0~3 のプロセッサ番号)の GLuint
型の配列を指定してください。なお、ジオメトリプロセッサはシェーダプロセッサ 0 と共用です。
シェーダ実行クロック数カウンタはハードウェアの起動時に 0 にリセットされ、常に動作しています。
結果は 32 ビット値で格納されています。下表にデータの格納順と情報の対応を示します。
データ | 情報 |
---|---|
result[0] | プログラムカウンタの遷移数(実行されたシェーダアセンブラの命令数と同じです) |
result[1] | シェーダアセンブラ命令の依存関係によりストールしたクロック数(NN_GX_PROFILING_VERTEX_SHADER0 のみ、ジオメトリシェーダが有効なときに後段のモジュールがビジーとなって vout 命令の発行が待たされた場合を含みます) |
result[2] | アドレスレジスタの更新(mova 命令発行)によりストールしたクロック数 |
result[3] | ステータスレジスタの更新(cmp 命令発行)によりストールしたクロック数 |
result[4] | プログラムのプリフェッチのミスヒットによりストールしたクロック数(分岐命令などによるプログラムカウンタの不連続遷移により発生します) |
9.3.3. 頂点キャッシュ入力頂点数カウンタ
頂点キャッシュ入力頂点数カウンタの結果を取得するには、item
に NN_GX_PROFILING_VERTEX_CACHE
を指定します。result
には、要素数が NN_GX_PROFILING_RESULT_BUFSIZE_VERTEX_CACHE
の GLuint
型の配列を指定してください。
頂点キャッシュ入力頂点数カウンタは、頂点バッファを使用する(レジスタ 0x022F に 1 を書き込む)描画が開始されたときにカウンタが 0 にリセットされます。そのため、取得できるのは最後に実行された描画での計測結果です。描画に使用した頂点インデックスの総数と比較することで、ポスト頂点キャッシュの効率が推測できます。ただし、同じ頂点データで描画を行った場合でも、頂点インデックスのロードのタイミングが異なったり、後段のモジュールがビジーとなったりすることによって、カウントが多少上下することがあります。また、nngxStartProfiling()
で計測を開始していなくても、動作しているようなプロファイル結果が取得されることがありますが、その値は正しくない可能性があります。正しい結果を取得するためには、必ず nngxStartProfiling()
を呼び出して計測を開始してください。
結果は 32 ビット値で格納されています。下表にデータの格納順と情報の対応を示します。
データ | 情報 |
---|---|
result[0] | ポスト頂点キャッシュに入力された頂点数 |
9.3.4. 入出力ポリゴン数カウンタ
入出力ポリゴン数カウンタの結果を取得するには、item
に NN_GX_PROFILING_POLYGON
を指定します。result
には、要素数が NN_GX_PROFILING_RESULT_BUFSIZE_POLYGON
の GLuint
型の配列を指定してください。
入出力ポリゴン数カウンタはハードウェアの起動時に 0 にリセットされ、常に動作しています。
結果は 32 ビット値で格納されています。下表にデータの格納順と情報の対応を示します。
データ | 情報 |
---|---|
result[0] | トライアングルセットアップへの入力頂点数 |
result[1] | トライアングルセットアップへの入力ポリゴン数 |
result[2] | トライアングルセットアップからの出力ポリゴン数 |
出力ポリゴン数は、入力されたポリゴン数からクリッピングやカリングにより省かれたポリゴンを差し引いた値です。クリップボリュームに交わるポリゴンは、実際には複数のポリゴンに分割されて出力されますが、1 とカウントされます。
9.3.5. 入力フラグメント数カウンタ
入力フラグメント数カウンタの結果を取得するには、item
に NN_GX_PROFILING_FRAGMENT
を指定します。result
には、要素数が NN_GX_PROFILING_RESULT_BUFSIZE_FRAGMENT
の GLuint
型の配列を指定してください。
入力フラグメント数カウンタはハードウェアの起動時に 0 にリセットされ、常に動作しています。
結果は 32 ビット値で格納されています。下表にデータの格納順と情報の対応を示します。
データ | 情報 |
---|---|
result[0] | パーフラグメントオペレーションモジュールに入力されたフラグメント数 |
フラグメント数には、クリッピング、シザーテスト、アーリーデプステストにより破棄されたフラグメントは含まれません。アルファテスト、ステンシルテスト、デプステストについてはテスト前のフラグメント数をカウントするため、テスト結果はカウントに影響しません。
9.3.6. メモリアクセス数カウンタ
メモリアクセス数カウンタの結果を取得するには、item
に NN_GX_PROFILING_MEMORY_ACCESS
を指定します。result
には、要素数が NN_GX_PROFILING_RESULT_BUFSIZE_MEMORY_ACCESS
の GLuint
型の配列を指定してください。
メモリアクセス数カウンタはハードウェアの起動時に 0 にリセットされ、常に動作しています。
結果は 32 ビット値で格納されています。下表にデータの格納順と情報の対応を示します。
データ | 情報 |
---|---|
result[0] | GPU によるVRAM のリード(A チャンネル) |
result[1] | GPU によるVRAM のライト(A チャンネル) |
result[2] | GPU によるVRAM のリード(B チャンネル) |
result[3] | GPU によるVRAM のライト(B チャンネル) |
result[4] | コマンドバッファおよび頂点アレイをロードするモジュールによるコマンドバッファ、頂点アレイ、インデックスアレイのリード |
result[5] | テクスチャユニットによるテクスチャメモリのリード |
result[6] | パーフラグメントオペレーションモジュールによるデプスバッファおよびステンシルバッファのリード |
result[7] | パーフラグメントオペレーションモジュールによるデプスバッファおよびステンシルバッファのライト |
result[8] | パーフラグメントオペレーションモジュールによるカラーバッファのリード |
result[9] | パーフラグメントオペレーションモジュールによるカラーバッファのライト |
result[10] | 上画面 LCD コントローラによるディスプレイバッファのリード |
result[11] | 下画面 LCD コントローラによるディスプレイバッファのリード |
result[12] | ポスト転送モジュールによるリード(nngxTransferRenderImage() 、glCopyTexImage2D() などによる転送) |
result[13] | ポスト転送モジュールによるライト(nngxTransferRenderImage() 、glCopyTexImage2D() などによる転送) |
result[14] | メモリフィルモジュールのチャネル 0 によるバッファのライト(glClear() などによるバッファクリア) |
result[15] | メモリフィルモジュールのチャネル 1 によるバッファのライト(glClear() などによるバッファクリア) |
result[16] | CPU による VRAM のリード(glReadPixels() など) |
result[17] | CPU(DMA 転送)による VRAM のライト(nngxAddVramDmaCommand() などによる DMA 転送) |