| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
以下のマクロは、プロファイル用コードの生成を助ける。
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_PROLOGUE か FUNCTION_EPILOGUE により
破壊されるレジスタや条件コードは、マクロ FUNCTION_BLOCK_PROFILER、
FUNCTION_BLOCK_PROFILER_EXIT、BLOCK_PROFILER により、
それぞれ __bb_init_trace_func、__bb_trace_ret、
__bb_trace_func の呼び出しに先だって、セーブしなければならない。
MACHINE_STATE_RESTORE (id)MACHINE_STATE_SAVE によりセーブされた、条件コードを含む、
全レジスタをリストアする C の文か複文。
FUNCTION_PROLOGUE か FUNCTION_EPILOGUE により
破壊されるレジスタや条件コードは、マクロ FUNCTION_BLOCK_PROFILER、
FUNCTION_BLOCK_PROFILER_EXIT、BLOCK_PROFILER により、
それぞれ __bb_init_trace_func、__bb_trace_ret、
__bb_trace_func の呼び出しの後で、リストアしなければならない。
BLOCK_PROFILER_CODEブロックプロファイリングをサポートするライブラリで必要な一つの、 あるいは複数の関数。
This document was generated
using texi2html 1.78.