## PHP および DTrace の使用

DTrace 動的トレーシングをサポートするプラットフォームでは、 DTrace 静的プローブ付きで PHP を構成できます。

### DTrace 静的プローブのために PHP を構成

OS の DTrace サポートを有効にするには、 プラットフォーム固有の外部のドキュメントを参照ください。 例えば、Oracle Linux では UEK3 を起動して下記を行います。

    # modprobe fasttrap
    # chmod 666 /dev/dtrace/helper

`chmod` を使用する代わりに、 デバイスのアクセスを特定のユーザーに制限するために ACL パッケージ・ルールを使用できるでしょう。

`--enable-dtrace` 構成パラメータとともに PHP をビルドします。

    # ./configure --enable-dtrace ...
    # make
    # make install

これは、 コア PHP で静的プローブを利用可能にします。 それら自身のプローブを提供するどの PHP 拡張モジュールも、 共用拡張モジュールとして別々にビルドするべきです。

静的プローブを有効にするには、USE_ZEND_DTRACE=1環境変数を対象となるPHPプロセスにセットします。

### コア PHP の DTrace 静的プローブ

PHP では、以下の静的プローブが使用できます
プローブ名 | プローブの説明 | プローブの引数
--- | --- | ---
`request-startup` | リクエスト開始時に発射されます。 | char *file, char *request_uri, char *request_method
`request-shutdown` | リクエスト・シャットダウン時に発射されます。 | char *file, char *request_uri, char *request_method
`compile-file-entry` | スクリプトのコンパイル開始時に発射されます。 | char *compile_file, char *compile_file_translated
`compile-file-return` | スクリプトのコンパイル終了時に発射されます。 | char *compile_file, char *compile_file_translated
`execute-entry` | op コードの配列が実行される際に発射されます。 例えば、関数の呼び出し、インクルードおよびジェネレータ続行時に発射されます。 | char *request_file, int lineno
`execute-return` | op コードの配列の実行後に発射されます。 | char *request_file, int lineno
`function-entry` | PHP エンジンが、PHP の関数またはメソッドの呼び出しに入り込む際に発射されます。 | char *function_name, char *request_file, int lineno, char *classname, char *scope
`function-return` | PHP エンジンが、PHP の関数またはメソッドの呼び出しから戻る際に発射されます。 | char *function_name, char *request_file, int lineno, char *classname, char *scope
`exception-thrown` | 例外がスローされる際に発射されます。 | char *classname
`exception-caught` | 例外が捕捉される際に発射されます。 | char *classname
`error` | error_reporting レベルにかかわらず、 エラー発生時に発射されます。 | char *errormsg, char *request_file, int lineno

PHP 拡張モジュールには、追加の静的プローブもあるかもしれません。

### PHP の DTrace 静的プローブ一覧

使用できるプローブを一覧表示するには、 PHP プロセスを開始して以下のように実行します。

    # dtrace -l

出力は以下のようになります。

       ID   PROVIDER            MODULE                          FUNCTION NAME
       [ . . . ]
        4   php15271               php               dtrace_compile_file compile-file-entry
        5   php15271               php               dtrace_compile_file compile-file-return
        6   php15271               php                        zend_error error
        7   php15271               php  ZEND_CATCH_SPEC_CONST_CV_HANDLER exception-caught
        8   php15271               php     zend_throw_exception_internal exception-thrown
        9   php15271               php                 dtrace_execute_ex execute-entry
       10   php15271               php           dtrace_execute_internal execute-entry
       11   php15271               php                 dtrace_execute_ex execute-return
       12   php15271               php           dtrace_execute_internal execute-return
       13   php15271               php                 dtrace_execute_ex function-entry
       14   php15271               php                 dtrace_execute_ex function-return
       15   php15271               php              php_request_shutdown request-shutdown
       16   php15271               php               php_request_startup request-startup

PROVIDER 列の値は、`php` および 現在実行中の PHP プロセスのプロセス ID から構成されます。

Apache Web サーバーが実行中の場合、モジュール名は、例えば libphp5.so かもしれません。 そして、実行中の Apache プロセスごとに 1 つ、 一覧表の複数のブロックが存在するかもしれません。

FUNCTION 列は、各プロバイダが配置された PHP 内部の C 実装関数名を参照します。

