DRED を使用して GPU のフォールトを診断する

DRED とは、Device Removed Extended Data (デバイス削除拡張データ) のことです。 DRED は、予期しないデバイス削除エラーの原因特定に役立つように設計された機能の集合であり、その機能は進化を続けています。 必要な機能 (以下で定義) がサポートされているハードウェアでは、DRED のブレッドクラムと GPU ページ フォールト報告の機能を利用できます。

自動ブレッドクラム

自動ブレッドクラムについて説明する前に、手動での方法を考えてみます。 タイムアウト検出と復旧 (TDR) の事態に備えて、ID3D12GraphicsCommandList2::WriteBufferImmediate メソッドを使用してブレッドクラムを GPU コマンド ストリームの中に配置しておくと、GPU の進行状況を追跡することができます。

これは、独自の、低オーバーヘッドの実装を作成したい場合に妥当なアプローチとなります。 しかし、この方法には、標準化されたソリューションが持つ多様性が不足している可能性があります。たとえば、デバッガーの拡張機能や、Windows エラー報告 (WER) (別名 Watson) 経由の報告です。

そのため、DRED の自動ブレッドクラムは WriteBufferImmediate を呼び出して進行状況のカウンターを GPU コマンド ストリームの中に配置します。 DRED は、各 レンダー操作の後に階層リンクを挿入します。これは、GPU の動作 ( 描画ディスパッチコピー解決など) を行うすべての操作を意味します。 デバイスが GPU ワークロードの途中で削除された場合は、DRED ブレッドクラムの値は実質的に、そのエラーの前に完了したレンダリング操作のコレクションとなります。

ブレッドクラム履歴リング バッファーでは、コマンド リスト 1 つにつき最大 64 KiB 分の操作が保持されます。 コマンド リストに 65536 を超える操作がある場合、最後の 64KiB 操作のみが格納され、最も古い操作が最初に上書きされます。 ただし、ブレッドクラム カウンターの値は、UINT_MAX に達するまで増え続けます。 したがって、LastOpIndex = (BreadcrumbCount - 1) % 65536 となります。

DRED 1.0 が初めて利用可能になったのは Windows 10 バージョン 1809 (Windows 10 October 2018 Update) であり、基本的な自動ブレッドクラム機能が公開されました。 ただし、API はなく、DRED 1.0 を有効にする唯一の方法は 、フィードバック ハブ を使用して 、アプリ & ゲームの>パフォーマンスと互換性の TDR 再現 (再現) をキャプチャすることでした。 DRED 1.0 の主な目的は、ユーザーからのフィードバックを介してゲームのクラッシュの根本原因分析に役立てることでした。

注意事項

  • GPU ではパイプラインが多用されているため、失敗した操作をブレッドクラム カウンターが正確に示すとは限りません。 それだけではなく、タイル ベースの遅延レンダリング デバイスでは、ブレッドクラム カウンターが実際の GPU 進行状況よりも、リソースまたは順序指定されていないアクセス ビュー (UAV) バリア 1 つ分遅れることがあります。
  • ディスプレイ ドライバーは、コマンドの順序を変更することや、コマンド実行のかなり前にリソース メモリからプリフェッチすることや、キャッシュ済みメモリをコマンド完了のかなり後にフラッシュすることがあります。 これらはどれも、GPU エラーの原因となります。 このような場合は、ブレッドクラム カウンターがあまり役立たず、誤解を招くこともあります。

パフォーマンス

自動ブレッドクラムは低オーバーヘッドとなるように設計されていますが、まったくないわけではありません。 経験的測定では、典型的な AAA Direct3D 12 グラフィックス ゲーム エンジンで 2% から 5% のパフォーマンス低下が見られます。 このような理由から、自動ブレッドクラムは既定ではオフに設定されています。

ハードウェア要件

ブレッドクラム カウンターの値はデバイス削除の後も保持する必要があることから、ブレッドクラムが格納されているリソースはシステム メモリに存在する必要があり、デバイス削除が発生したときも存続する必要があります。 つまり、ディスプレイ ドライバーが D3D12_FEATURE_EXISTING_HEAPS をサポートしていることが必要です。 Windows 10 (バージョン 1903) のほとんどの Direct3D 12 ディスプレイ ドライバーは、これをサポートしています。

GPU ページ フォールトの報告

DRED 1.1 の新機能の 1 つが DRED GPU ページ フォールトの報告です。 GPU ページ フォールトは一般的に、次の条件のいずれかで発生します。

  1. アプリケーションが誤って、削除済みオブジェクトを参照する作業を GPU に対して実行している。 これは、予期しないデバイス削除が起きる理由の 1 つです。
  2. アプリケーションが誤って、無効にされたリソース、または非常駐のタイルにアクセスする作業を GPU に対して実行している。
  3. シェーダーが、未初期化または古い記述子を参照している。
  4. シェーダーのインデックスがルート バインドの終端の先を指している。

