GPUViewのMemory Viewer

GPUViewのMemory Viewerは、GPUが使用しているメモリ空間を視覚的に把握することが出来るツールです。
ただしその内容は、OSのバージョン、GPUのベンダー、機種、そしてドライバーのバージョンなどに依存すると思います。下記の内容は、私の環境で実行したもので、おそらく他の環境(特にGPUベンダーが違う場合)ですと、全く違った内容になるかと思います。ちなみに私の環境は下記の通りです。

OS:Windows7-64Bit Windows Aero OFF
GPU:GeForce680GTX-2GB DriverVersion301.42

Windows AeroをオフにするとGPU側のメモリ消費が最小限になるので、特定のプロセスなどを監視しやすくなります。

ゲームなどを立ち上げていない状態

4つのセグメントが見て取れます。
左から

  1. Cache Coherent, Aperture 768MB
  2. Aperture 1280MB
  3. Cache Coherent 約2048MB
  4. Cpu Visible, Cache Coherent 32 MB

となっています。
以下憶測です。

  • セグメント1と2のApertureフラグは、GPU側からCPUのメモリ空間が見えることを意味すると思われます。(AGP-Aperture?) 従って実体はメインメモリ上に存在するはずです。総計2GBメモリ空間が割り当てられているので、仮想アドレス空間が割り当てられていると思います。
  • セグメント3はいわゆるGPU側ののメモリ空間だと思われます。サイズが中途半端なので、GPU内の物理アドレスと対応するアドレス空間がマッピングされていると思われます。
  • セグメント4はCPU Visibleフラグが付いているので、必然的にGPU側のメモリ空間と思われ、さらにCPUから読み出し可能な領域と思われます。

セグメント3の上部に確保されているオブジェクトはcsrss.exeが確保しているもので、Windowsのデスクトップの表示に使用されているものと思われます。ちなみにサイズは17039360Byteだったので、私のデスクトップのピクセル数で割るとちょうど4Byteになります。

DirectX SDK内のDX11 Tutorial07を実行した場合


このアプリケーションは非常に単純なものですが、VS,PS,CB,VB,IB,TextureそしてBackbuffer,DepthStencilと一通りのオブジェクトを生成し実行しているものです。Memory Viewer上のView by currently referencedを選択すると、現在処理中の描画が参照しているオブジェクトが白くマークされます。セグメント3の上部と下部に参照されている比較的大きなオブジェクトが見られます。これらはBackbufferとDepthStencilとTextureのです。NVIDIAのドライバは各セグメントの上位アドレスと下位アドレスの両方から使用していくようです。どのオブジェクトがどちらを使うかに関して確実な法則性は見いだせませんでしたが、Backbufferはセグメント3の下位アドレスに確保されるようです。おそらくアドレス空間のフラグメンテーションの進行を遅らせる事を意図していると思われます。

巨大なテクスチャを使用するテストアプリケーションを複数同時に実行した場合


黄色くマークされてるのは、Marked for evictionというフラグが付けられたオブジェクトで、メインメモリ上に退避可能な状態のオブジェクトです。ピンク色にマークされているのは Temporary Resource になります。おそらくセグメント3に空きがないので、Apertureを利用してメインメモリ上のオブジェクトをGPUに使用させていると思われます。

長時間にわたってDX9のゲームを実行して、FPSの低下が起きた場合


長時間にわたってDX9のゲームを実行し、FPSの低下が見られたケースのログです。Marked for eviction や Temporary Resource はありませんが、セグメント2に多数のオブジェクトが確保されています。セグメント3に空きはありますが、フラグメンテーションが進行している状態です。推測ですが、アプリケーション側で比較的大きなオブジェクトをD3DPOOL_DEFAULT上に確保を試みて、失敗した結果D3DPOOL_SYSTEMMEMにオブジェクトを確保している状態だと思われます。Aperture上に確保されたオブジェクトはGPU側からRead/Writeするのに非常に時間がかかるので、結果的にFPSの極端な低下に繋がります。
このケースで興味深いのは、もしフラグメンテーションを解消することが出来たら、セグメント2に確保されているオブジェクトはセグメント3に確保できるのではないかということです。もしDX9を使っていて、主なオブジェクトをD3DPOOL_MANAGEDで確保していたら、

IDirect3DDevice9::EvictManagedResources();

を呼び出すことで、セグメント3上に存在するManagedResourceをいったん退避させることが出来るはずです。ただしRender TargetなどManagedが許可されていないオブジェクトは退避出来ませんし、Managed Resource はDX9ex以降では使えないので、今後の事を考えるとManaged Resourceに頼るのは得策とはいえません。やはりフラグメンテーションを回避する一番確実な方法は、許容されるタイミングで全てのオブジェクトの開放と確保のし直しを行うことだと思われます。結果的に不用意なタイミングでの性能低下を免れることになり、相対的ににプイレイヤー側の体験向上に繋がる事になると思われます。極端な考え方ですがユーザーにそのタイミングを明示的に選択してもらうこともゲームの内容如何では可能かも知れません。

WindowsのCPUのプロセスはプロセスごとに仮想アドレス空間が割り当てられており、システム全体ではメモリ使用によるフラグメンテーションは発生しないのに対して、GPUではシステム全体でこれらのセグメントのアドレス空間を共有しているので、現在はフラグメンテーション/セキュリティの問題を孕んでいると思われます。今後GPUに求められることが考えられるのは、プロセスごとの独立したアドレス空間ですが、これを実現するためにはIntelのVt-dと同様の機構を、通常のプロセスに対しても適用する必要があるはずです。加えてGPU上でのメモリアクセス例外の処理も充実させる必要があるかもしれません。このあたりはまた近い将来に考えてみたいと思います。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中