8

さまざまなコンパイル時オプション(_BUILD_SMALL、_BUILD_FASTなど)を使用して構築できる静的Cライブラリがあります。機能があります

void Foo(void);

ベンチマークツールの単一インスタンスを使用して、ライブラリの「小さい」バージョンと「速い」バージョンのベンチマークを行いたいと思います。.dllを使用したくありません。

「small」ライブラリと「fast」ライブラリにリンクし、関数名にエイリアスを付けて、smallバージョンとfastバージョンを呼び出すにはどうすればよいですか。理想的には、次のようになります。

void benchmark(void)
{
  FAST_Foo();

  SMALL_Foo();
}

詳しくは:

ライブラリは、さまざまな最適化オプション-Osと-O3を使用して構築できます。また、アルゴリズムはわずかに異なります(つまり、キャッシュされた値と常に値を検索する)。異なるバージョンのサイズと速度のトレードオフを比較したいと思います。ユニットテストとベンチマークを、ライブラリの両方のバージョンで可能な限り最も簡単な方法で実行したいと思います。

4

6 に答える 6

6

これは、@MichałGórnyによって与えられた方法の単なるバリエーションです(コメントスペースが不足しています)...

次の形式のインクルードファイルを作成できます。

/* Automatically created file - do not edit or ugly dinosaur will eat you */
#ifndef PREFIX
#  define RENAME(f)
#else
#  define RENAME(f) PREFIX ## f
#endif

/* list all the function and variables you want to rename here in one place */
#define func_foo RENAME(func_foo)
#define func_bar RENAME(func_bar)
/* ... many more ... */

#undef RENAME

少なくともgcc、オプションを使用してコマンドラインからヘッダーファイルを含めるように指定できます-include rename.h(このファイルが呼び出されると仮定しますrename.h)。gccそっくりのオプション(-O3および)を使用しているため、この回答の残りの部分でOs使用していると想定しています。gccそれ以外の場合、Cコンパイラが妥当であれば、同様の方法で実行できるはずです。

CFLAGSCコンパイラにさまざまなオプションを提供することで(ここでは設定を通じて)、必要に応じて同時にリンクできるライブラリの2つまたは3つのバージョンを簡単に作成できます。

CFLAGS += -include rename.h -DPREFIX=fast_ -D_BUILD_FAST -O3 -DBENCHMARKING
CFLAGS += -include rename.h -DPREFIX=small_ -D_BUILD_SMALL -Os -DBENCHMARKING
CFLAGS += -D_BUILD_FAST -O2

ライブラリヘッダーファイルが非常に規則的に見え、ライブラリプライベート関数を宣言する場合、static非常に単純な正規表現を使用してダミースクリプトを使用し、それらのヘッダーファイルから関数を簡単に抽出して、rename.hファイルを自動的に生成します。makeを使用している場合、または同様のものを使用している場合、これは自然なビルドターゲットです。同時に使用できるようにするには、同じメソッドを使用してすべてのグローバル変数の名前も変更する必要があります。

このソリューションには、次の3つの主要なポイントがあります。

  1. 醜い名前変更ビジネスは1つのファイルに隠すことができ、実際のソースファイルを編集する必要はありません。特に、ソースファイルを乱雑にする必要はありませんが、クリーンで読みやすくすることができます。
  2. いくつかの単純な原則に従うと、名前の変更を簡単に自動化できます(ヘッダーファイルとヘッダーファイルのコーディング規則に従って、すべてのグローバル変数と関数が宣言されます)。
  3. テストプログラムを複数回実行する必要があるため、ベンチマークをより面倒にする理由はありません(これは、私と同じように怠惰で、私と同じように繰り返しのタスクが嫌いな場合に関係します-多くの人が気にしないことを知っています、それはやや好みの問題)。
于 2012-08-21T04:12:46.870 に答える
2

両方の静的ライブラリを同じ実行可能ファイルにリンクしようとすると、リンク行にリストされている2番目のライブラリは効果がありません。これは、提供されたすべてのシンボルが最初のライブラリによってすでに満たされているためです。呼び出すための単純な一意のラッパー関数を提供しFooた場合でも、複数の定義があるため、失敗します。次に例を示します。

/* x.c */
extern void Y_Bar ();
extern void Z_Bar ();
int main ()
{
    Y_Bar();
    Z_Bar();
}

liby.aこのメインは、およびで提供される一意のラッパー関数を呼び出しますlibz.a

/* y.c in liby.a */
#include <stdio.h>
void Y_Bar () {
    extern void Foo ();
    Foo();
}
void Foo () {
    printf("%s\n", "that Foo");
}

/* z.c in libz.a */
#include <stdio.h>
void Z_Bar () {
    extern void Foo ();
    Foo();
}
void Foo () {
    puts("this foo");
}

実行可能ファイルをとリンクしようとする-ly -lzと失敗します。

最も簡単な回避策は、2つの別々の実行可能ファイルを作成することです。次に、ベンチマークドライバーは、両方の実行可能ファイルを実行して、それらの相対的なパフォーマンスを比較できます。

于 2012-08-15T21:41:53.447 に答える
2

1つの方法は、両方に同じ名前を付け、コンパイル時のオプションセットに応じて適切に呼び出すことです。

ifdef SMALL_FOO
void foo() {

/* Small foo code */
}
#endif

ifdef BIG_FOO
void foo() {

/* Big foo code */
}
#endif

SMALL_FOO/BIG_FOOコンパイル中にを設定し-dます。

于 2012-08-15T20:41:10.793 に答える
2

簡単な解決策として、マクロを使用して次のように関数名をマングルすることができます。

#ifdef FAST
#   define FUNC(x) FAST_##x
#else
#   define FUNC(x) SLOW_##x
#endif

void FUNC(Foo)();

そして今-DFAST、ライブラリを使用しFAST_Fooてビルドされます。それがなければ、SLOW_FooFUNC()実装部分でもマクロを使用する必要があり(ライブラリ内からその関数を参照する場合は常に)、#ifdef FAST高速コードと低速コードを切り替える必要があることに注意してください。

実稼働コードでは使用しないでください。

于 2012-08-15T20:47:27.360 に答える
0

ライブラリをビルドしてコンパイル時のオプションを変更できると言うので、コードを編集してそれぞれの関数の名前を変更してみませんか。(ライブラリの2つの異なるバージョンを作成することになります。)

于 2012-08-15T20:41:29.917 に答える
0

たぶん-D option when call gcc, like -D_FAST_, -D_SMALL_,、makeを使用するときに入力パラメータを使用するか、受け取ることができます。たとえば、でmakeを使用する場合のようCFG=FAST, make CFG=SMALL,makefile、パラメータを取得するときに定義できますFAST, link to FAST library

于 2012-08-16T05:57:12.200 に答える