prex をプログラムに接続後、prex コマンドを使用して、収集するデータのパラメータを変更できます。prex list コマンドを使用して、プログラム内のプローブをすべて表示できます。プログラムの実行中にプローブポイントが実行されると、その実行ごとに情報がトレースファイルに記録されます。収集された情報は、tnfdump() を使用して表示します。tnfdump() については、「tnfdump ファイルの読み取り」を参照してください。
ユーザーは、プログラムに対する prex の接続と切り離しを繰り返し行なって、複数のセッションを作成できます。たとえば、最初のセッションでは、prex を使用してターゲットプログラムを起動し、プローブを設定してから prex コマンドの quit resume を実行することができます。
この操作は、prex の起動、収集する情報の定義、prex の終了を行い、最後にプログラムの実行を再開することによって情報の収集を開始します。これらの処理を行うコマンドを表 1-2 に示します。
2 回目のセッションでは、prex を同じプログラムに接続して、プローブを再設定してから、再度 prex コマンドの continue を実行することができます。この操作は繰り返し何度でも行うことができます。
すべてのトレース結果は、最初のセッションで名前を指定したトレースファイルに書き込まれます。このトレースファイル名を変更することはできません。
コマンド |
結果 |
---|---|
% prex a.out |
プログラムに prex を接続し、prex を起動します。 |
prex> enable $all |
すべてのプローブを有効にします。 |
prex> quit resume |
prex を終了して、プログラムを再実行します。 |
プローブポイントをソースコードに挿入するときに、さまざまな属性や (必要に応じて) 値を各プローブポイントに割り当てることができます。たとえば、任意の名前を "name" 属性の値に割り当てることができます。
定義済みの属性とその値の意味を表 1-3 に示します。prex コマンドを使用して、プローブポイントの属性または値に一致する複数のプローブポイントをグループとして選択できます。また、選択したプローブポイントのトレースやデバッグを行うこともできます。
prex コマンドとそのアクションは、表 1-5 を参照してください。
例 1-1 では、TNF_PROBE
マクロによって work_start という名前のプローブポイントが定義されています。このプローブポイントには、state と message という 2 つの引数があります。work_start という名前のプローブが検出されるたびに、変数 state と message のタイムスタンプと値がトレースファイルに記録されます。
#include <tnf/probe.h> int work(int state, char *message) { TNF_PROBE_2(work_start, "work_module work" "sunw%debug in function work", tnf_long, int_input, state, tnf_string, string_input, message); ... ... }
TNF_PROBE
マクロとこのコード例についての詳細は、「TNF_PROBE マクロの使い方」を参照してください。
属性は、コード内のプローブポイントを識別するための特性です。定義済みの属性を表 1-3 に示します。ユーザーは、TNF_PROBE
を使用して別の属性を追加定義することができます。「TNF_PROBE マクロの使い方」を参照してください。
属性 |
特性 |
値 |
---|---|---|
enable |
プローブポイントは、そのプローブポイントが有効な場合にだけ、設定されているアクションを実行します。たとえば、トレースを行うように設定しても、プローブポイントが有効になっている場合にしかトレースは行われません。 |
OFF (デフォルト) |
file |
プローブポイントが含まれているファイルの名前。 | work.c |
funcs |
このプローブに接続されたプローブ関数のリストを表示します。現在使用できるのはデバッグ関数だけです。 |
<値なし> (デフォルト) |
keys |
プローブポイントが属するグループ。プローブポイントのいずれかのキーが有効になると、そのプローブポイントは有効になります。 |
work_module work |
line |
プローブポイントが現われるコード内の行番号 |
10 |
name |
プローブポイントの名前 |
work_start |
object |
プローブポイントが含まれている共有オブジェクトまたは実行可能プログラムの名前。特定のモジュール中のプローブをすべて選択する場合に便利な属性です。 |
work |
slots |
プローブポイントの引数 (arg_name_n については、「TNF_PROBE_1 〜 TNF_PROBE_5」を参照) の名前。 |
int_input string_input |
trace |
プローブポイントのトレースがオンの場合、プログラムのプローブポイントを実行するたびに、データが 1 行ずつトレースファイルに書き込まれます。 |
ON (デフォルト) |
プローブの属性と値に基づいてプローブを選択します。 selector_list に選択条件を指定します。それぞれの属性または値は、以下のいずれかで表現できます。
識別子−英字、数字、_ ¥ . % (下線、バックスラッシュ、ピリオド、パーセント記号) を使用した文字列。識別子の最初の文字を数字にすることはできません。
引用符付き文字列−単一引用符で囲んだ文字列。この文字列は文字どおりに解釈される直定数とみなされます。照合する文字列が予約語の場合に便利な表現です。予約語の一覧については、表 1-4 を参照してください。
正規表現−スラッシュ (/) で囲んだ文字列。ed(1) の規則に従って照合用に拡張されています。正規表現においてパス名などを表すためにスラッシュを使用する場合は、/¥/tmp¥/filename のように、バックスラッシュでそのスラッシュをエスケープしてください。
selector_list は、1 つ以上の selector= という形式の選択条件で構成されています。最初の selector= が指定されていない場合は、keys= がデフォルトになります。たとえば、enable コマンドは以下の書式で指定します。
enable selector_list
たとえば、以下のように指定します。
enable name=/first/ file='sampleZ.c'
このコマンドは、値 first が含まれている name 属性 (正規表現による一致) をもつプローブポイント、または値が sampleZ.c である file 属性を持つプローブポイントをすべて有効にします。なお、トレースは、論理積ではなく論理和であることに注意してください。
選択条件 selector_list の簡略名として、$set_name のように変数を設定することができます。以下の例では、myprobes がその set_name に当たります。
create $myprobes name=/first/ file='sampleZ.c' enable $myprobes
これは、前述の例と同じ処理を行います。set_name は、識別子の命名規則に従っています。デフォルト設定の $all は、プログラムのプローブをすべて選択します。
予約語を表 1-4 に示します。これらの予約語を使用して属性または値を選択する場合は、その予約語を単一引用符で囲んでください。
表 1-4 予約語add | alloc | buffer |
clear | connect | continue |
create | dealloc | delete |
disable | enable | fcns |
filter | help | history |
kill | ktrace | list |
off | on | pfilter |
probes | quit | resume |
sets | source | suspend |
trace | untrace | values |
たとえば、以下のコマンドは、trace 属性の値が ON のプローブをすべて有効にします。trace と on はどちらも予約語なので、単一引用符で囲む必要があります。
enable 'trace'='on'表 1-5 prex のコマンド
コマンド |
アクション |
---|---|
clear $set_name clear selector_list |
接続されているプローブ関数を切り離します。 |
connect &debug $set_name connect &debug selector_list |
デバック関数をプローブポイントに接続します。このコマンドを実行しても、プローブポイントは有効になりません。デバッグ関数は、トレースファイルにではなく stderr に出力を送ります。 |
continue |
prex を接続したまま、プログラムの実行を再開します。 |
create $set_name selector_list |
selector_list と一致するプローブポイントのグループを作成します。同時に、selector_list のエイリアス $set_name を作成します。 |
enable $set_name enable selector_list disable $set_name disable selector_list |
プローブポイントに設定されているアクションをそのプローブポイントに実行させるかどうかを制御します。デフォルトでは、プローブポイントは無効になっています。つまり、prex はトレースをオンにしません。プローブポイントのトレースを停止する最も効率的な方法 (プローブポイントにおける実行時間の面から考えた場合) は、disable コマンドを使用する方法です。 enable と disable コマンドは、主スイッチで、トレースを実行するかどうかを決定する最も優先度が高い要素です。プローブポイントが無効の場合は、そのプローブポイントが debug() 関数に接続されていて trace 属性がオンであっても、stderr やトレースファイルに情報は送られません。 |
help |
使用可能な prex コマンドをすべて表示します。 |
list attributes probes selector_list list attributes probes$ set_name |
指定されたプローブポイントが有効/無効のどちらであるか、そのプローブポイントのトレースがオン/オフのどちらであるか、および接続されているプローブ関数を表示します。「属性」で説明したように、属性が選択条件になります。たとえば、以下のコマンドは、一致したプローブポイントの name 属性と file 属性の値だけを表示します。 list name file probes $all 以下のコマンドは、デフォルトの属性とその値 (name、enable、trace、file、line、funcs) をすべて表示します。 list probes $all |
list fcns |
定義済みの関数 (現在は、&debug だけが定義されています) を表示します。 |
list history |
制御コマンドの履歴を表示します。dlopen() によって新しい共有オブジェクトがプログラムに取り込まれるたびに connect、clear、trace、untrace、enable、disable で使用したコマンドの履歴が記録されます。「dlopen()、dlclose()、履歴」を参照してください。 |
list sets |
定義されたセットを表示します。 |
list values attributes |
attributes に指定された属性に関連付けられた固有値を表示します。たとえば list values keys を実行すると、プログラム内の固有キーがすべて表示されます。 |
source filename |
prex コマンドのファイルを読み込みます。ファイル名は引用符で囲んでください。 |
trace $set_name >trace selector_list untrace $set_name untrace selector_list |
プローブポイントのトレース動作を制御します。trace と untrace を使用して、プローブポイントを実行したときにそのプローブポイントにトレース記録を生成させるかどうかを切り替えます。trace と untrace のどちらを実行しても、プローブポイントは有効になりません。
デフォルトでは、トレースはオンになります。
untrace コマンドは、デバッグ出力だけを得たいときに利用できます。このコマンドを使用する際には、トレースをオフ、デバッグをオンにして、プローブを有効にする必要があります。
debug は stderr に書き込みを行いますが、trace は mmap された (メモリーが割り当てられた) ファイルに書き込みを行います。そのため、トレースの方がデバッグ関数よりもプログラムに与える負荷が少なくなります。 |
quit |
prex を終了します。prex を使用してプログラムがロードされている場合は、そのプログラムを強制終了します。prex にプログラムが接続されている場合は、そのプログラムが再実行されます。 |
quit kill |
prex を終了して、プログラムを強制終了します。 |
quit resume |
prex を終了して、プログラムを再実行します。 |
quit suspend |
プログラムを中断したまま、prex を終了します。 |
プローブポイントをトレースするには、プローブポイントのトレースをオンにして、プローブポイントを有効にする必要があります。プローブポイントでデバッグするには、プローブポイントをデバッグ関数に接続して、そのプローブポイントを有効にする必要があります。
トレース、プローブポイント、デバッグ関数の設定状態の組み合わせと、その結果を表 1-6 に示します。
表 1-6 トレース、プローブポイント、デバッグ関数の設定状態の組み合わせとその結果
プローブポイント (有効または無効) |
トレースの状態 (オン/オフ) |
デバッグの状態 (接続/未接続) |
結果 |
---|---|---|---|
有効 |
オン |
接続 |
トレースとデバッグ |
有効 |
オン |
未接続 |
トレースのみ |
有効 |
オフ |
接続 |
デバッグのみ |
有効 |
オフ |
未接続 |
なし |
無効 |
オン |
接続 |
なし |
無効 |
オン |
未接続 |
なし |
無効 |
オフ |
接続 |
なし |
無効 |
オフ |
未接続 |
なし |
prex へのコマンドは、prex コマンド行から、または prex コマンドが含まれているファイルから入力します。
prex を起動すると、prex は .prexrc という名前のファイルをまず $HOME/ ディレクトリ内で探し、その次に、prex を起動したディレクトリ内で探します。コマンドは、検索されたすべてのファイルから読み取られます。したがって、ホームディレクトリの .prexrc ファイルで設定されたデフォルト値が、現在のディレクトリの .prexrc ファイルによって上書きされる可能性もあります。
検索された .prexrc ファイルを読み取った後は、prex コマンド行から入力されたコマンドが実行されます。.prexrc ファイルを使用して作業のすべてを設定する場合は、.prexrc ファイル中の最後の文を quit resume にします。quit resume は、prex を終了してプログラムを再実行します。
また、prex の実行中には、source filename コマンドを使用して、prex が読み取るコマンドが記述されているファイル filename を指定できます。このファイルは、どのような名前でも構いません。
スクリプト内のコマンドは、prex コマンド行から入力するコマンドと同様に、すべて ASCII 形式にしてください。スクリプトには以下の規則が適用されます。
各コマンドの最後には、改行文字を入力します。
次の行までコマンドが続く場合は、1 行目の終わりにバックスラッシュ (¥) を入力します。
トークンは、空白 (1 つ以上の空白文字またはタブ) で区切ります。
コメントの先頭には、ハッシュ記号 (#) を入力します。
コマンド行から入力する prex コマンドとスクリプトのコマンドとでコマンド言語は同じですが、スクリプトでは出力が stdout に送られるため、出力を返すコマンド (たとえば、list probes...) をスクリプトで使用してもあまり意味がありません。
このプログラム cookie.c は give me a COOKIE! というメッセージを表示します。それに対する応答は、大文字で入力する必要があります。小文字の場合は誤りとみなされます。また、数値の素因数を計算することもできます。これら 2 つの処理過程を通して、トレース機能がどのように動作しているかを見てみましょう。
このプログラムをコンパイルして cookie() という実行可能プログラムを作成するには、以下のコマンドを実行します。
$ cc -o cookie cookie.c
このプログラムでは、5 つのプローブポイントが定義 (大文字で表記) されています。各プローブポイントの名前は、start (17 行目)、inloop (33 行目)、factor_start (60 行目)、found_a_factor (65 行目)、factor_end (72 行目)となっています。これらのプローブポイントについての詳細は、「prex セッションのサンプル」で説明しています。
#include <sys/types.h> #include <stdio.h> #include <string.h> #include <tnf/probe.h> #define MAX_RESPONSE_SIZE 256 static void find_factor(int n); int main(int argc, char **argv) { boolean_t shouldexit = B_FALSE; int sum = 0, max_loop = 5; int i; TNF_PROBE_0(start, "cookie main", "sunw%debug starting main"); while (!shouldexit) { char response[MAX_RESPONSE_SIZE]; int factor_input; (void) printf("give me a COOKIE! "); (void) scanf("%s", response); if (!strcmp(response, "COOKIE")) { (void) printf("thanks!¥n"); shouldexit = B_TRUE; } else if (!strcmp(response, "loop")) { for (i = 0; i < max_loop; i++) { TNF_PROBE_2(inloop, "cookie main loop","sunw%debug in the loop", tnf_long, loop_count, i, tnf_long, total_iterations, sum); sum++; } max_loop += 2 ; } else if (!strcmp(response, "factor")) { (void) printf("number you want factored? "); (void) scanf("%d", &factor_input); find_factor(factor_input); } else { (void) printf("not a %s, ", response); } } return 0; } /* end main */ static void find_factor(int n) { int i; (void) printf("¥tfactors of %d = ", n); TNF_PROBE_1(factor_start, "factor", "", tnf_long, input_number, n); for (i=2; i <= n; i++) { while (n % i == 0) { TNF_PROBE_2(found_a_factor, "cookie find_factor", "", tnf_long, searching_for, n, tnf_long, factor, i); (void) printf("%d ", i); n /= i; } } TNF_PROBE_0(factor_end, "factor", ""); (void) printf("¥n"); }
この prex セッションのサンプルは、prex のさまざまな機能を紹介できるように作られています。cookie を実行するときに収集されるデータは、「tnfdump ファイルの読み取り」に示しています。
% prex cookie /* prex によって、実行可能プログラム cookie がロードされます。*/ Target process stopped Type "continue" to resume the target, "help" for help ... prex> list sets $all 'keys'=/.*/ /* エイリアス $all が 1 つ定義されています --- (すべてのプローブです)。*/ prex> list fcns &debug tnf_probe_debug /* デバッグ関数は、使用可能な唯一の関数です。*/ prex> list probes $all name=inloop enable=off trace=on file=cookie.c line=35 funcs=<no value> name=factor_end enable=off trace=on file=cookie.c line=72 funcs=<no value> name=factor_start enable=off trace=on file=cookie.c line=61 funcs=<no value> name=found_a_factor enable=off trace=on file=cookie.c line=67 funcs=<no value> name=start enable=off trace=on file=cookie.c line=17 funcs=<no value> prex>/* 行番号は、5 つのプローブのそれぞれの最終行を示しています。*/ prex> create $factor /factor/ /* "keys" 属性に文字列 "factor" が含まれている プローブと一致する新しいセットを作成します。*/ prex> prex> list sets $all 'keys'=/.*/ $factor 'keys'=/factor/ /* "factor" という名前の新しいセットが作成されて、そのセットが表示されています。*/ prex> /* セットの一覧 */ prex> list probes $factor /* この行によって、どのプローブがそのセットと一致しているかがわかります。*/ name=factor_end enable=off trace=on file=cookie.c line=72 funcs=<no value> name=factor_start enable=off trace=on file=cookie.c line=61 funcs=<no value> name=found_a_factor enable=off trace=on file=cookie.c line=67 funcs=<no value> prex> list probes $all /* 有効なプローブがあるかどうか検査します。*/ name=inloop enable=off trace=on file=cookie.c line=35 funcs=<no value> name=factor_end enable=off trace=on file=cookie.c line=72 funcs=<no value> name=factor_start enable=off trace=on file=cookie.c line=61 funcs=<no value> name=found_a_factor enable=off trace=on file=cookie.c line=67 funcs=<no value> name=start enable=off trace=on file=cookie.c line=17 funcs=<no value> prex> /* 有効なプローブはありませんが、 どのプローブもトレースはオンになっています。*/ prex> enable $all /* すべてのプローブを有効にします。*/ prex> list probes $all /* 有効なプローブがあるかどうか、再度検査します。*/ name=inloop enable=on trace=on file=cookie.c line=35 funcs=<no value> name=factor_end enable=on trace=on file=cookie.c line=72 funcs=<no value> name=factor_start enable=on trace=on file=cookie.c line=61 funcs=<no value> name=found_a_factor enable=on trace=on file=cookie.c line=67 funcs=<no value> name=start enable=on trace=on file=cookie.c line=17 funcs=<no value prex> list values name /* プローブの名前を調べます。*/ name = factor_end factor_start found_a_factor inloop start prex> list values /.*/ /* 定義済みの属性とその値をすべて表示します。*/ enable = /* 固有の属性だけを表示します。*/ on file = cookie.c funcs = keys = cookie factor find_factor loop main line = 17 35 61 67 72 name = factor_end factor_start found_a_factor inloop start object = cookie slots = factor input_number loop_count searching_for total_iterations sunw%debug = /* ユーザー定義のマクロ sunw%debug も表示されています。*/ in /* このマクロは、cookie.c の 17 行目で定義されています。*/ loop main starting the trace = on prex> list values object object = cookie prex> connect &debug name=inloop prex> list /.*/ probes $all /* すべてのプローブの情報をすべて表示します。*/ enable=on trace=on object=cookie funcs=<no value> name=inloop slots=loop_count total_iterations keys=cookie main loop file=cookie.c line=35 sunw%debug=in the loop enable=on trace=on object=cookie funcs=<no value> name=factor_end slots=<no value> keys=factor file=cookie.c line=72 enable=on trace=on object=cookie funcs=<no value> name=factor_start slots=input_number keys=factor file=cookie.c line=61 enable=on trace=on object=cookie funcs=<no value> name=found_a_factor slots=searching_for factor keys=cookie find_factor file=cookie.c line=67 enable=on trace=on object=cookie funcs=<no value> name=start slots=<no value> keys=cookie main file=cookie.c line=17 sunw%debug=starting main prex> continue give me a COOKIE! loop /* ループカウントの例 */ probe inloop; sunw%debug "in the loop"; loop_count=0; total_iterations=0; probe inloop; sunw%debug "in the loop"; loop_count=1; total_iterations=1; probe inloop; sunw%debug "in the loop"; loop_count=2; total_iterations=2; probe inloop; sunw%debug "in the loop"; loop_count=3; total_iterations=3; probe inloop; sunw%debug "in the loop"; loop_count=4; total_iterations=4; give me a COOKIE! factor number you want factored? 25 factors of 25 = 5 5 give me a COOKIE! factor number you want factored? 43645729 factors of 43645729 = 43645729 give me a COOKIE! ^C Target process stopped Type "continue" to resume the target, "help" for help... prex> continue give me a COOKIE! biscuit not a biscuit, give me a COOKIE! cookie not a cookie, give me a COOKIE! COOKIE thanks! prex: target process finished