以下のような場合に、プローブポイントをコードに挿入します。
プログラムの変数値をトレースする。
エクスポートされたインタフェースからは得ることができない内部状態の情報を提供する。これは、デバッグやパフォーマンス分析を行う場合に役立ちます。
たとえば、プローブポイントを使用して、C++ の private クラスに隠されているパフォーマンス関連の情報を表示したり、ハッシュテーブル内の衝突率などの処理データを表示できます。ハッシュテーブルのコード中にプローブポイントを配置しておくと、衝突が検出されるたびにそのプローブポイントはトレースファイルに書き込みを行うことができます。
プローブを挿入するためのインタフェースは、TNF_PROBE_0 から TNF_PROBE_5 までの TNF_PROBE マクロによって定義されます。0 〜 5 の数字は、マクロによってトレースされる変数の数です。
これらのマクロを使用して、コードの任意の場所にプローブポイントを挿入することによって、変数の値を取得したり、プログラムの実行をトレースすることができます。libtnfprobe ライブラリでは標準のスカラー型 (int、long、float など) が定義されていますが、TNF_DECLARE_RECORD マクロと TNF_DEFINE_RECORD マクロを使用すると、さらに複雑な構造を定義することもできます。「プローブポイントのユーザー定義型」を参照してください。
単純な例として、TNF_PROBE_0 を以下に示します。このマクロには、引数の型は指定しません。
TNF_PROBE_0 (name, keys, detail);
各変数について説明します。
name - プローブの名前。この名前は、ANSI C の識別子の構文規則にすべて従います。name は、使用したときに宣言されるので、あらかじめ別に宣言する必要はありません。この宣言はブロックスコープ宣言なので、プログラムの名前空間には影響を与えません。
keys - プローブが属するグループのリスト。このリスト中には複数のキーワードが含まれており、各キーワードは空白文字で区切られています。このリストの中では、セミコロン (;)、等号 (=)、単一引用符 (') は使用できません。いずれかのグループが有効になると、そのプローブポイントも有効になります。keys を変数にすることはできません。keys はインライン文字列にしてください。
detail - 独自の属性と値を定義する手段を提供します。detail 文字列には、複数の組の属性と値が含まれており、各組はセミコロンで区切られています。ただし、この値は省略可能です。最初のワード (空白文字まで) は属性、残りの文字列 (セミコロンまで) は値とみなされます。区切り文字のセミコロンの前後には、スペースを入れることができます。detail 文中では単一引用符と等号は使用できません。
属性名の前にベンダー固有の記号と % 記号を付けて、名前の衝突を避けてください。以下の例では、 sunw%debug、comX%exception、comY%func_entry、comY%color という 4 つの属性が定義されています。prex は空白文字の値をトークン化するので、複数の語から成る値の場合はいずれかの語で照合できますが、文字列全体で照合することはできません。たとえば、以下のような例が考えられます。
sunw%debug entering function A; comX%exception no file; comY%func_entry; comY%color red blue
上記のコマンドで照合される値を表 1-8 に示します。
表 1-8 ユーザー定義属性の例
属性 |
値 |
prex が照合する値 |
---|---|---|
sunw%debug |
entering function A |
entering または function または A |
comX%exception |
no file |
no または file |
comY%func_entry |
|
/.*/ (正規表現) |
comY%color |
red blue |
red または blue |
libtnfprobe は、ベンダー記号が前に付いていない属性名をすべて予約します (つまり、名前に % 記号が含まれていない属性をすべて予約します)。「C プログラムのサンプル」の cookie.c では、以下の TNF_PROBE_0 を使用しています。
TNF_PROBE_0(start, "cookie main", "sunw%debug starting main");
プリプロセッサオプションの -DNPROBE (cc(1) のマニュアルページを参照) を使用してコンパイルする場合、またはプリプロセッサ制御文 #include <tnf/probe.h> の前に #define NPROBE を置いてコンパイルする場合には、プローブポイントと TNF の型拡張コードがプログラムにコンパイルされないようにしてください。
引数の名前に含まれている数字 1 〜 5 は、プローブポイントに指定する変数の数を表します。たとえば、TNF_PROBE_1 の構文は次のようになっています。
TNF_PROBE_1(name, keys, detail, arg_type_1, arg_name_1, arg_value_1);
また、TNF_PROBE_5 の構文は次のようになっています。
TNF_PROBE_5(name, keys, detail, arg_type_1, arg_name_1, arg_value_1 arg_type_2, arg_name_2, arg_value_2 arg_type_3, arg_name_3, arg_value_3 arg_type_4, arg_name_4, arg_value_4 arg_type_5, arg_name_5, arg_value_5);
以下、各引数について説明します。
arg_type_n − n 番目の引数の型です。n には 1 〜 5 の数字が入ります。定義済みの型を表 1-9 に示します。ユーザー独自の型の定義については、「プローブポイントのユーザー定義型」 を参照してください。
arg_name_n − n 番目の引数に与える名前です。 ANSI C の識別子に関する規則に従ってください。また、引数の名前は、引用符で囲まないでください。(「属性」で取り上げた slots 属性には、この名前の文字列の場合が含まれています。)
arg_value_n − トレースファイルに含まれている値に対して評価される式です。value_n に含まれている任意の変数に対して読み取り (アクセス) を行うことができます。マルチスレッドのプログラムで、読み取りを禁止する必要があるデータが value_n に含まれている場合には、マクロ TNF_PROBE_n の前後にロックを配置してください。
型 |
対応する C 言語の型と意味 |
---|---|
tnf_long |
int、long |
tnf_ulong |
unsigned int、unsigned long |
tnf_longlong |
long long (コンパイラに実装されている場合) |
tnf_ulonglong |
unsigned long long (コンパイラに実装されている場合) |
tnf_float |
float |
tnf_double |
double |
tnf_string |
char * |
tnf_opaque |
void * |
たとえば、「C プログラムのサンプル」の cookie.c では、以下のように TNF_PROBE_2 を使用しています。
TNF_PROBE_2(inloop, "cookie main loop","sunw%debug in the loop", tnf_long, loop_count, i, tnf_long, total_iterations, sum);
cookie.c のマクロ定義の一部について、表 1-10 で説明します。
表 1-10 cookie.c の TNF マクロ定義
TNF_PROBE_0 ( |
引数の型が指定されていないプローブ |
start, |
プローブの名前 |
"cookie main", |
プローブが cookie と main (keys 属性の値) に属しているグループのリスト |
"sunw%debug starting main"); |
ユーザー定義の属性 = sunw%debug、値 = starting main (デバッグプローブ関数で使用されます) |
TNF_PROBE_2 ( |
2 つの変数を持ったプローブ |
inloop, |
プローブの名前 |
"cookie main loop", |
keys - cookie、main、loop |
"sunw%debug in the loop", |
デバッグプローブ関数の値 |
tnf_long, |
最初の変数の型 |
loop_count, |
最初の変数の名前 (slots 属性の値) |
i, |
最初の変数 |
tnf_long, |
2 番目の変数の型 |
total_iterations, |
2 番目の変数の名前 (slots 属性の値) |
sum); |
2 番目の変数 |
""); |
例 1-4 では、関数の入口と出口にプローブポイントを配置して、関数内で費やされる時間を測定しています。関数の入口に配置されたプローブは、その関数への引数も記録します。
prex は、トレースが許可されているプローブポイントをプログラム実行時に検出すると、トレースファイルに記録を書き込みます。各プローブポイントは、検出された時刻を記録し、ファイル名、行番号、name、keys などのプローブポイントの詳細情報が含まれたタグ記録を参照します。これらのタグの記録は、トレースファイルに 1 度だけ書き込まれ、上書きされることはありません。
以下のコード例において、最初のプローブポイント work_args は、そのプローブポイントの 2 つの変数値 (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_0(work_end, "work_module work", ""); }