Diavlo IV タイトルイメージ

​※本ブログは、米国時間 2021 年 6 月 3 日に公開された Diablo IV debugs Linux core dumps from Visual Studio の翻訳です。

Blizzard 社では、Visual Studio 2019 を使用して Linux用Windows サブシステム (WSL)  での Linux コア ダンプをデバッグしています (英語)。(このブログは、Blizzard 社でディアブロ IV の開発に携わるシニア ソフトウェア エンジニアである Bill Randolph 氏によって書かれたものです。)

はじめに

ディアブロ IV では、Windows上ですべてのコード開発を行い、複数のプラットフォーム向けにコンパイルされ、マイクロソフトのLinuxサーバー上で実行されています。 このコードには、必要に応じて条件付きコンパイルと、プラットフォーム固有のカスタムコードが含まれます。

まずこのようなワークフローの理由として、私たちのチームの中核となる技術は Windows 上にありるということです。ほとんどのサーバー プログラマーが精通しているのは Windows での開発であり、チームのプログラマー全員が共通のツールセットとナレッジ ベースを使用できるというのがありがたいことです。

もう 1 つ、私たちが Windows で開発を行う最も大きな理由は、Visual Studio で提供される機能と堅牢なツールセットです。仮にLinux でネイティブに開発しても、Visual Studioに匹敵するものはありません。

ただし、展開されたサーバーがクラッシュし、それによって生成されたコア ダンプをデバッグする場合、課題がいくつか生じます。クラッシュした仮想マシン (具体的にはコンテナ) にリモート ログインし、そこで gdb コマンドを実行してクラッシュを診断することはできますが、これには欠点があります。まず、ソースをバイナリと共に展開していないため、仮想マシンまたはコンテナ上のgdb セッションでソースを使用することができません。

もう 1 つのハードルは、gdb を日常的に使用しない限り、gdb自体を便利に使えるだけの習熟度レベルを維持することはできません。つまり、開発者たちはむしろデバッグには使い慣れたツールを使用することを望んでいました。 私たちの開発者で gdb に精通しているのは 2、3 人しかおらず、実稼働でのクラッシュ診断を担当するのが事実上彼らだけとなり、これは最適な状況とは言えません。

Linux コアのデバッグには、もっと直感的なアプローチが必要であると常に感じていたため、Visual Studio の馴染みのある環境でそれを実現できる新しい機能を使用できることに、私たちは夢がかなったと言っても決して過言ではありません。

Diablo IV ゲーム画面 (プレイ中)

デバッグ ワークフロー

Visual Studio の Linux コアのデバッグ ワークフローは、WSL をインストールするか、Linux 接続を接続マネージャーに追加する場合にのみ有効になります。まずサーバー開発者は、展開したディストリビューションを使用して WSL をインストールします。そして私が書いたスクリプトを実行して、WSL でサーバーを構築するために必要な開発ツールとサポート ライブラリをすべてインストールします。

(トピックから少し逸れますが、WSL は開発者が Linux ビルドで変更をテストするために使用できる最良の Linux 環境であると思います。WSL に入り、共有コード ディレクトリに移動するだけで、そこからビルドできるのが非常に便利です。これは、仮想マシンやコンテナを実行するよりはるかに優れたソリューションだと思います。CMake でビルドしている場合は、Visual Studio の WSL ネイティブ対応 (英語) を活用できます。)

私たちのビルドについて背景を説明します。私たちは Windows でコードを開発し、それらをWindows で実行できるサーバーを持っています。これは、通常の機能開発には便利ですが、私たちは Linux 上にサーバーを展開しており、Linux 自体で生成されたビルドが必要です。  Linux ビルドは、Linux ボックス上のビルド システムを使用するビルド ファームで生成され、展開されるサーバーとコンテナを構築します。Linux 実行可能ファイルはコンテナでのみ展開され、開発者は通常はアクセスできません。

私たちの基盤でサーバーがクラッシュすると、自動化されたプロセスによりそれが通知され、コア ファイルがネットワーク共有にアーカイブされます。Linuxまたは Visual Studio を使用してコアをデバッグするには、実行されていた実行可能ファイルが必要です。これは、展開されたコンテナで使用される共有ライブラリを使用してデバッグするのにも役立ちます。これらのファイルを取得するには、別のスクリプトを使用します。まず、コアをローカル マシンにコピーし、スクリプトを実行してこれがコアを指すようにします。スクリプトは、そのバージョンでビルドされた Docker コンテナをダウンロードし、そこからサーバーのバイナリと gdb で使用する特定の共有ランタイム ライブラリを抽出します (これにより、WSL バージョンが展開された Linux バージョンと一致しない場合に生じる可能性のある gdb の互換性の問題を回避できます)。スクリプトは、デバッグ セッションのシステム ライブラリとして共有ライブラリを設定するため、~/.gdbinit に書き込みを行います。

