4

プロファイリングを行うために、Cでスコープガードを使用したいと思います。

関数にどれだけの時間を費やしているか知りたいのですが。これが私がすることです:

int function() {

  tic();

  ... do stuff ...
  if (something)
  {
    toc();
    return 0;
   }

  toc();
  return 1;
}

関数を終了するたびにtocステートメントを配置する必要があります。どこにでも貼り付けtocをコピーせずにそれをやりたいです。マクロなどを使用して、それを行う一般的な方法はありますか?また、プロファイリングする必要のある関数が多数あるため、関数の呼び出し方法を変更したくありません。

ありがとう

4

8 に答える 8

5

これは、関数の呼び出し方法を変更しません。ただし、すべての関数をプロファイリングできるようにしたい場合は、おそらくあまり役​​に立ちません。

static inline int real_function() {
    // previous contents of function(), with no tic or toc
}

int function() {
    tic();
    int r = real_function();
    toc();
    return r;
}

誰もが言うように、プロファイラーを使用すると、長期的には多くの労力を節約できます。彼らが言っていないように:あなたのプラットフォームにそれがある場合。

そうでない場合、最も簡単な方法は、(コーディング ルールとして) 関数には 1 つの終了ポイントのみが必要であり、その終了ポイントはマクロ経由でなければならないということです。その後、入口と出口でコードを使用してすべての関数を手動で計測できます。複数の戻り値を持つレガシー関数は、上記のようにまとめることができます。

また、このようなことをしているときは、コンパイラが混乱する可能性があることに注意してください。あなたはこれを書くかもしれません:

tic();
do_something();
int i = something_else();
toc();
return i;

コンパイラは、something_else に副作用がないと判断した場合、something_else にかなりの時間がかかりますが、コードを次のように変更する可能性があります。

tic();
do_something();
toc();
return something_else();

また、プロファイル データは、関数に費やされた時間を過小評価します。もう 1 つの理由は、実際のプロファイラーが非常に優れていることです。それは、コンパイラーと連携できます。

于 2010-01-19T19:25:08.933 に答える
4

次のようなマクロを定義できます。

#define TOC_RETURN(x) \
    do { \
    toc(); \
    return x; \
    } while(0)

どこに置いても機能するはずです。return *;次に、 への置換を自動化できますTOC_RETURN(*)

于 2010-01-19T18:57:43.680 に答える
4

gprofのような実際のプロファイリング ツールを使用してみませんか?

于 2010-01-19T18:59:40.367 に答える
2

マクロを介してリターンを「再定義」することができます:(免責事項を参照してください)

#include <stdio.h>

void tic() { printf("tic\n"); }
void toc() { printf("toc\n"; }

#define return toc(); return
int foo() {
    tic();

    return 0;
}
#undef return

int main() {
    foo();
    return 0;
}

免責事項:これは、次の理由で醜くハッキーと見なすことができます。

  • returnを使用しない限り、void関数では機能しません。-ステートメント。
  • MSVC8で動作しますが、ポータブル/標準ではない可能性があります。
  • キーワードを定義するべきではありません。
于 2010-01-19T19:05:05.987 に答える
1

これにはマクロをお勧めしません。たまにコードをプロファイリングし、その目的のためだけに「return」を特別なマクロに置き換えると、コードが読みにくくなります。

以下のようにすればよくないですか?

tic();
call_function();
toc();

これにより、関数からの「すべての終了ポイント」が自動的に処理されます。

PS なぜプロファイラーを使わないのですか?

于 2010-01-19T18:58:38.807 に答える
1

実際のプロファイラーでは、プロファイリングを有効にしてコンパイルするだけで、コードを変更する必要はありません。

于 2010-01-19T18:59:31.490 に答える
0

うーん、関数呼び出しをマクロ (実際にはマクロのファミリ) でラップすることはできますか? これは引数を取らず、Retval を返すものです:

// define the wrapper for name
#define DEFTIMECALL0(Retval,name) \
    Retval timed##name() \
    { \
        Retval ret;
        tic(); \
        ret = name(); \
        toc(); \
        return ret; \
    }

Retval と void を返すバージョンを使用して、作成する関数呼び出しのアリティごとにマクロが必要になります。

編集ラッパー関数を定義する意味さえないかもしれません。関数呼び出しを tic/toc で直接ラップするマクロのファミリを (ここでも、アリティと戻り値の型/void バージョンごとに) 持つ方がよいでしょう。コールサイト

基本的にこれを行うプロファイラーの計測を恐れないでください。

于 2010-01-19T18:58:09.057 に答える