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

OCI8 2.0 では、DTrace をサポートする OS 上で使用できる 静的な DTrace プローブが導入されました。 PHP および DTrace の概要については、DTrace 動的トレーシング をご覧ください。

DTrace サポート付きで OCI8 をインストール

PHP OCI8 で DTrace のサポートを有効にするには、 PHP_DTRACE を設定後、 OCI8 を共用拡張モジュールとしてビルドします。

$ export PHP_DTRACE=yes
$ pecl install oci8

php.ini を編集し、作成された oci8.so がある ディレクトリを extension_dir に 設定します。 さらに以下のように追加してその拡張モジュールを有効にします。

extension=oci8.so

もし、phpize および configure を ( pecl の代わりに) 使用して PECL から PHP OCI8 をインストールする場合、 さらに PHP_DTRACE=yes を設定する必要があります。 それは、--enable-dtrace オプションが、PECL バンドルの 制限された configure スクリプトにより 無視されるからです。

一般的な PECL インストール手順については、PECL 拡張モジュールのインストール をご覧ください。

PHP OCI8 の DTrace 静的プローブ

PHP OCI8 では、以下の静的プローブが使用できます
プローブ名 プローブの説明 プローブの引数
oci8-connect-entry oci_connect()、oci_pconnect() および oci_new_connect() により開始されます。データベース接続が確立する前に発射されます。 char *username, char *dbname, char *charset, long session_mode, int persistent, int exclusive
oci8-connect-return 接続終了時に発射されます。 void *connection
oci8-check-connection Oracle のエラーにより、接続が不正になったかもしれない場合に発射されます。 void *connection, char *client_id, int is_open, long errcode, unsigned long server_status
oci8-sqltext oci_parse() が実行された際に発射されます。 void *connection, char *client_id, void *statement, char *sql
oci8-connection-close データベースへの接続が完全に破壊された際に発射されます。 void *connection
oci8-error Oracle のエラーが生じた場合に発射されます。 int status, long errcode
oci8-execute-mode 実行モードを示す oci_execute のたびに発射されます。 void *connection, char *client_id, void *statement, unsigned int mode

これらのプローブは、OCI8 スクリプトのトレーシングで有用です。

connection および statement は、 PHP の接続および実行されたステートメントを追跡するために使用される内部構造への ポインタです。

client_id は、 oci_set_client_identifier により設定される値です。

コア PHP にも静的プローブがあります。 コア PHP の DTrace 静的プローブ をご覧ください。

OCI8 の DTrace プローブ内部デバッギング
プローブ名
oci8-connect-expiry
oci8-connect-lookup
oci8-connect-p-dtor-close
oci8-connect-p-dtor-release
oci8-connect-type
oci8-sesspool-create
oci8-sesspool-stats
oci8-sesspool-type

これらのプローブは、OCI8 メンテナにとって有用です。 引数およびいつ発射されるかについては、OCI8 のソースコードを参照ください。

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

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

# dtrace -l

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

   ID   PROVIDER            MODULE                          FUNCTION NAME
   [ . . . ]
   17 phpoci22116           oci8.so   php_oci_dtrace_check_connection oci8-check-connection
   18 phpoci22116           oci8.so                php_oci_do_connect oci8-connect-entry
   19 phpoci22116           oci8.so         php_oci_persistent_helper oci8-connect-expiry
   20 phpoci22116           oci8.so             php_oci_do_connect_ex oci8-connect-lookup
   21 phpoci22116           oci8.so  php_oci_pconnection_list_np_dtor oci8-connect-p-dtor-close
   22 phpoci22116           oci8.so  php_oci_pconnection_list_np_dtor oci8-connect-p-dtor-release
   23 phpoci22116           oci8.so                php_oci_do_connect oci8-connect-return
   24 phpoci22116           oci8.so             php_oci_do_connect_ex oci8-connect-type
   25 phpoci22116           oci8.so          php_oci_connection_close oci8-connection-close
   26 phpoci22116           oci8.so                     php_oci_error oci8-error
   27 phpoci22116           oci8.so         php_oci_statement_execute oci8-execute-mode
   28 phpoci22116           oci8.so              php_oci_create_spool oci8-sesspool-create
   29 phpoci22116           oci8.so            php_oci_create_session oci8-sesspool-stats
   30 phpoci22116           oci8.so            php_oci_create_session oci8-sesspool-type
   31 phpoci22116           oci8.so          php_oci_statement_create oci8-sqltext

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

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

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

