[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

17.7.11 プロファイリング用コードの生成

以下のマクロは、プロファイル用コードの生成を助ける。

FUNCTION_PROFILER (file, labelno)

一個の C の文か複文で、file に、プロファイルサブルーチン mcount を呼び出すアセンブラコードを出力する。 呼び出しの前に、このアセンブラコードはカウンタ変数のアドレスを、 mcount がそのアドレスを見つけると想定しているレジスタに ロードしなければならい。このカウンタ変数の名前は ‘LP’ の後に、 番号 labelno が付いたものなので、fprintf で ‘LP%d’ と することでこの名前を生成できる。

アドレスが mcount にどのように渡されるかの詳細は、 GNU CC ではなく、ユーザのオペレーティングシステム環境により 決まる。それがどういうものであるか調べるには、小さいプログラムを システムにインストール済みの C コンパイラを使ってプロファイリング用に コンパイルし、その結果生成されるアセンブラコードを見れば良い。

PROFILE_BEFORE_PROLOGUE

関数のプロファイリング用コードを関数のプロローグコードの前に置くべきなら このマクロを定義する。普通は、プロファイリング用コードはプロローグコードの 後に来る。

FUNCTION_BLOCK_PROFILER (file, labelno)

一個の C の文か複文で、file に、現在のオブジェクトモジュールの 基本ブロックのプロファイリングを初期化するアセンブラコードを出力する。 グローバルなコンパイルフラグ profile_block_flag で 二つのプロファイリングのモードを区別する。

profile_block_flag != 2

オブジェクトモジュール毎にサブルーチン __bb_init_func を一度だけ 呼び出すコードを出力する。このサブルーチンにはただ一つの引数として、 そのオブジェクトモジュール内に割り当てられたあるブロックのアドレスを 渡す。

ブロック名はローカルシンボルであり、次の文で作られる。

 
ASM_GENERATE_INTERNAL_LABEL (buffer, "LPBX", 0);

もちろん、このマクロの定義だけではなくて、 ASM_GENERATE_INTERNAL_LABEL の定義も書くわけだから、 このマクロの定義をショートカットして、生成されるとわかっている名前を 使っても良い。

このブロックの先頭のワードは、そのオブジェクトモジュールが既に初期化済み であればゼロでない値となるフラグである。そのため、まずこのワードを 調べ、フラグがゼロでなければ __bb_init_func を呼ばないようにする。 labelno には、__bb_init_func が呼ばれないときの 分岐先ラベルを生成するのに使われる一意的な番号が入る。

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

 
  cmp (LPBX0),0
  bne local_label
  parameter1 <- LPBX0
  call __bb_init_func
local_label:
profile_block_flag == 2

サブルーチン __bb_init_trace_func を呼び出し、二つのパラメータを 渡すコードを出力する。 第一のパラメータは __bb_init_func と同じである。 二番目のパラメータは、labelno により与えられる関数の先頭の 基本ブロックの番号である。 __bb_init_trace_func は、オブジェクトモジュールが既に初期化済み の場合でも、必ず呼び出されなければならないことに注意して欲しい。

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

 
parameter1 <- LPBX0
parameter2 <- BLOCK_OR_LABEL
call __bb_init_trace_func
BLOCK_PROFILER (file, blockno)

一個の C の文か、複文。この文は file に、 基本ブロック番号 blockno に付随するカウンタをインクリメント するアセンブラコードを出力する。 グローバルなコンパイルフラグ profile_block_flag で、 以下の二つのプロファイルモードを区別する。

profile_block_flag != 2

カウンタを直接インクリメントするコードを出力する。基本ブロックは 各コンパイル毎に別々にゼロから始まる番号が付けられる。 基本ブロック番号 blockno に付随するカウンタは、ワードの ベクトルの添え字 blockno の要素にある。 この配列の名前は、以下の文で作られるローカルシンボルである。

 
ASM_GENERATE_INTERNAL_LABEL (buffer, "LPBX", 2);

もちろん、このマクロの定義だけではなくて、 ASM_GENERATE_INTERNAL_LABEL の定義も書くわけだから、 このマクロの定義をショートカットして、生成されるとわかっている名前を 使っても良い。

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

 
inc (LPBX2+4*BLOCKNO)
profile_block_flag == 2

グローバルな構造体 __bb を初期化し、関数 __bb_trace_func を呼び出すコードを出力する。__bb_trace_func は、カウンタを インクリメントする。

__bb は二つのワードからなる。最初のワードには、blockno で与えられる、現在の基本ブロックの番号が格納されなければならない。 二番目のワードには、オブジェクトモジュール中に割り当てられたブロックの アドレスが格納されなければならない。このアドレスは、以下の文で作られる ラベルで与えられる。

 
ASM_GENERATE_INTERNAL_LABEL (buffer, "LPBX", 0);

アセンブラ言語で書くと、出力すべきコードは以下のようになる。

 
move BLOCKNO -> (__bb)
move LPBX0 -> (__bb+4)
call __bb_trace_func
FUNCTION_BLOCK_PROFILER_EXIT (file)

一個の C の文か、複文。この文は、file に関数 __bb_trace_ret を呼び出すアセンブラコードを出力する。 このアセンブラコードは、グローバルなコンパイルフラグ profile_block_flag == 2 の場合だけ出力すべきである。 このマクロは、関数から戻るためのコードが生成される全ての場所で (例えば、FUNCTION_EPILOGUE)使う必要がある。 FUNCTION_EPILOGUE の定義も同様に書かなければならないが、 このマクロを定義することでコンパイラに対し、__bb_trace_ret の 正しい呼び出しが生成されるよう指示しなければならない。

MACHINE_STATE_SAVE (id)

一個の C の文か、一個の複文。この文は、全レジスタをセーブする。 レジスタは関数呼び出しにより破壊されるものであっても良く、条件コードを含む。 この作業を扱うのに一番必要そうなのは、asm 文だろう。 アセンブラコード中の局所ラベルを文字列 id と連結して、 一意的なラベル名を得ることもできる。

FUNCTION_PROLOGUEFUNCTION_EPILOGUE により 破壊されるレジスタや条件コードは、マクロ FUNCTION_BLOCK_PROFILERFUNCTION_BLOCK_PROFILER_EXITBLOCK_PROFILER により、 それぞれ __bb_init_trace_func__bb_trace_ret__bb_trace_func の呼び出しに先だって、セーブしなければならない。

MACHINE_STATE_RESTORE (id)

MACHINE_STATE_SAVE によりセーブされた、条件コードを含む、 全レジスタをリストアする C の文か複文。

FUNCTION_PROLOGUEFUNCTION_EPILOGUE により 破壊されるレジスタや条件コードは、マクロ FUNCTION_BLOCK_PROFILERFUNCTION_BLOCK_PROFILER_EXITBLOCK_PROFILER により、 それぞれ __bb_init_trace_func__bb_trace_ret__bb_trace_func の呼び出しの後で、リストアしなければならない。

BLOCK_PROFILER_CODE

ブロックプロファイリングをサポートするライブラリで必要な一つの、 あるいは複数の関数。


This document was generated using texi2html 1.78.