C/C++プログラマのためのDTrace入門

第3回 マルチスレッド/子プロセス/共有ライブラリ

この記事を読むのに必要な時間:およそ 7 分

関数呼び出しにおける基本的な情報採取に関しては,前回までに説明した手法で十分なのですが,実際の情報採取の際には気を付けるべきトピックが幾つかあります。

今回は,それらのトピックについて説明したいと思います。

マルチスレッド

マルチスレッド化によって性能や応答性の向上を実現するケースは,少なくないでしょう。

特に近年は,個人のデスクトップPCやノートPCでさえ,物理的に複数コアのCPUを搭載するご時勢ですので,CPUの使用効率を高める上でもマルチスレッド化の流れは加速するものと思われます。

マルチスレッド稼動時の関数フロー

マルチスレッドで稼働中のプロセスから DTraceで関数フローを採取した場合,どのような出力が得られるでしょうか?

各スレッドで,リスト1に示すような処理を行う状況を仮定します。

リスト1 各スレッド上で実施される処理

void*
running(void* arg)
{
    int loops = (int)arg;
    int i;

    for(i = 0 ; i < loops ; i += 1){
        f3();
    }

    return NULL;
}

ループ内で呼び出している関数 f3() については,連載第1回のリスト6を参照してください。

この処理を複数のスレッドで実行する際の関数フローを採取してみましょう。関数フロー採取には,リスト2のwatch_flow_whole.dスクリプトを使用します。

リスト2 関数フロー採取スクリプト (watch_flow_whole.d)

pid$target:$1::entry,
pid$target:$1::return
{
}

5つのスレッドを並走させて採取された関数フローの例を,以下に示します(※1)⁠

リスト3 複数スレッドの関数フロー採取 ~ その1

CPU FUNCTION
  0  -> _start
  0    -> __fsr
  0    <- __fsr
  0    -> main
  0      -> running
  0        -> running
  0          -> running
  0            -> running
  0              -> running
  0  -> f3
  0    -> f1
  0    <- f1
  0    -> f2
  0      -> f1
  0      <- f1
  0    <- f2
  0  <- f3
  0  -> f3
  0    -> f1
  0    <- f1
  0    -> f2
....

どの関数フローがどのスレッドで実行されたものか判別がつきませんね。

関数フローが複雑な場合や,より多くのスレッドが関与する場合,各スレッドごとの関数フローの対応を取るだけでもウンザリすることでしょう。

※1)
running() 関数のインデントが変になっているのは,複数スレッドで実行されている影響です。

スレッド識別情報の使用

マルチスレッド稼動時の DTrace 出力の問題点は,それがどのスレッドで採取されたものかがわからない点にあります。

しかし裏を返せば,どのスレッドで採取された情報であるかがわかるようにしてやれば良い,ということにもなります。

Dスクリプトで使用可能な組み込み変数には,スレッドの識別情報として使用可能なtid変数があります。リンク先の説明にもあるように,ユーザプロセスでの採取においてこの変数を使用した場合,pthread_self(3C)呼び出し結果と同等の値を得ることができます。

それでは,組み込み変数tidを併用して関数フローを採取してみましょう。

リスト4 スレッド識別情報の採取

pid$target:$1::entry,
pid$target:$1::return
{
    printf("tid=%d", tid);
}

上記Dスクリプトは,関数の入りentryと出returnの両方で,組み込み変数tidの値を表示することで,どのスレッド上での関数フローであるかを識別可能にしています。

リスト 5 複数スレッドの関数フロー採取 ~ その2

CPU FUNCTION
  0  -> _start                                tid=1
  0    -> __fsr                               tid=1
  0    <- __fsr                               tid=1
  0    -> main                                tid=1
  0      -> running                           tid=2
  0        -> running                         tid=3
  0          -> running                       tid=4
  0            -> running                     tid=5
  0              -> running                   tid=6
  0  -> f3                                    tid=2
  0    -> f1                                  tid=2
  0    <- f1                                  tid=2
  0    -> f2                                  tid=2
  0      -> f1                                tid=2
  0      <- f1                                tid=2
  0    <- f2                                  tid=2
  0  <- f3                                    tid=2
  0  -> f3                                    tid=3
  0    -> f1                                  tid=3
  0    <- f1                                  tid=3
  0    -> f2                                  tid=3
....

スレッド識別情報を表示することで,各スレッド上での関数フローの対応関係が明確になりました。

著者プロフィール

藤原克則(ふじわらかつのり)

Mercurial三昧の日々が嵩じて, いつの間にやら『入門Mercurial Linux/Windows対応』を上梓。凝り性なのが災いして,年がら年中アップアップな一介の実装屋。最近は仕事の縁が元で,OpenSolarisに入れ込む毎日。

コメント

コメントの記入