PHP OCI8 についての DTrace の例

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

例1 DTrace を使用して すべてのユーザーレベルの PHP OCI8 静的プローブをトレースするための user_oci8_probes.d

#!/usr/sbin/dtrace -Zs

#pragma D option quiet

php*:::oci8-connect-entry
{
    printf("%lld: PHP connect-entry\n", walltimestamp);
    printf("  credentials=\"%s@%s\"\n", arg0 ? copyinstr(arg0) : "", arg1 ? copyinstr(arg1) : "");
    printf("  charset=\"%s\"\n", arg2 ? copyinstr(arg2) : "");
    printf("  session_mode=%ld\n", (long)arg3);
    printf("  persistent=%d\n", (int)arg4);
    printf("  exclusive=%d\n", (int)arg5);
}

php*:::oci8-connect-return
{
    printf("%lld: PHP oci8-connect-return\n", walltimestamp);
    printf("  connection=0x%p\n", (void *)arg0);
}

php*:::oci8-connection-close
{
    printf("%lld: PHP oci8-connect-close\n", walltimestamp);
    printf("  connection=0x%p\n", (void *)arg0);
}

php*:::oci8-error
{
    printf("%lld: PHP oci8-error\n", walltimestamp);
    printf("  status=%d\n", (int)arg0);
    printf("  errcode=%ld\n", (long)arg1);
}

php*:::oci8-check-connection
{
    printf("%lld: PHP oci8-check-connection\n", walltimestamp);
    printf("  connection=0x%p\n", (void *)arg0);
    printf("  client_id=\"%s\"\n", arg1 ? copyinstr(arg1) : "");
    printf("  is_open=%d\n", arg2);
    printf("  errcode=%ld\n", (long)arg3);
    printf("  server_status=%lu\n", (unsigned long)arg4);
}

php*:::oci8-sqltext
{
    printf("%lld: PHP oci8-sqltext\n", walltimestamp);
    printf("  connection=0x%p\n", (void *)arg0);
    printf("  client_id=\"%s\"\n", arg1 ? copyinstr(arg1) : "");
    printf("  statement=0x%p\n", (void *)arg2);
    printf("  sql=\"%s\"\n", arg3 ? copyinstr(arg3) : "");
}

php*:::oci8-execute-mode
{
    printf("%lld: PHP oci8-execute-mode\n", walltimestamp);
    printf("  connection=0x%p\n", (void *)arg0);
    printf("  client_id=\"%s\"\n", arg1 ? copyinstr(arg1) : "");
    printf("  statement=0x%p\n", (void *)arg2);
    printf("  mode=0x%x\n", arg3);
}

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

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

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

# ./user_oci8_probes.d

PHP スクリプトまたはアプリケーションを実行します。 モニタリングの D スクリプトは、各プローブが発射されるたびに その引数を出力します。 例えば、テーブルを照会する単純な PHP スクリプトにより 以下のトレース出力がもたらされるでしょう。

1381794982092854582: PHP connect-entry
  credentials="hr@localhost/pdborcl"
  charset=""
  session_mode=0
  persistent=0
  exclusive=0
1381794982183158766: PHP oci8-connect-return
  connection=0x7f4a7907bfb8
1381794982183594576: PHP oci8-sqltext
  connection=0x7f4a7907bfb8
  client_id="Chris"
  statement=0x7f4a7907c2a0
  sql="select * from employees"
1381794982183783706: PHP oci8-execute-mode
  connection=0x7f4a7907bfb8
  client_id="Chris"
  statement=0x7f4a7907c2a0
  mode=0x20
1381794982444344390: PHP oci8-connect-close
  connection=0x7f4a7907bfb8

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