Procプロバイダ

procプロバイダは、プロセスの作成と終了、LWPの作成と終了、新しいプログラム・イメージの実行、およびシグナルの送信と処理に関連するプローブを使用可能にします。

procプローブ

次の表に、procプロバイダのプローブを示します。

表8-3 procプローブ

プローブ 説明

create

fork()またはvfork() (どちらもclone()を呼び出す)を使用してプロセス(またはプロセス・スレッド)が作成されるときに起動します。新しい子プロセスに対応するpsinfo_tは、args[0]によってポイントされます。

exec

プロセスがexecve()システム・コールのバリアントを使用して、新しいプロセス・イメージをロードするときに起動します。execプローブが起動するのは、プロセス・イメージがロードされる前です。したがって、execnamecurpsinfoなどのプロセス変数には、イメージがロードされるより前のプロセス状態が格納されます。execプローブの起動後しばらくしてから、同じスレッドでexec-failureプローブまたはexec-successプローブが起動します。新しいプロセス・イメージのパスは、args[0]によってポイントされます。

exec-failure

exec()のバリアントが失敗したときに起動します。exec-failureプローブは常に、同じスレッドでexecプローブが起動した後で起動します。errno値は、args[0]で指定されます。

exec-success

exec()のバリアントが成功したときに起動します。exec-failureプローブと同様、exec-successプローブは常に、同じスレッドでexecプローブが起動した後に起動します。exec-successプローブが起動したときにはすでに、execnamecurpsinfoなどのプロセス変数に、新しいプロセス・イメージがロードされた後のプロセス状態が格納されています。

exit

現在のプロセスが終了しようとするときに起動します。終了の理由が、いずれかのSIGCHLD <asm-generic/signal.h>コードとしてargs[0]に格納されます。

lwp-create

プロセス・スレッドの作成時に起動します。後者は通常、pthread_create()の結果として作成されます。新しいスレッドに対応するlwpsinfo_tは、args[0]によってポイントされます。スレッドを作成したプロセスを表すpsinfo_tは、args[1]によってポイントされます。

lwp-exit

シグナル、またはexitpthread_exit()の明示的なコールによって、プロセスまたはプロセス・スレッドが終了する直前に起動します。

lwp-start

新しく作成されたプロセスまたはプロセス・スレッドのコンテキストで起動します。lwp-startプローブは、ユーザー・レベル命令が実行されるより先に起動します。スレッドがプロセスで最初に作成される場合は、まずstartプローブが起動し、続いてlwp-startプローブが起動します。

signal-clear

ターゲット・スレッドがsigwait()sigwaitinfo()またはsigtimedwait()でシグナルを待機しているために、保留中のシグナルがクリアされたときに起動します。この条件になると、保留中のシグナルはクリアされ、コール元にはシグナル番号が返されます。シグナル番号はargs[0]に格納され、signal-clearは、それ以前に待機していたスレッドのコンテキストで起動します。

signal-discard

シングルスレッド・プロセスにシグナルが送信され、シグナルがプロセスによってブロック解除されて無視されたときに起動します。この条件では、シグナルは作成後すぐに破棄されます。ターゲット・プロセスおよびスレッドのlwpsinfo_tpsinfo_tは、それぞれargs[0]args[1]に格納されます。シグナル番号はargs[2]に格納されます。

signal-handle

スレッドがシグナルを処理する直前に起動します。signal-handleプローブは、シグナルを処理するスレッドのコンテキストで起動します。シグナル番号はargs[0]に格納されます。シグナルに対応するsiginfo_t構造体へのポインタは、args[1]に格納されます。プロセスにおけるシグナル・ハンドラのアドレスは、args[2]に格納されます。

signal-send

プロセス、またはプロセスによって作成されたスレッドにシグナルが送信されたときに起動します。signal-sendプローブは、送信側のプロセスまたはスレッドのコンテキストで起動します。受信側プロセスおよびスレッドのlwpsinfo_tpsinfo_tは、それぞれargs[0]args[1]に格納されます。シグナル番号はargs[2]に格納され、必ず受信側プロセスおよびスレッドでsignal-handleまたはsignal-clearが続きます。

start

新しく作成されたプロセスのコンテキストで起動します。startプローブは、そのプロセスで他のどのユーザー・レベル命令が実行されるより先に起動します。

ノート:

Linuxでは、プロセスとプロセスが作成するスレッドの間に基本的な違いはありません。プロセスのスレッドはリソースを共有できるように設定されますが、各スレッドはプロセス表に独自のエントリを持ち、プロセスIDも独自です。

procプローブの引数

次の表は、procプローブの引数の型を示しています。引数の詳細は、「procプローブ」を参照してください。

表8-4 procプローブの引数

プローブ args[0] args[1] args[2]

create

psinfo_t *

exec

char *

exec-failure

int

exec-success

exit

int

lwp-create

lwpsinfo_t *

psinfo_t *

lwp-exit

lwp-start

signal-clear

int

signal-discard

lwpsinfo_t *

psinfo_t *

int

signal-handle

int

siginfo_t *

void (*)(void)

signal-send