PHP プロセスが実行されていない場合、PHP プローブは表示されません。

### PHP についての DTrace の例

この例では、DTrace の D スクリプト言語の基本を示します。

例1 DTrace を使用してすべての PHP 静的プローブをトレースするためのall_probes.d

    #!/usr/sbin/dtrace -Zs

    #pragma D option quiet

    php*:::compile-file-entry
    {
        printf("PHP compile-file-entry\n");
        printf("  compile_file              %s\n", copyinstr(arg0));
        printf("  compile_file_translated   %s\n", copyinstr(arg1));
    }

    php*:::compile-file-return
    {
        printf("PHP compile-file-return\n");
        printf("  compile_file              %s\n", copyinstr(arg0));
        printf("  compile_file_translated   %s\n", copyinstr(arg1));
    }

    php*:::error
    {
        printf("PHP error\n");
        printf("  errormsg                  %s\n", copyinstr(arg0));
        printf("  request_file              %s\n", copyinstr(arg1));
        printf("  lineno                    %d\n", (int)arg2);
    }

    php*:::exception-caught
    {
        printf("PHP exception-caught\n");
        printf("  classname                 %s\n", copyinstr(arg0));
    }

    php*:::exception-thrown
    {
        printf("PHP exception-thrown\n");
        printf("  classname                 %s\n", copyinstr(arg0));
    }

    php*:::execute-entry
    {
        printf("PHP execute-entry\n");
        printf("  request_file              %s\n", copyinstr(arg0));
        printf("  lineno                    %d\n", (int)arg1);
    }

    php*:::execute-return
    {
        printf("PHP execute-return\n");
        printf("  request_file              %s\n", copyinstr(arg0));
        printf("  lineno                    %d\n", (int)arg1);
    }

    php*:::function-entry
    {
        printf("PHP function-entry\n");
        printf("  function_name             %s\n", copyinstr(arg0));
        printf("  request_file              %s\n", copyinstr(arg1));
        printf("  lineno                    %d\n", (int)arg2);
        printf("  classname                 %s\n", copyinstr(arg3));
        printf("  scope                     %s\n", copyinstr(arg4));
    }

    php*:::function-return
    {
        printf("PHP function-return\n");
        printf("  function_name             %s\n", copyinstr(arg0));
        printf("  request_file              %s\n", copyinstr(arg1));
        printf("  lineno                    %d\n", (int)arg2);
        printf("  classname                 %s\n", copyinstr(arg3));
        printf("  scope                     %s\n", copyinstr(arg4));
    }

    php*:::request-shutdown
    {
        printf("PHP request-shutdown\n");
        printf("  file                      %s\n", copyinstr(arg0));
        printf("  request_uri               %s\n", copyinstr(arg1));
        printf("  request_method            %s\n", copyinstr(arg2));
    }

    php*:::request-startup
    {
        printf("PHP request-startup\n");
        printf("  file                      %s\n", copyinstr(arg0));
        printf("  request_uri               %s\n", copyinstr(arg1));
        printf("  request_method            %s\n", copyinstr(arg2));
    }

このスクリプトは、dtrace に対して `-Z` オプションを使用します。 それにより、実行中の PHP プロセスがない場合に実行できるようになります。 もしこのオプションが書き落とされた場合、 モニターされているプローブがどれも存在しないことがわかっているので、 スクリプトは即座に終了します。

スクリプトは、PHP スクリプト実行中の期間全体にわたって、 すべてのコア PHP 静的プローブ・ポイントをトレースします。 D スクリプトを実行します。

    # ./all_probes.d

PHP スクリプトまたはアプリケーションを実行します。 モニタリングの D スクリプトは、各プローブが発射されるたびに その引数を出力します。

モニタリングが完了した際には、``CTRL`+`C`` を使用して D スクリプトを終わらせることができます。

マルチ CPU マシンでは、プローブの順序は規則的に連続して表示されないことがあります。 これは、どの CPU がプローブを処理し、 CPU の間をスレッドがどのように移動したかに依存します。 プローブのタイムスタンプを表示すると、 混乱を減らすことができます。 その例です。

    php*:::function-entry
    {
          printf("%lld: PHP function-entry ", walltimestamp);
          [ . . .]
    }

### 参考

- OCI8 および DTrace 動的トレーシング

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open