PR

ThreadScopeのインストール

 ThreadScopeはHaskell Platform 2011.2.0.1には含まれていません。ThreadScopeを使うには,第39回で説明したcabalコマンドなどを使ってthreadscopeパッケージをインストールする必要があります。

$ cabal install threadscope

 threadscopeパッケージはGtk2Hsを使って実装されているため,事前にGtk2Hsをインストールしておく必要があります。Gtk2Hsの基本的なインストール方法については第43回を参照してください。

 ただし,原稿執筆時点ではGtk2HsはGHC 7.2.xやHaskell Platform 2011.2.0.1で提供されているGHC 7.0.3などに対応していません(すでに問題を修正したPre-release版が用意されているので,間もなく対応する見込みです,参考リンク1参考リンク2)。対策としては,Haskell Platform 2010.2.0.0を利用することが考えられます。同梱されているGHC 6.12.3を使ってGtk2HsやThreadScopeをインストールできます(参考リンク)。

ThreadScopeで並列プロファイルの結果を可視化

 では,ThreadScopeを使って<実行コマンド名>.eventlogファイルに出力された並列プロファイルの結果を見てみましょう。

 ThreadScopeを実行し,<実行コマンド名>.eventlogファイルを開きます。メニューバーの「File」→「開く」でダイアログボックスを開き,プロファイル結果を表示させたいファイルを選んでください。

ThreadScope1

 コマンドラインを使う場合は,ThreadScopeの引数として<実行コマンド名>.eventlogを渡します。

$ threadScope ParallelTest.eventlog

 これで,ThreadScopeに並列プログラムの実行に関する追跡情報が表示されます。

ThreadScope2

 ThreadScopeの右上のペインにはグラフが表示されます。グラフの左端に表示されている青いバーを左クリックして動かすことで,任意の時間に移動できます(実装にバグがあるのか,表示するグラフのサイズによっては青いバーが表示されないこともあります)。

 ThreadScopeの右下のペインにはRTS内部のイベントを追跡した情報が表示されています。このペインに表示される情報は,バーのある位置(時間)に対応して変わります。表示されているイベントのうち,反転表示されているのが,バーが示している時間に起きたイベントです。

 左側のペインのKeyタブでは,グラフの色分けの意味を示しています。また,Bookmarksタブの「+」ボタンをクリックすることで,バーの位置を保存できます。保存されたバーの位置は,グラフでピンク色のバーとして表示されます。

ThreadScope3

 なお,プログラムの中でGHC.ExtsモジュールのtraceEvents関数を利用した場合には,traceEvents関数で出力させたメッセージをBookmarksタブでのLabelとした,ピンク色のバーが自動的に作成されます。

 表示されているグラフは保存が可能です。メニューバーの「File」→「Export images...」でダイアログボックスを開き,ドロップダウンリストの「PNG bitmap files」を選ぶことでPNG画像,「PDF files」を選ぶことでPDFとして保存されます(ドロップダウンリストの値は,デフォルトでは「PNG bitmap files」になっています)。青いバーやBookmarksタブで利用されるピンクのバーは,グラフを保存する際には画像には含まれません。

 では,グラフを見てみましょう。Activityという一番上のグラフは,プログラム全体の処理の活発さを示しています。続くHEC*では,HEC*でのHaskellプログラムの式の評価・実行をグリーン,GCの実行をオレンジで示しています。グリーンの部分が多ければ,それに応じてActivityの値も大きくなります。

ThreadScope4

 各HEC*で同時に処理が実行されている時間が長く,その結果としてActivityの値が大きい時間が長ければ,並列処理を実行している時間が長いということになります。逆に処理の実行が特定のHEC*に偏っており,複数のHEC*で同時に処理を実行している時間が短く,その結果としてActivityの値が小さい時間が長ければ,そのプログラムの実行はあまり並列化できていません。

 このグラフの場合,最初はすべてのHECで並列に処理を行っていますが,途中からHEC3が単独で処理を行っています。このようにあまり並列化ができていない場合には,右下のペインに表示されたイベントの追跡情報を参考にしたり,プログラムを変更して再度プロファイルを行ったりして,原因を探ってみてください。すべてのHEC上での並列処理の実行が長くなるようプログラムを改良することで,並列プログラムの性能を改善できるでしょう。

 もっとも,並列プログラムの性能をこのグラフだけで判断すべきではありません。グラフではプログラムの並列化がうまくできているように見えても,それが前回指摘した「やみくもな並列化」の結果によるものかもしれないからです。並列プログラムの性能を見る場合には,並列プロファイラの結果からThreadScopeが出力するグラフだけではなく,第43回で説明したcriterionや第44回で説明したprogressionなどを使って,実際の性能を確認してください。

 グラフの内容は,左側のペインにあるTraceタブのチェックボックスを使うことで増やしたり減らしたりできます。「Activity Profile」がグラフ中のActivityに,「HEC Traces」がHEC*に対応します。さらにチェックボックスにチェックを入れて有効化することで,これまで表示されていたグラフの下に,追加のグラフを表示させることができます。

 「Spark Creation」や「Spark Conversion」,「Spark Pool」を有効化すると,それぞれ,sparkの作成状況について示す「Spark creation rate (spark/ms) HEC *」,sparkで実際に行われた並列処理について示す「Spark conversion rate (spark/ms) HEC *」,プール内のsparkの量を示す「Spark pool size HEC *」といった,sparkの追跡情報をグラフとして表示する項目が追加で現れます(こうした項目の情報を表示させるには,GHC 7.4.1以降が必要です)。スクロールバーを使って,HEC*の下に追加されたこれらの項目を見てみましょう。

ThreadScope5

 このようにThreadScopeでは「プログラム全体の活発さ」や「sparkの追跡情報」をグラフとして時間軸で表現します。ただし,sparkを使った並列評価がうまくいかなかった理由は何も提示しません。

 一方,RTSの-sオプションで出力される統計情報では,sparkによる並列評価がうまくいかなかった理由を表示します。しかし,「プログラム全体の活発さ」や「sparkの追跡情報」は提示してくれません。そこでThreadScopeとRTSの-sオプションを併用し,それぞれに足りないところを補完すれば,より細かい分析ができるでしょう。