2016-07-03 5 views
2

私が取り組んでいるプロジェクトでは、エラーを処理するためのエラーコード(例外なし)を返す関数のみを使用することに同意しました。引数値の計器化

私のコードをデバッグメッセージで「汚染」させないために、私は計装に基づいたソリューション(this postに触発されています)に取り組んでいました。で、しかし

// File rc.cc 
#include <stdio.h> 
#include <time.h> 
#include "rc.h" 

static FILE *fp_trace; 
static int isError;  

extern "C" 
{ 

    void __attribute__ ((constructor)) trace_begin (void) 
    { 
     fp_trace = fopen("trace.out", "w"); 
     isError = 0; 
    } 

    void __attribute__ ((destructor)) trace_end (void) 
    { 
     if(fp_trace != NULL) { 
     fclose(fp_trace); 
     } 
    } 

    void __cyg_profile_func_enter (void *func, void *caller) __attribute__((no_instrument_function)); 
    void __cyg_profile_func_exit (void *func, void *caller) __attribute__((no_instrument_function)); 

    void __cyg_profile_func_enter (void *func, void *caller) 
    { 
    } 

    void __cyg_profile_func_exit (void *func, void *caller) 
    { 
    if ((fp_trace != NULL) && (isError == 1)) { 
     fprintf(fp_trace, "x %p %p %lu\n", func, caller, time(NULL)); 
     isError = 0; 
    } 
    } 
} 

rc::rc(int valueIn) : 
    value(valueIn) 
{ 
} 

rc& rc::operator=(rc rcIn) 
{ 
    value = rcIn.value; 
    if (value != 0) 
    { 
     isError = 1; 
     fprintf(fp_trace, "%d\n", value); 
    } 
    return *this; 
} 

:次に、これらの演算子と計測機能を定義

// File rc.h 
class rc 
{ 
public: 
    rc(int) __attribute__((no_instrument_function)); 
    rc& operator=(rc); 
private: 
    int value; 
}; 

:代わりに、エラーコードとしてint型を使用しての

、私はとクラスでそれをカプセル化していますあまりにも多くのものを印刷しないようにするには、戻りコード0を返す関数呼び出しをログに記録したくないので、isErrorフラグ。

これは、以下の例で使用することができます:

#include <cstdlib> 
#include <ctime> 
#include "rc.h" 

rc bar(void) 
{ 
    rc result(std::rand() % 3); 
    return result; 
} 

int main(void) 
{ 
    std::srand (std::time(NULL)); 
    rc returnCode(0); 
    for (int i=0; i<10; ++i) 
    { 
    returnCode = bar(); 
    } 
    return 0; 
} 

コンパイルとin the previously mentioned post指定したスクリプトを使って出力を読む

g++ -finstrument-functions -g -c -o rc.o rc.cc 
g++ -g -c -o test.o test.cc 
g++ test.o rc.o -o a.out 
./a.out 

で実行のようなものになります:

Error code 2 
rc::operator=(rc) at 2016-07-03T18:32:09+0200, called from main (test.cc:32) 

これは私が望むことができるほとんどです。しかし、出力がゼロでないかどうかをテストしてエラーをログに記録するというテストをrc foo(void)に追加するだけの解決策と比較すると、エラーが発生した場合のオーバーヘッド(チェックによるオーバーヘッド)うまくいけばそれほど頻繁ではありません)、私は機器ごとにオーバヘッドを追加します(rcラッパーのためにオーバーヘッドがありますが、それでも問題ありませんが)...

ソリューションはありますか?引数がゼロの場合にはを計測しませんか? rc::valueは実行時にしか分かっていないので、私はテンプレートをvalue=0に特化した値と引数を持つテンプレートとは思っておらず、その場合は機能しません。それ?

追加の制約があります:呼び出し側のことを知りたいので、計装された関数が代入演算子であることが重要です。したがって、追加のプロキシレベルを追加できません。


編集この最後の点について、私は代入演算子をインラインに作ることを考えて(とインストルメントではない)しましたし、リターンコードがゼロではないですが、それができない場合は、インストルメント関数を呼び出しますfinstrument-function doc pageは、次のように述べています。

この計測は、他の関数でインライン展開された関数に対しても行われます。プロファイリングコールは、インライン関数がどこに概念的に入力され、終了したかを示します。

実際の呼び出し元を指していないようにします。

+0

すべてのコードを一から書き、決してC++ライブラリを使用しない限り、あなたのプログラムで例外が発生する可能性が高いことは知っていますか? –

+0

はい、私はこれを認識しています。しかし、我々は多くのものを書き直しています... – Vser

+0

エラーコードとして負の数を使用し、結果に正の値(0を含む)を使用することをお勧めします。これがLinuxのシステムコールがすることです。 –

答えて

0

解決方法は計装に依存するのではなく、計器によって使用される関数に依存します。

あなたは、呼び出し元の戻りポインタを取得するには、この機能を使用することができます:あなたは、発信者のアドレスを取得するために、計測器に依存する必要はありませんし、使用した上で、本当にわずかなオーバーヘッドが追加されます

rc& rc::operator=(rc rcIn) 
{ 
    value = rcIn.value; 
    if (value != 0) 
    { 
     fprintf(fp_trace, "%d %p\n", value, __builtin_return_address(1)); 
    } 
    return *this; 
} 

その方法単純にintです。

関連する問題