lwpsinfo_t *

psinfo_t *

int

start

lwpsinfo_t

一部のprocプローブは、lwpsinfo_t型の引数をとります。このデータ構造体の詳細は、/usr/lib64/dtrace/version/procfs.dを参照してください。lwpsinfo_t構造体の定義は、次のとおりです:

typedef struct lwpsinfo {       
        int pr_flag;                    /* lwp flags (DEPRECATED) */
        int pr_lwpid;                   /* lwp id */
        uintptr_t pr_addr;              /* internal address of lwp */
        uintptr_t pr_wchan;             /* wait addr for sleeping lwp */
        char pr_stype;                  /* sync event type */
        char pr_state;                  /* numeric lwp state */
        char pr_sname;                  /* printable char for pr_state */
        char pr_nice;                   /* nice for cpu usage */
        short pr_syscall;               /* syscall number */
        char pr_oldpri;                 /* priority */
        char pr_cpu;                    /* CPU usage */
        int pr_pri;                     /* priority */
        ushort_t pr_pctcpu;             /* % of recent cpu time */
        ushort_t pr_pad;
        timestruc_t pr_start;           /* lwp start time */
        timestruc_t pr_time;            /* usr+sys cpu time */
        char pr_clname[8];              /* scheduling class name */
        char pr_name[16];               /* name */
        processorid_t pr_onpro;         /* processor last ran on */
        processorid_t pr_bindpro;       /* processor bound to */
        psetid_t pr_bindpset;           /* processor set */
        int pr_lgrp;                    /* lwp home lgroup */
        int pr_filler[4];

} lwpsinfo_t;

ノート:

Linuxには、軽量プロセスは存在しません。かわりに、Oracle Linuxのタスク・リストでは、プロセスとスレッドはstruct task_struct型のプロセス記述子によって表されます。DTraceは、lwpsinfo_tのメンバーを、Oracle Linuxプロセスのtask_structから変換します。

スレッドが停止する場合、pr_flag1に設定されます。それ以外の場合は、0に設定されます。

Oracle Linuxでは、pr_stypeフィールドはサポートされていないため、常に0です。

次の表では、pr_stateが受取り可能な値について、それに対応するpr_snameの文字値を含めて説明します。

表8-5 pr_stateの値

pr_state Value pr_sname Value 説明

SRUN (2)

R

スレッドは実行可能であるか、CPUで実行中です。sched:::enqueueプローブは、スレッドの状態がSRUNに移行する直前に起動します。sched:::on-cpuプローブは、スレッドが実行を開始した直後に起動します。

Oracle Linuxで同等のタスク状態は、TASK_RUNNINGです。

SSLEEP (1)

S

スレッドはスリープ中です。sched:::sleepプローブは、スレッドの状態がSSLEEPに移行する直前に起動します。

Oracle Linuxで同等のタスク状態は、TASK_INTERRUPTABLEまたはTASK_UNINTERRUPTABLEです。

SSTOP (4)

T

スレッドは、明示的なprocディレクティブやその他の停止メカニズムにより停止しています。

Oracle Linuxで同等のタスク状態は、__TASK_STOPPEDまたは__TASK_TRACEDです。

SWAIT (7)

W

スレッドは待機キューで待機中です。sched:::cpucaps-sleepプローブは、スレッドの状態がSWAITに移行する直前に起動します。

Oracle Linuxで同等のタスク状態は、TASK_WAKEKILLまたはTASK_WAKINGです。

SZOMB (3)

Z

スレッドはゾンビです。

Oracle Linuxで同等のタスク状態は、EXIT_ZOMBIEEXIT_DEADまたはTASK_DEADです。

psinfo_t

一部のprocプローブは、psinfo_t型の引数をとります。このデータ構造体の詳細は、/usr/lib64/dtrace/version/procfs.dを参照してください。psinfo_t構造体の定義は、次のとおりです:

typedef struct psinfo {
        int pr_flag;                    /* process flags (DEPRECATED) */
        int pr_nlwp;                    /* number of active lwps (Linux: 1) */
        pid_t pr_pid;                   /* unique process id */
        pid_t pr_ppid;                  /* process id of parent */
        pid_t pr_pgid;                  /* pid of process group leader */
        pid_t pr_sid;                   /* session id */
        uid_t pr_uid;                   /* real user id */
        uid_t pr_euid;                  /* effective user id */
        uid_t pr_gid;                   /* real group id */
        uid_t pr_egid;                  /* effective group id */
        uintptr_t pr_addr;              /* address of process */
        size_t pr_size;                 /* size of process image (in KB) */
        size_t pr_rssize;               /* resident set sie (in KB) */
        size_t pr_pad1;
        struct tty_struct *pr_ttydev;   /* controlling tty (or -1) */
        ushort_t pr_pctcpu;             /* % of recent cpu time used */
        ushort_t pr_pctmem;             /* % of recent memory used */
        timestruc_t pr_start;           /* process start time */
        timestruc_t pr_time;            /* usr+sys cpu time for process */
        timestruc_t pr_ctime;           /* usr+sys cpu time for children */
        char pr_fname[16];              /* name of exec'd file */
        char pr_psargs[80];             /* initial chars of arg list */
        int pr_wstat;                   /* if zombie, wait() status */
        int pr_argc;                    /* initial argument count */
        uintptr_t pr_argv;              /* address of initial arg vector */
        uintptr_t pr_envp;              /* address of initial env vector */
        char pr_dmodel;                 /* data model */
        char pr_pad2[3];
        taskid_t pr_taskid;             /* task id */
        dprojid_t pr_projid;            /* project id */
        int pr_nzomb;                   /* number of zombie lwps (Linux: 0) */
        poolid_t pr_poolid;             /* pool id */
        zoneid_t pr_zoneid;             /* zone id */
        id_t pr_contract;               /* process contract */
        int pr_filler[1];
        lwpsinfo_t pr_lwp;

} psinfo_t;