ここからが本題ですが、次に Visual Studio に切り替えます。Windows サーバーのバージョンを構築するためのソリューションをロードし、[デバッグ]、[その他のデバッグ ターゲット]、[Debug Linux Core Dump with Native Only] より、新しいデバッグ ダイアログを開きます。[Debug on WSL] チェックボックスをオンにし、コア ファイルとサーバー バイナリの両方の (WSL 固有の) パスを入力します。すると、[Debug & watch the show] が表示されます。

Visual Studio Debug Linux Core Dump with Native Only

Visual Studio はバックグラウンドで WSL の gdb を呼び出します。ディスク読み込みの後、クラッシュのコール スタックが表示され、関連するコード行に命令ポインターが置かれます。ここが魅力です。

次は、クラッシュを特定するタスクです。クラッシュを止めてハウスキーピング処理を行うクラッシュ ハンドラーがあるため、シングルスレッド サーバーではコール スタックがクラッシュします。ただし、サーバーの一部はマルチスレッドであり、クラッシュはそれらのスレッドのいずれかで発生している可能性があります。クラッシュ ハンドラーはクラッシュ元のファイルと行番号をログに記録するため、これらの変数を調べることで、最初に何をするかを判断できます。私たちはこのコードを実行していたコール スタックを探します。

私たちは数週間前では gdb を使用してすべてのスレッドのバックトレースを取得し、生成されたリストを詳細に調べて、クラッシュした可能性が最も高いコール スタックがどのスレッドにあるかを把握しました。たとえば、スレッドが単にスリープ状態の場合、そのスレッドがクラッシュしている可能性はほとんどありません。「スリープ」と示されたいくつかのフレーム以外の、もっと多くのコンテンツを含むスタックを探し、コードを調べて問題が明白かどうか確認するか、gdb 自体にアクセスしてプロセスの状態を調べていました。

しかし、Visual Studio では、それよりはるかに強力な機能があります。マルチスレッド コアの場合、デバッグ セッションで [スレッド] ウィンドウを開き、各スレッドを調べて、スタックの状態を確認します。これは gdb のアプローチと非常によく似ており、スレッドの数が 50 ともなれば、とても面倒な作業になり得ます。しかし、これをはるかに簡単にする、並列スタックという機能があります。

正直に申しますと、私たちは並列スタックをマイクロソフトのErika Sweet 氏のチームから教わるまでまで知りませんでした。[デバッグ]、[ウィンドウ]、[並列スタック] (デバッグ セッションでのみ使用可能) の順にクリックすると、プロセス内の各スレッドのコール スタックを示す新しいウィンドウが開かれます。これは、プロセス スペース全体を俯瞰した魅力的な機能です。任意のスレッドの任意のスタック フレームをダブルクリックすると、Visual Studio は、ソースとコール スタックの両方のウィンドウで、そのフレームに切り替わります。これは、非常に時間の節約になります。

クラッシュ付近のコードを確認できたら、マウスでのポイント、クイック ウォッチ、その他 Visual Studio 内の多くのツールを使用して、変数を調べることができます。実際、リリース ビルドでは、多くの変数が最適化されていますが、同時に最適化されていないものも多くあります。Visual Studio のインターフェイスを使用することで、以前 gdb のみを使用していたときよりはるかに迅速に、問題に集中できるようになりました。

Diablo IV ゲーム画面

まとめ

私たちのチームは、Visual Studio で実稼働環境から Linux コアをデバッグできることに大きく期待しています。これによって、より多くの開発者が、実稼働での問題を積極的に診断できるようになり、Visual Studio のデバッグの強力なツールセットを私たち全員が使用できるようになります。初期設定が完了すれば、Visual Studio のデバッグ セッションに入るまでにかかる時間はわずか 1 分程度です。この機能により、コード内の問題を非常に迅速かつ効率的に見つけられるようになります。私たちに協力していただいた、マイクロソフトのErika と彼女のチームに感謝いたします。