DRED は、このようなシナリオに対処するために、既存または最近解放された API オブジェクトのうち、GPU から報告されたページ フォールトの仮想アドレス (VA) に一致するものの名前と型を報告します。

注意点

すべての GPU でページ フォールトがサポートされるわけではありません (しかし、多くでサポートされます)。 GPU の中には、メモリ フォールトへの対応として、ビット バケットの書き込みや、シミュレートされたデータ (たとえばゼロ) の読み取りを行うものもあれば、単にハングするものもあります。 GPU がすぐにハングしない場合は、タイムアウト検出と復旧 (TDR) がパイプ内の後のほうで発生することがあり、根本原因を見つけるのがさらに困難になります。

パフォーマンス

Direct3D 12 ランタイムは、既存または最近削除された API オブジェクトのうち、仮想アドレス (VA) によってインデックスが付けられるもののコレクションを積極的に集める必要があります。 この結果としてシステム メモリのオーバーヘッドが増加し、オブジェクトの作成と破棄に対して小さなパフォーマンス ヒットが発生します。 このような理由から、この動作は既定ではオフに設定されています。

ハードウェア要件

ページ フォールトをサポートしない GPU でも、自動ブレッドクラム機能の利点を活用できます。

コードで DRED を設定する

DRED の設定はプロセスに対してグローバルであり、Direct3D 12 デバイスを作成する前に構成する必要があります。 これを行うには、D3D12GetDebugInterface 関数を呼び出して ID3D12DeviceRemovedExtendedDataSettings を取得します。

CComPtr<ID3D12DeviceRemovedExtendedDataSettings> pDredSettings;
VERIFY_SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pDredSettings)));

// Turn on auto-breadcrumbs and page fault reporting.
pDredSettings->SetAutoBreadcrumbsEnablement(D3D12_DRED_ENABLEMENT_FORCED_ON);
pDredSettings->SetPageFaultEnablement(D3D12_DRED_ENABLEMENT_FORCED_ON);

Note

DRED の設定を変更しても、既に作成されているデバイスに影響はありません。 しかし、それ以降の D3D12CreateDevice への呼び出しでは最新の DRED の設定が使用されます。

コードで DRED データにアクセスする

デバイス削除が検出された (たとえば、Present から DXGI_ERROR_DEVICE_REMOVED が返された) 後に、ID3D12DeviceRemovedExtendedData インターフェイスのメソッドを使用して、削除されたデバイスの DRED データにアクセスします。

ID3D12DeviceRemovedExtendedData インターフェイスを取得するには、QueryInterfaceID3D12Device (または派生した) インターフェイスに対して呼び出します。このときに、ID3D12DeviceRemovedExtendedData のインターフェイス識別子 (IID) を渡します。

void MyDeviceRemovedHandler(ID3D12Device * pDevice)
{
    CComPtr<ID3D12DeviceRemovedExtendedData> pDred;
    VERIFY_SUCCEEDED(pDevice->QueryInterface(IID_PPV_ARGS(&pDred)));
    D3D12_DRED_AUTO_BREADCRUMBS_OUTPUT DredAutoBreadcrumbsOutput;
    D3D12_DRED_PAGE_FAULT_OUTPUT DredPageFaultOutput;
    VERIFY_SUCCEEDED(pDred->GetAutoBreadcrumbsOutput(&DredAutoBreadcrumbsOutput));
    VERIFY_SUCCEEDED(pDred->GetPageFaultAllocationOutput(&DredPageFaultOutput));
    // Custom processing of DRED data can be done here.
    // Produce telemetry...
    // Log information to console...
    // break into a debugger...
}

DRED へのデバッガーのアクセス

デバッガーから DRED データへのアクセスは、d3d12!D3D12DeviceRemovedExtendedData データ エクスポートを介して行われます。

WinDbg ユーザーの場合は、DRED 状態のデバッグをはるかに簡単にする WinDBG 拡張機能については、DirectX-Debugging-Tools GitHub リポジトリDirect3D 12参照してください。

DRED テレメトリ

開発するアプリケーションで DRED API を使用して、DRED の機能を制御することや、問題の分析に役立つテレメトリを収集することができます。 このことを利用すると、再現しにくい TDR を捕捉するための網を広げることができます。

Windows 10 (バージョン 1903) からは、ユーザー モードのデバイス削除イベントはすべて Windows エラー報告 (WER)、別名ワトソンに報告されます。 あるアプリケーション、GPU、ディスプレイ ドライバーの組み合わせによって生成されたデバイス削除イベントの数が十分にある場合は、同じアプリケーションを同様の構成で起動する顧客に対して DRED を一時的に有効にすることができます。

DRED の詳細