ノート:

Linuxには、軽量プロセスは存在しません。Oracle Linuxのタスク・リストでは、プロセスとスレッドはstruct task_struct型のプロセス記述子によって表されます。DTraceは、psinfo_tのメンバーを、Oracle Linuxプロセスのtask_structから変換します。

pr_dmodelは、32ビット・プロセスを表すPR_MODEL_ILP32か、64ビット・プロセスを表すPR_MODEL_LP64に設定されます。

procの例

次の例は、procプロバイダによって公開されるプローブの使用を示しています。

exec、exec-successおよびexec-failure

次の例は、execexec-successおよびexec-failureのプローブを使用して、どのプログラムがどの親プロセスによって実行されているかを簡単に判断する方法を示しています。次のDソース・コードを入力して、whoexec.dという名前のファイルに保存します:

#pragma D option quiet

proc:::exec
{
  self->parent = execname;
}

proc:::exec-success
/self->parent != NULL/
{
  @[self->parent, execname] = count();
  self->parent = NULL;
}

proc:::exec-failure
/self->parent != NULL/
{
  self->parent = NULL;
}

END
{
  printf("%-20s %-20s %s\n", "WHO", "WHAT", "COUNT");
  printa("%-20s %-20s %@d\n", @);
}

この例のスクリプトを短時間実行すると、次のような出力が得られます:

WHO                  WHAT                 COUNT
bash                 date                 1
bash                 grep                 1
bash                 ssh                  1
bash                 wc                   1
bash                 ls                   2
bash                 sed                  2
...

startプローブとexitプローブ

プログラムが作成されてから終了するまでの実行時間を調べるには、次の例で示すようにstartプローブとexitプローブを有効にします。progtime.dという名前のファイルに保存します。

proc:::start
{
  self->start = timestamp;
}

proc:::exit
/self->start/
{
  @[execname] = quantize(timestamp - self->start);
  self->start = 0;
}

ビルド・サーバー上で数秒間この例のスクリプトを実行すると、次のような出力が得られます。

...
cc
          value  ------------- Distribution ------------- count
       33554432 |                                         0
       67108864 |@@@                                      3
      134217728 |@                                        1
      268435456 |                                         0
      536870912 |@@@@                                     4
     1073741824 |@@@@@@@@@@@@@@                           13
     2147483648 |@@@@@@@@@@@@                             11
     4294967296 |@@@                                      3
     8589934592 |                                         0

sh
          value  ------------- Distribution ------------- count
         262144 |                                         0
         524288 |@                                        5
        1048576 |@@@@@@@                                  29
        2097152 |                                         0
        4194304 |                                         0
        8388608 |@@@                                      12
       16777216 |@@                                       9
       33554432 |@@                                       9
       67108864 |@@                                       8
      134217728 |@                                        7
      268435456 |@@@@@                                    20
      536870912 |@@@@@@                                   26
     1073741824 |@@@                                      14
     2147483648 |@@                                       11
     4294967296 |                                         3
     8589934592 |                                         1
    17179869184 |                                         0
...

signal-send

次の例は、signal-sendプローブを使用して、シグナルに関連付けられたプロセスの送受信を確認する方法を示しています。次のDソース・コードを入力し、sig.dという名前のファイルに保存します。

#pragma D option quiet

proc:::signal-send
{
  @[execname, stringof(args[1]->pr_fname), args[2]] = count();
}

END
{
  printf("%20s %20s %12s %s\n",
      "SENDER", "RECIPIENT", "SIG", "COUNT");
  printa("%20s %20s %12d %@d\n", @);
}

このスクリプトを実行すると、次のような出力が得られます。

              SENDER            RECIPIENT          SIG COUNT
       kworker/u16:7               dtrace            2 1
       kworker/u16:7                 sudo            2 1
           swapper/2             sssd_kcm           34 1
           swapper/6             pmlogger           14 1

procの安定性

procプロバイダは、DTraceの安定性メカニズムを使用してその安定性を記述します。これらの値を、次の表に示します。

要素 名前の安定性 データの安定性 依存クラス

プロバイダ

発展中

発展中

ISA

モジュール

非公開

非公開

不明

関数

非公開

非公開

不明

名前

発展中

発展中

ISA

引数

発展中

発展中

ISA