DTraceBeginnersのソース

#freeze
[[Solarisのページに戻る>Solaris]]

目次
#contentsx

* はじめてのDTrace特集 [#m641476e]
** はじめての DTrace(1) "簡単なことからこつこつと" [#z80b8aad]
[[スライドのリンク>http://www.slideshare.net/shojiha/dtrace-for-biginners-part1]]
** はじめての DTrace(2)"簡単なことからこつこつと" [#gcf6f527]
[[スライドのリンク>http://www.slideshare.net/shojiha/dtrace-biginners2]]
** はじめての DTrace(3)"簡単なことからこつこつと" [#y2b1c476]

DTrace をプログラミングで活用する初歩的なわざを紹介します。
Java, JavaScript, Ruby,Perl, PHP, Python, %%sh%%の組み込みプロバイダーの基本的な使い方や
Java や C言語で、ユーザ定義のプロバイダーの作り方と使い方など。今さら人には聞けない、といっても ネットに参考情報も少ない初心者向けの基本を簡単なサンプルプログラムとデモで紹介します。 

*** はじめに [#r0d8a3da]
DTrace というと、稼働中のシステムで CPU や IOの負荷を調べたりとかシステムの監視には便利なものですが、こういう状況で DTraceを使える人は正直とても少ないと思っています。もっと身近で、例えば自分で書いたプログラムやスクリプトの検証やデバッグで DTrace が使えたり、デスクトップ上でよく使う Web アプリケーションを DTrace で監視できたら、DTrace を使う機会も、用途も広がるのではないかと思います。今回のデモは、DTrace を使ってみたいけど、なかなか機会がないと思われるような人達へ、最初"きっかけ"になればと思っています。

今回紹介する内容の元ネタは、4~5年前にも紹介した古いものですが、最近の状況を見てなかったこともあり、いい機会と思い、久々にデモを作って再確認してみました。今回もDTraceの詳細の使い方とか高度なテクニックとかは一切説明いたしません(というか、説明できません)、各言語系で、DTrace が使えるようになるまでを、簡単に説明致します。また、今回使う DTrace のスクリプトや、各言語のサンプルプログラムは、Solaris 10 や Solaris 11 でデフォルトでインストールされる DTrace Tool kit をそのまま使っています(Solaris 11 では、/usr/dtrace/DTT の下にインストールされています)、不足しているコードは、このページから参照できますので、ぜひ実際に試してみてください。実際にトレースできると、ついついDTrace でいろんなことをしてみたくなると思います。
*** 各言語と使える Provider と DTrace 利用の可否状況 [#k4965f87]

最新の Oracle Solaris 11.2 Beta 上で調べてみました。個人的な検証ですので非公式ですし、将来の対応についてはコメントもできません。参考程度に読んでいただければと思います。

|言語|利用可能なProvider名|Solaris 11/OpenIndiana上でデフォルトでの利用可否、利用方法など|
|C/C++|pid(User-land), fbt(kernel),profile, sched, prockstatなど|defaultでほとんどが利用可|
|Java|hotspot, hotspot_jni|defaultで利用可、但し、method-entry/method-return,object-alloc,monitor Probe は、default では OFF になっているため、java(JVM) 起動時に、java -XX:+ExtendedDTraceProbes で指定する、また jinfo -flag +ExtendedDTraceProves で動的に ON にする,また今回説明する JSDT(Java Statically Defined Tracing は JDK 1.7 で有効です|
|JavaSctipt|javascript|defaultで使えます。ブラウザ(firefox) が --enable-dtrace オプションでビルドされている必要があります。|
|Perl|perl|defaultで使えます|
|PHP|php|Solaris 11 で pkg install 可能な ~PHP5.3 では、php プロバイダーは使えません。今回のでデモでは、PHP5.4 tarball を、/configure --enable-dtrace でビルドしたものを使っています|
|Python|python|defaultで使えます|
|Ruby|ruby|Solaris 11 で pkg install 可能な ~ Ruby 1.9 では ruby プロバイダーは使えません。Ruby 2.0 以降で dtrace 対応されており、今回のデモでは、Ruby 2.0 のtarball を、/configure --enable-dtrace でビルドしたものを使っています。また DTrace Toolkit の ruby probe のうち、function-entry/function-return probe は、method-entry/method-return に置き換えて使う必要があります|
|Tcl|tcl|Solaris 11 で pkg install 可能な ~TCL 8.5.12 では、tcl プロバイダーは使えません。今回のデモでは TCL 8.5.15 tarballを /configure --enable-dtrace でビルドしたものを使っています|
|Shell|sh|OpenSolaris の時は、(Bourne) sh provider 実装の計画 PSARC/2008/008 がありましたが、結局 Oracle Solaris には実装されなかったと思います。今となってはプロトタイプの sh も入手できないので、今回のデモでは割愛します_o_|

各言語で使える DTrace スクリプトと、サンプルコードは、Oracle Solaris 11 の場合は /usr/dtace/DTT の下にあります。OpenIndiana 系は、/opt/DTT の下にあります。

  $ cd /usr/dtrace/DTT
  $ ls
  Apps         FS           Locks        Php          System       dvmstat      iosnoop
  Bin          Guide        Man          Proc         Tcl          errinfo      iotop
  Code         Include      Mem          Python       User         execsnoop    opensnoop
  Cpu          Java         Misc         README       Version      hotkernel    procsystime
  Disk         JavaScript   Net          Ruby         Zones        hotuser      rwsnoop
  Docs         Kernel       Notes        Shell        dexplorer    install      rwtop
  Examples     License      Perl         Snippits     dtruss       iopattern    statsnoop

*** USDT(User Statically Defined Tracing) [#zd2b1b79]

Solaris kernel系の probe は、実装されているものを通常使いますが、C/C++ のプログラムに自分で定義した Provider や Probe を静的に埋め込むことができます。DTrace off では何もしませんが、on にすると、自分で仕込んで置いた監視点(probe) をトレースすることが可能です。

作り方は、C言語の知識があれば、いたって簡単でして、Provider 定義用の <適当な名前>.d ファイルを作成して、
#include <sys/sdt.h> に用意されている DTRACE_PROBE* のマクロを、プログラム中の観測点に記入するだけです。

myserv.d
  provider myserv {
          probe check(char *);
  };

Tips: 最後の } 後に ; の記入が必要です。

func_abc.c
  #include <stdio.h>
  #include <unistd.h>
  #include <sys/sdt.h>
  
  int func_a();
  int func_b();
  int func_c();
  
  
  int main(void)
  {
          func_a();
  }
  
  int func_a()
  {
  	/* probe: check */
        DTRACE_PROBE1(myserv,check,"FUNC_A");
  	printf("Function A\n");
	sleep(1);
        func_b();
  
  }
  int func_b()
  {
  	/* probe: check */
        DTRACE_PROBE1(myserv,check,"FUNC_B");
        printf("Function B\n");
        sleep(1);
        func_c();
  }
  int func_c()
  {
  	/* probe: check */
        DTRACE_PROBE1(myserv, check,"FUNC_C");
  	printf("Function C\n");
  	sleep(1);
  }


プログラムのコンパイル

  $ cc -c func_abc.c

dtrace コマンドで、provider 定義オブジェクトを作成

  $ dtrace -G -s myserv.d func_abc.o

オブジェクトのリンク

  $ cc -o func_abc myserv.o func_abc.o

実行確認

  $ ./func_abc
  Function A
  Function B
  Function C
  $ 

DTrace on でチェックポイント確認

  $ dtrace -c ./func_abc -n 'myserv$target:::check { trace(copyinstr(arg0)); }'
  dtrace: description 'myserv$target:::check ' matched 3 probes
  Function A
  Function B
  Function C
   CPU     ID                    FUNCTION:NAME
     1  96890                     func_a:check   FUNC_A                           
     1  96889                     func_b:check   FUNC_B                           
     1  96888                     func_c:check   FUNC_C                           
  dtrace: pid 2827 has exited
  
  $ 


この例は、監視点を通ったかどうかだけを見る、もっとも簡単な例ですが、DTRACE_PROBE*マクロを使って、関数の返り値、引数等も定義、監視することも可能です。

sys/sdt.h から
  #define DTRACE_PROBE(provider, name)
  #define DTRACE_PROBE1(provider, name, arg1)
  #define DTRACE_PROBE2(provider, name, arg1, arg2)
  #define DTRACE_PROBE3(provider, name, arg1, arg2, arg3)
  #define DTRACE_PROBE4(provider, name, arg1, arg2, arg3, arg4)
  #define DTRACE_PROBE5(provider, name, arg1, arg2, arg3, arg4, arg5)


参考
+ [[http://dtrace.org/guide/chp-usdt.html>http://dtrace.org/guide/chp-usdt.html]]
+ [[https://wikis.oracle.com/display/DTrace/Statically+Defined+Tracing+for+User+Applications>https://wikis.oracle.com/display/DTrace/Statically+Defined+Tracing+for+User+Applications]]
+ [[http://sat-store.jp/technicalnote/solairs-dtrace/>http://sat-store.jp/technicalnote/solairs-dtrace/]]
+ 藤原さんの連載記事: C/C++プログラマのためのDTrace入門 [[http://gihyo.jp/dev/serial/01/dtrace4cpg>http://gihyo.jp/dev/serial/01/dtrace4cpg]]
+ 藤原さんの DTrace Day 2010.03 のスライド [[ユーザプログラムでの DTrace 応用編>http://foozy.bitbucket.org/dtrace-logging/advanced.ja.html]]

*** JSDT(Java Statically Defined Tracing) [#n0ad076f]

Java で、ユーザ定義の DTrace Provider を使用する方法です。JavaSE7 (JDK1.7) で対応されました。なんとか動いてますが、Java 言語には詳しくないので、つっこみどころ満載だとおもいます(^^;

ユーザ定義のProvider の定義、<Provider名>.java ファイルを作成します。

MyProvider.java
  public interface MyProvider extends com.sun.tracing.Provider {
      void MyCheckpoint(String greeting);
  }

MyProvider と MyCheckpoint が、自分で定義した Provider と Prove 名です。

DTrace の Java サンプルとして使われてる TestGreeting.java Greeting.java です。

Greeting.java
  public class Greeting {
        public void greet() {
                System.out.println("Hello DTrace!");
        }
  }

TestGreeting.java
  public class TestGreeting {
        public static void main(String[] args) {
                Greeting hello = new Greeting();
                while (true) {
                        hello.greet();
                        try {
                                Thread.sleep(1000);
                        } catch (InterruptedException e) {
                        }
                }
        }
  }

Greeting.java の greet() に prove を仕込みます。

更新した Greeting.java
  import com.sun.tracing.*;
  
  public class Greeting {
        ProviderFactory factory = ProviderFactory.getDefaultFactory();
        MyProvider p = factory.createProvider(MyProvider.class);
        public void greet() {
                String greeting = "Hello DTrace!";
                System.out.println("greeting);
                p.MyCheckpoit(greeting);
        }
  }

p.Mycheckpoint(); が仕込んだ Probe です。

  $ java -version
  java version "1.7.0_55"
  Java(TM) SE Runtime Environment (build 1.7.0_55-b13)
  Java HotSpot(TM) Server VM (build 24.55-b03, mixed mode)

Java コンパイルすると以下の警告がでますが、MyProvider.class, Greeting.class, TestGreeting.class が作成されます。

  $ javac TestGreeting.java
  Greeting.java:4: 警告: ProviderFactoryは内部所有のAPIであり、今後のリリースで削除される可能性があります
	ProviderFactory factory = ProviderFactory.getDefaultFactory();
	^
  Greeting.java:4: 警告: ProviderFactoryは内部所有のAPIであり、今後のリリースで削除される可能性があります
	ProviderFactory factory = ProviderFactory.getDefaultFactory();
	                          ^
  Greeting.java:4: 警告: Providerは内部所有のAPIであり、今後のリリースで削除される可能性があります
	ProviderFactory factory = ProviderFactory.getDefaultFactory();
  ^
  警告3個

実行例
  $ java TestGreeting
  Hello DTrace!
  Hello DTrace!
  Hello DTrace!
  Hello DTrace!
  Hello DTrace!
  ...

DTrace で Prove を監視してみます。

  # jps
  5199 Jps
  5198 TestGreeting

  # dtrace -n 'MyProvider*:::Mycheckpoint {trace(copyinstr(arg0));}' -p 5198
  dtrace: description 'MyProvider*:::MyCheckpoint ' matched 1 probe
 CPU     ID                    FUNCTION:NAME
   0  96888         unspecified:MyCheckpoint   Hello DTrace!                    
   0  96888         unspecified:MyCheckpoint   Hello DTrace!                    
   0  96888         unspecified:MyCheckpoint   Hello DTrace!                    
   0  96888         unspecified:MyCheckpoint   Hello DTrace!                    
   0  96888         unspecified:MyCheckpoint   Hello DTrace!                    
   0  96888         unspecified:MyCheckpoint   Hello DTrace!                    
   0  96888         unspecified:MyCheckpoint   Hello DTrace!
   
FUNCTION が、unspecified になっているのが、気になっているところですが、なんとかトレースできてます。

参考
+ [[https://blogs.oracle.com/kamg/entry/announcing_statically_defined_dtrace_probes>https://blogs.oracle.com/kamg/entry/announcing_statically_defined_dtrace_probes]]
+ [[http://www.oracle.com/technetwork/articles/servers-storage-dev/java-tracing-1612018.html>http://www.oracle.com/technetwork/articles/servers-storage-dev/java-tracing-1612018.html]]

*** C言語プログラムのトレース [#a500b0a6]

Solaris/UNIX 上であれば、Cプログラムはたくさんあるので、サンプル Cプログラムでの実行例は割愛いします。ユーザランドのプログラムであれば、pid provider を使うのが簡単でしょう。kernel の場合は、fbt プロバイダーでトレースできます。システムコールのトレースという点では truss(1)でも同様なことはできますが、DTrace では関数を指定したり、条件を設定したりで監視点を絞り込んだりできます。

ユーザランドの例

  # dtrace -n 'pid$target:::entry' -c date

カーネルの例

  # dtrace -n 'fbt:zfs::'

~-F をつけるとFlow 形式で表示されます。

  # dtrace -Fn 'fbt:zfs::'

*** 各プログラム言語でのトレース [#ba8cb663]

以下で紹介する各言語でのトレースでは、下記のような簡単なプログラムを実行し、期待どおりに各ファンクションが実行されているか DTrace でトレースします。

  main {
     func_a {
            func_b {
                    func_c {};
            }
     }
  }

ということで

  main 開始 
        --> func_a 開始 
                  --> func_b 開始
                             --> func_c 開始
                             <--  func_c 終了
             <-- func_b 終了
        <-- func_a 終了
  main 終了

と期待の順番どおりにトレースできることを検証します。


*** Javaプログラムのトレース [#wd768f31]

Java トレース用のサンプルプログラム

/usr/dtrace/DTT/Code/Java/Func_abc.java

  public class Func_abc {
    public static void func_c() {
        System.out.println("Function C");
        try {
            Thread.currentThread().sleep(1000);
        } catch (Exception e) { }
    }
    public static void func_b() {
        System.out.println("Function B");
        try {
            Thread.currentThread().sleep(1000);
        } catch (Exception e) { }
        func_c();
    }
    public static void func_a() {
        System.out.println("Function A");
        try {
            Thread.currentThread().sleep(1000);
        } catch (Exception e) { }
        func_b();
    }
  
    public static void main(String[] args) {
        func_a();
    }
  }

コンパイルします。

  $ javac Func_abc.java

実行確認
  $ java Func_abc
  Function A
  Function B
  Function C
  $ 

/usr/dtrace/DTT/Java/j_flow.d を使って snoop のように監視します。
この script では、method-entry/method-return probe を監視するので、起動時に
~-XX:+ExtendedDTraceProbes を指定します。

  $ j_flow.d -c 'java -XX:+ExtendedDTraceProbes Func_abc'

情報が多すぎて、サンプルプログラムのトレースがよく見えないので grep をかけます。

  j_flow.d -c 'java -XX:+ExtendedDTraceProbes Func_abc'| grep Func_abc
  2   7461 98824244966      -> Func_abc.main
  2   7461 98824244972        -> Func_abc.func_a
  2   7461 98825250665          -> Func_abc.func_b
  2   7461 98826251955            -> Func_abc.func_c
  2   7461 98827253782            <- Func_abc.func_c
  2   7461 98827253788          <- Func_abc.func_b
  2   7461 98827253793        <- Func_abc.func_a
  2   7461 98827253799      <- Func_abc.main
  ^C$

期待どおりに動いています。j_classflow.d を使えば、引数で指定される Class 名に一致した場合のみ print しますので、上と同じことができます。

  $ ./j_classflow.d Func_abc -c 'java -XX:+ExtendedDTraceProbes Func_abc'
  C    PID TIME(us)         -- CLASS.METHOD
  1   7480 99116649107      -> Func_abc.main
  1   7480 99116649121        -> Func_abc.func_a
  Function A
  1   7480 99117651508          -> Func_abc.func_b
  Function B
  1   7480 99118652157            -> Func_abc.func_c
  Function C
  1   7480 99119652788            <- Func_abc.func_c
  1   7480 99119652796          <- Func_abc.func_b
  1   7480 99119652803        <- Func_abc.func_a
  1   7480 99119652809      <- Func_abc.main
  ^C

j_thread.d スクリプトを使ってもっと複雑な Java プログラムをトレースしてみます。

  $ j_thread.d -c 'java -jar /usr/java/demo/jfc/Java2D/Java2Demo.jar'

Java2Demoは、Solaris 11 の場合、pkg install java-demo-6 or java-demo-7 でインストールされます。

  TIME                    PID/TID   -- THREAD
  2014 May 28 02:42:29    7515/8     => Reference Handler
  2014 May 28 02:42:29    7515/9     => Finalizer
  2014 May 28 02:42:29    7515/10    => Signal Dispatcher
  2014 May 28 02:42:29    7515/11    => C2 CompilerThread0
  2014 May 28 02:42:29    7515/12    => C2 CompilerThread1
  2014 May 28 02:42:29    7515/13    => Service Thread
  2014 May 28 02:42:30    7515/15    => Java2D Disposer
  2014 May 28 02:42:31    7515/16    => AWT-XAWT
  2014 May 28 02:42:31    7515/17    => process reaper
  2014 May 28 02:42:31    7515/17    <= process reaper


*** JavaScript のトレース [#j612a80b]

ブラウザ(firefox) が DTrace 有効である必要があります。

JavaScript トレース用のサンプルプログラム

/usr/dtrace/DTT/Code/JavaScript/func_slow.html

  <HTML>
  <HEAD><TITLE>func_slow, JavaScript</TITLE></HEAD>
  <BODY>
  <SCRIPT type="text/javascript">
  function func_c() {
  	document.write("Function C<br>")
  	for (i = 0; i < 30000; i++) {
  		j = i + 1
  	}
  }
  
  function func_b() {
  	document.write("Function B<br>")
  	for (i = 0; i < 20000; i++) {
  		j = i + 1
  	}
  	func_c()
  }
  
  function func_a() {
  	document.write("Function A<br>") 
  	for (i = 0; i < 10000; i++) {
  		j = i + 1
  	}
  	func_b()
  }
  
  func_a()
  </SCRIPT>
  </BODY>
  </HTML>


JavaScript 用の snoop トレース js_flow.d でトレースします。

  $ firefox file:///usr/dtrace/DTT/Code/JavaScript/func_slow.html &

  $ /usr/dtrace/DTT/JavaScript/js_flow.d | grep func_slow
  3 11195215654      func_slow.html         -> func_a
  3 11195216169      func_slow.html           -> func_b
  3 11195216634      func_slow.html             -> func_c
  3 11195216935      func_slow.html             <- func_c
  3 11195216945      func_slow.html           <- func_b
  3 11195216951      func_slow.html         <- func_a
  3 11195216957      func_slow.html         <- (null)
  ^C$ 
*** Perl スクリプトのトレース [#ga323047]

Perl スクリプトのトレース用のサンプルプログラム

/usr/dtrace/DTT/Code/Perl/func_abc.pl

  #!/usr/bin/perl -w
  
  sub func_c {
      print "Function C\n";
      sleep 1;
  }
  
  sub func_b {
      print "Function B\n";
      sleep 1;
      func_c();
  }
  
  sub func_a {
      print "Function A\n";
      sleep 1;
      func_b();
  }

実行確認

  $ ./func_abc.pl
  Function A
  Function B
  Function C


Perl 用の snoop トレース、pl_flow.d でトレースします。

  $ /usr/dtrace/DTT/Perl/pl_flow.d -c ./func_abc.pl

  C TIME(us)         FILE             -- SUB
  Function A
  3 124813901003     func_abc.pl      -> func_a
  Function B
  2 124814901131     func_abc.pl        -> func_b
  Function C
  3 124815901191     func_abc.pl          -> func_c
  3 124816901253     func_abc.pl          <- func_c
  3 124816901264     func_abc.pl        <- func_b
  3 124816901271     func_abc.pl      <- func_a
  ^C
*** PHP のトレース [#mc56a6f6]

Solaris 11.2 Beta 環境で pkg install 可能な PHP 5.3.28 は DTrace が有効ではありません。Web Stack として提供されていた PHP は、5.3.99 で DTrace が enable になっています。 

  # php -v
  PHP 5.3.28 (cli) (built: Apr  9 2014 18:32:50) 
  Copyright (c) 1997-2013 The PHP Group
  Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies
    with Xdebug v2.2.0, Copyright (c) 2002-2012, by Derick Rethans
    with Suhosin v0.9.33, Copyright (c) 2007-2012, by SektionEins GmbH

今回のデモでは手っ取り早く、Open Source の PHP 5.4 の tarball からビルドして使いました。

 
  $ cd php-5.4.28
  $ ./configure --enable-dtrace
  $ make
  $ sudo make install

  $ /usr/local/bin/php -v
  PHP 5.4.28 (cli) (built: May 26 2014 12:16:59) 
  Copyright (c) 1997-2014 The PHP Group
  Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies

''尚、Openindiana 用の DTrace 付き PHP 5.4 のビルドとパッケージ化は、現在 yamachan さんが作業中のことです。''

  $ /usr/local/bin/php -i | grep -i "dtrace support"
  DTrace Support => enabled

PHP トレース用のサンプルプログラム
/usr/dtrace/DTT/Code/Php/func_abc.php

  <?php
  function func_c()
  {
  	echo "Function C\n";
  	sleep(1);
  }
  
  function func_b()
  {
  	echo "Function B\n";
  	sleep(1);
  	func_c();
  }
  
  function func_a()
  {
  	echo "Function A\n";
  	sleep(1);
  	func_b();
  }
  
  func_a();
  ?>

実行確認

  $ /usr/local/bin/php ./func_abc.php
  Function A
  Function B
  Function C

php_flowinfo.d を使って PHP function の snoop トレースしてみる。


  $ /usr/dtrace/DTT/Php/php_flowinfo.d -c '/usr/local/bin/php ./func_abc.php'
  C    PID/TID   DELTA(us)              FILE:LINE TYPE     -- FUNC
  Function A
  1   2885/1             1      func_abc.php:22   func     -> func_a
  Function B
  1   2885/1       1000052      func_abc.php:19   func       -> func_b
  Function C
  1   2885/1       1000053      func_abc.php:12   func         -> func_c
  1   2885/1       1000048      func_abc.php:12   func         <- func_c
  1   2885/1            12      func_abc.php:19   func       <- func_b
  1   2885/1             6      func_abc.php:22   func     <- func_a
  ^C




*** Python のトレース [#v06984d6]

トレース用の Python のサンプルプログラム
/usr/dtrace/DTT/Code/Python/func_abc.py

  #!/usr/bin/python
  
  import time
  
  def func_c():
  	print "Function C"	
  	time.sleep(1)
  
  def func_b():
  	print "Function B"
  	time.sleep(1)
  	func_c()
  
  def func_a():
  	print "Function A"
  	time.sleep(1)
  	func_b()
  
  func_a()

実行確認
  $ python -V
  Python 2.6.8

  $ python ./func_abc.py
  Function A
  Function B
  Function C

py_flowinfo.d スクリプトを使って Python のfunction の snoop トレースする。

  $ /usr/dtrace/DTT/Python/py_flowinfo.d -c 'python ./func_abc.py' | grep   func_abc
  1   2994        339       func_abc.py:3    func     -> <module>
  1   2994       2753       func_abc.py:14   func       -> func_a
  3   2994    1000203       func_abc.py:9    func         -> func_b
  3   2994    1000047       func_abc.py:5    func           -> func_c
  3   2994    1000041       func_abc.py:7    func           <- func_c
  3   2994         14       func_abc.py:12   func         <- func_b
  3   2994          6       func_abc.py:17   func       <- func_a
  3   2994          6       func_abc.py:19   func     <- <module>
  ^C$ 

*** Ruby のトレース [#w7311f14]

Ruby は Ruby 2.0 以降に DTrace 対応されており、Solaris 11 で pkg install 可能な ruby-19 では DTrace は対応されておりません。

  $ ruby -v
  ruby 1.9.3p484 (2013-11-22 revision 43786) [amd64-solaris2.11]

このデモでは、オープンソースの Ruby 2.0 tarball からビルドして使っています。

  $ cd ruby-2.0.0-p481
  $ ./configure --enable-dtrace
  $ make
  $ sudo make install

  $ /usr/local/bin/ruby -v
  ruby 2.0.0p481 (2014-05-08 revision 45883) [i386-solaris2.11]

Ruby トレース用のサンプルプログラム
/usr/dtrace/DTT/Code/Ruby/func_abc.rb

  #!/usr/local/bin/ruby -w
  
  def func_c
    print "Function C\n"
    sleep 1
  end
  
  def func_b
    print "Function B\n"
    sleep 1
    func_c
  end
  
  def func_a
    print "Function A\n"
    sleep 1
    func_b
  end
  
  func_a

実行確認

  $ ./func_abc.rb
  Function A
  Function B
  Function C

rb_flow.d を使って Ruby を snoop トレースします。尚、rb_flow.d の中の probeの部分は
function-entry -> method-entry, function-return -> method-return に書き換える必要があります。

  ruby*:::method-entry
  {
          printf("%3d %-16d %-22s %*s-> %s::%s\n", cpu, timestamp / 1000,
              basename(copyinstr(arg2)), self->depth * 2, "", copyinstr(arg0),
              copyinstr(arg1));
          self->depth++;
  }
  
  ruby*:::method-return
  {
          self->depth -= self->depth > 0 ? 1 : 0;
          printf("%3d %-16d %-22s %*s<- %s::%s\n", cpu, timestamp / 1000,
              basename(copyinstr(arg2)), self->depth * 2, "", copyinstr(arg0),
              copyinstr(arg1));
  }



  $ /usr/dtrace/DTT/Ruby/rb_flow.d -c ./func_abc.rb | grep func_abc
  0 3864881979       func_abc.rb            -> Object::func_a
  0 3865882113       func_abc.rb              -> Object::func_b
  0 3866882160       func_abc.rb                -> Object::func_c
  0 3867882206       func_abc.rb                <- Object::func_c
  0 3867882216       func_abc.rb              <- Object::func_b
  0 3867882223       func_abc.rb            <- Object::func_a
  ^C$ 

*** Tcl のトレース [#f1ad3505]

Solaris 11 で、pkg install 可能な、tcl-8 は DTrace が有効ではありません。
今回のデモでは、オープンソースの Tcl 8.5.15 tarball からビルドしたものを使いました。

  $ cd tcl8.5.15
  $ ./configure --enable-dtrace
  $ make
  $ sudo make install

Tcl トレース用のサンプルプログラム
/usr/dtrace/DTT/Code/Tcl/func_abc.tcl

  #!/usr/local/bin/tclsh
  
  proc func_c {} {
  	puts "Function C"
  	after 1000
  }
  
  proc func_b {} {
  	puts "Function B"
  	after 1000
  	func_c
  }
  
  proc func_a {} {
  	puts "Function A"
  	after 1000
  	func_b
  }
  
  func_a

実行確認

  $ ./func_abc.tcl
  Function A
  Function B
  Function C

Tcl トレース用のスクリプト tcl_flow.d で snoop トレースします。

  $ /usr/dtrace/DTT/Tcl/tcl_flow.d -c ./func_abc.tcl | grep func_
  1   3859 9466859704        > func_a
  1   3859 9466859723         -> func_a
  3   3859 9467859881            > func_b
  3   3859 9467859909             -> func_b
  3   3859 9468859970                > func_c
  3   3859 9468859997                 -> func_c
  2   3859 9469860232                 <- func_c
  2   3859 9469860238                < func_c
  2   3859 9469860243             <- func_b
  2   3859 9469860246            < func_b
  2   3859 9469860249         <- func_a
  2   3859 9469860252        < func_a
  ^C$

*** 参考文献/リンク [#o0a1692b]

+ お薦めの参考本: DTrace - Brendan Gregg, Jim Mauro 著[[http://www.dtracebook.com/index.php/Main_Page>http://www.dtracebook.com/index.php/Main_Page]]
+ DTraceToolKit [[http://www.brendangregg.com/dtrace.html#DTraceToolkit]]
+ SolarisInternal [[http://www.solarisinternals.com/wiki/index.php/DTrace_Topics>http://www.brendangregg.com/dtrace.html#DTraceToolkit]]
+ SolarisInternal [[http://www.solarisinternals.com/wiki/index.php/DTrace_Topics ]]
+ Wikis [[https://wikis.oracle.com/display/DTrace/DTrace>https://wikis.oracle.com/display/DTrace/DTrace]]
+ 藤原さんの DTrace Day 2010.03 のスライド [[ユーザプログラムでの DTrace 導入編>http://foozy.bitbucket.org/dtrace-logging/intro.ja.html]]