DTraceBeginners

Solarisのページに戻る

目次

Table of Contents

はじめてのDTrace特集

はじめての DTrace(1) "簡単なことからこつこつと"

スライドのリンク

はじめての DTrace(2)"簡単なことからこつこつと"

スライドのリンク

はじめての DTrace(3)"簡単なことからこつこつと"

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

はじめに

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 利用の可否状況

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

言語利用可能なProvider名Solaris 11/OpenIndiana上でデフォルトでの利用可否、利用方法など
C/C++pid(User-land), fbt(kernel),profile, sched, prockstatなどdefaultでほとんどが利用可
Javahotspot, hotspot_jnidefaultで利用可、但し、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 で有効です
JavaSctiptjavascriptdefaultで使えます。ブラウザ(firefox) が --enable-dtrace オプションでビルドされている必要があります。
Perlperldefaultで使えます
PHPphpSolaris 11 で pkg install 可能な ~PHP5.3 では、php プロバイダーは使えません。今回のでデモでは、PHP5.4 tarball を、/configure --enable-dtrace でビルドしたものを使っています
Pythonpythondefaultで使えます
RubyrubySolaris 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 に置き換えて使う必要があります
TcltclSolaris 11 で pkg install 可能な ~TCL 8.5.12 では、tcl プロバイダーは使えません。今回のデモでは TCL 8.5.15 tarballを /configure --enable-dtrace でビルドしたものを使っています
ShellshOpenSolaris の時は、(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)

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)

参考

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

JSDT(Java Statically Defined Tracing)

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 になっているのが、気になっているところですが、なんとかトレースできてます。

参考

  1. https://blogs.oracle.com/kamg/entry/announcing_statically_defined_dtrace_probes
  2. http://www.oracle.com/technetwork/articles/servers-storage-dev/java-tracing-1612018.html

C言語プログラムのトレース

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::'

各プログラム言語でのトレース

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

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

ということで

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

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

Javaプログラムのトレース

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 のトレース

ブラウザ(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 スクリプトのトレース

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 のトレース

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 のトレース

トレース用の 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 のトレース

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 のトレース

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$

参考文献/リンク

  1. お薦めの参考本: DTrace - Brendan Gregg, Jim Mauro 著http://www.dtracebook.com/index.php/Main_Page
  2. DTraceToolKit http://www.brendangregg.com/dtrace.html
  3. SolarisInternal http://www.solarisinternals.com/wiki/index.php/DTrace_Topics
  4. SolarisInternal http://www.solarisinternals.com/wiki/index.php/DTrace_Topics
  5. Wikis https://wikis.oracle.com/display/DTrace/DTrace
  6. 藤原さんの DTrace Day 2010.03 のスライド ユーザプログラムでの DTrace 導入編