2

GPU または CPU で実行できるコードを記述します。CUDA プレゼンス ラッパーの場合、GPU で関数を実行してみます。エラーの場合 (メモリがないなど)、CPU で実行しようとします。再びエラーが発生した場合は 0 を返し、それ以外の場合は 1 を返します。CUDA が存在しない場合、ラッパーは CPU でのみ関数を実行しようとします。

これが私のマクロです:

#ifdef CUDA_FOUND
#define SET_F(FNARGS, FNSTRIP) int FNARGS{  \
    if(!Only_CPU) if(CU ## FNSTRIP) return 1;\
    if(CPU ## FNSTRIP) return 1;            \
    return 0;                               \
}
#else
#define SET_F(FNARGS, FNSTRIP) int FNARGS{  \
    if(CPU ## FNSTRIP) return 1;            \
    return 0;                               \
}
#endif // CUDA_FOUND

新しい関数を定義するには、次のように呼び出します。

SET_F(fillrandarr(size_t sz, char *arr), fillrandarr(sz, arr))

質問FNARGS: composeの引数を分割するこのマクロを単純化する方法はありFNSTRIPますか? つまり、上記の定義を次のように短縮します。

SET_F(fillrandarr(size_t sz, char *arr))

?

4

4 に答える 4

4

nmが彼のコメントに書いたように:

Boost プリプロセッサ ライブラリはおそらくこれを行うことができます。
Boost は一般的に C++ ですが、プリプロセッサ ライブラリは単なるマクロのセットであり、(私の知る限り) C++ 固有の部分はありません。

したがって、ここにブーストっぽいソリューションがあります:

#define BOOST_PP_VARIADICS 1

#include <boost/preprocessor.hpp>

#define FOO(...) FOO2(BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define FOO2(seq) FOO3(BOOST_PP_SEQ_HEAD(seq),BOOST_PP_SEQ_TAIL(seq))
#define FOO3(name, args) FOO6(name,                                \
                              BOOST_PP_SEQ_FOR_EACH_I(FOO4,,args), \
                              BOOST_PP_SEQ_FOR_EACH_I(FOO5,,args))
#define FOO4(rep, data, index, type) (type BOOST_PP_CAT(arg,index))
#define FOO5(rep, data, index, type) (BOOST_PP_CAT(arg,index))
#define FOO6(name, dargs, cargs)                                   \
  FOO8(name, FOO7(dargs, void), FOO7(cargs, ))
#define FOO7(seq, empty)                                           \
  BOOST_PP_IF(BOOST_PP_SEQ_SIZE(seq),                              \
              BOOST_PP_SEQ_TO_TUPLE(seq), (empty))
#define FOO8(name, dargs, cargs)                                   \
  int name dargs {                                                 \
    if (BOOST_PP_CAT(CPU_, name)cargs)                             \
      return 1;                                                    \
    return 0;                                                      \
  }

FOO(fillrandarr, size_t, char*)
FOO(fun1, int, double)
FOO(fun2)

次のようなコードを生成します (フォーマットは私が追加しました):

int fillrandarr (size_t arg0, char* arg1) {
  if (CPU_fillrandarr(arg0, arg1))
    return 1;
  return 0;
}

int fun1 (int arg0, double arg1) {
  if (CPU_fun1(arg0, arg1))
    return 1;
  return 0;
}

int fun2 (void) {
  if (CPU_fun2())
    return 1;
  return 0;
}

引数の名前は実質的に重要ではないため、マクロ呼び出しから省略しました。同じフレームワークで、引数のない関数の最後のケースを正しく処理するために、特別な注意が払われています。

さまざまな手順は次のとおりです。

  1. 可変個引数マクロはゼロ引数と 1 つの空の引数を明らかに区別できないため、常に関数名を含む最初のマクロは、可変個引数をより扱いやすいデータ構造 (この場合は括弧で囲まれた式のシーケンス) に変換する必要があります。
  2. 次に、そのシーケンスを関数名と引数の型に分割します。
  3. 引数型シーケンスを、関数定義用と関数呼び出し用の 2 つのシーケンスに変換します。
  4. 関数定義では、各引数名の前にその型を付けます。
  5. 関数呼び出しの場合、型を無視して、番号付きの引数名を単純に記述します。
  6. 次に、空のシーケンスを正しく処理する必要があります。呼び出しの場合は単純に記述できます()が、関数定義の場合は(void)代わりに記述する必要があります。
  7. そのため、シーケンスのサイズがゼロでないかどうかを確認します。その場合、それをタプルに変換します。つまり、要素間のカンマと要素の周りの括弧です。それ以外の場合は、提供されたデフォルトを使用します。
  8. 今、私たちはあなたが要求した方法ですべてを組み合わせます.
于 2013-01-17T12:27:55.580 に答える
2

別の数のパラメーターを使用して、関数用に既に持っているラッパー マクロを宣言することができます。

#define SET_F_2(fname, \
  vtype1, vname1, \
  vtype2, vname2 \
) \
  SET_F( \
    fname( \
      vtype1 vname1, \
      vtype2 vname2 \
    ), \
    fname( \
      vname1, \
      vname2 \
    ) \
)

#define SET_F_3(fname, \
  vtype1, vname1, \
  vtype2, vname2, \
  vtype3, vname3 \
) \
  SET_F( \
    fname( \
      vtype1 vname1, \
      vtype2 vname2, \
      vtype3 vname3 \
    ), \
    fname( \
      vname1, \
      vname2, \
      vname3 \
    ) \
)

... and so on

次のように使用します。

SET_F_2(x, short, s, int, i);
SET_F_3(y, int, i, short, s, float, f);

このアプローチは、 a のパラメーター数をカウントするためのslartibartfast 提案を使用して、冗長性を減らすために確実に最適化される可能性が#defineあります。

于 2013-01-16T17:22:40.940 に答える
1

プリプロセッサで前処理シンボルを分解することはできません。それらを結合することしかできません。これは、"fillrandarr(sz,arr)" がプリプロセッサの 1 つのアトミック ユニットであり、ニーズに合わないことを意味します。次のように、パラメーターリストで区切られたシンボルを渡す必要があります

#define SET_F(f_name,p1_type,p1_name,p2_type,p2_name) ...

関数に入る可変量のパラメーターについては、次を使用します

#define CNT_ARGS(...) CNT_ARGS_(__VA_ARGS__,8,7,6,5,4,3,2,1)
#define CNT_ARGS_(_1,_2,_3,_4,_5,_6,_7,_8,n) n

#define DROP_TYPE(...) DROP_TYPE_(CNT_ARGS(__VA_ARGS__),__VA_ARGS__)
#define DROP_TYPE_(n,...) DROP_TYPE__(n,__VA_ARGS__)
#define DROP_TYPE__(n,...) DROP_TYPE_##n(__VA_ARGS__)
#define DROP_TYPE_2(ptype,pname,...) pname
#define DROP_TYPE_4(ptype,pname,...) pname, DROP_TYPE_2(__VA_ARGS__)
#define DROP_TYPE_6(ptype,pname,...) pname, DROP_TYPE_4(__VA_ARGS__)
#define DROP_TYPE_8(ptype,pname,...) pname, DROP_TYPE_6(__VA_ARGS__)


#define FOO(fname,...)  fname(DROP_TYPE(__VA_ARGS__))

    FOO(my_func,t1,p1,t2,p2,t3,p3,t4,p4)  -> my_func(p1,p2,p3,p4)
    FOO(other_func,t1,p1,t2,p2)           -> other_func(p1,p2)
于 2013-01-16T08:44:57.650 に答える
1

結局、私は次のことをしました(最大10個の引数):

#define Fn1(A,B) A(x1)
#define Df1(A,B) A(B x1)
#define Fn2(A,B,C) A(x1, x2)
#define Df2(A,B,C) A(B x1, C x2)
#define Fn3(A,B,C,D) A(x1, x2, x3)
#define Df3(A,B,C,D) A(B x1, C x2, D x3)
#define Fn4(A,B,C,D,E) A(x1, x2, x3, x4)
#define Df4(A,B,C,D,E) A(B x1, C x2, D x3, E x4)
#define Fn5(A,B,C,D,E,F) A(x1, x2, x3, x4, x5)
#define Df5(A,B,C,D,E,F) A(B x1, C x2, D x3, E x4, F x5)
#define Fn6(A,B,C,D,E,F,G) A(x1, x2, x3, x4, x5, x6)
#define Df6(A,B,C,D,E,F,G) A(B x1, C x2, D x3, E x4, F x5, G x6)
#define Fn7(A,B,C,D,E,F,G,H) A(x1, x2, x3, x4, x5, x6, x7)
#define Df7(A,B,C,D,E,F,G,H) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7)
#define Fn8(A,B,C,D,E,F,G,H,I) A(x1, x2, x3, x4, x5, x6, x7, x8)
#define Df8(A,B,C,D,E,F,G,H,I) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7, I x8)
#define Fn9(A,B,C,D,E,F,G,H,I,J) A(x1, x2, x3, x4, x5, x6, x7, x8, x9)
#define Df9(A,B,C,D,E,F,G,H,I,J) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7, I x8, J x9)
#define Fn10(A,B,C,D,E,F,G,H,I,J,K) A(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)
#define Df10(A,B,C,D,E,F,G,H,I,J,K) A(B x1, C x2, D x3, E x4, F x5, G x6, H x7, I x8, J x9, K x10)

#define DEF(N, ...) int Df ## N(__VA_ARGS__)
#define CONCAT(A, B) A ## B
#define FN(N, ...) Fn ## N(__VA_ARGS__)
#define DF(N, ...) Df ## N(__VA_ARGS__)
#define XFUNC(T, X) CONCAT(T, X)
#define FUNC(T, ...) XFUNC(T, FN(__VA_ARGS__))
#define DFUNC(T,...) EXTERN int XFUNC(T, DF(__VA_ARGS__))

#ifdef WRAPPER_C
// even when using cuda in case of fail CUDA init use CPU
static int Only_CPU =
#ifdef CUDA_FOUND
    0
#else
    1
#endif
;
#ifdef CUDA_FOUND
#define SET_F(...) DEF(__VA_ARGS__){                    \
    if(!Only_CPU) if(FUNC(CU, __VA_ARGS__)) return 1;   \
    if(FUNC(CPU, __VA_ARGS__)) return 1;                \
    return 0;                                           \
}
#else
#define SET_F(...) DEF(__VA_ARGS__){                    \
    if(FUNC(CPU, __VA_ARGS__)) return 1;                \
    return 0;                                           \
}
#endif // CUDA_FOUND
#else
    #define SET_F(...)
#endif // WRAPPER_C

#ifdef CPU_C // file included from CPU.c
    #define BOTH(...) DFUNC(CPU, __VA_ARGS__);
    //#pragma message "CPUC"
#elif defined CUDA_CU //file included from CUDA.cu
    #define BOTH(...) DFUNC(CU, __VA_ARGS__);
#elif defined WRAPPER_C // wrapper.c needs names of both wariants
    #ifndef CUDA_FOUND
        #define BOTH(...) DFUNC(CPU, __VA_ARGS__);
    #else
        #define BOTH(...) DFUNC(CU, __VA_ARGS__); DFUNC(CPU, __VA_ARGS__);
    #endif // CUDA_FOUND
#else // file included from something else - just define a function
    #define BOTH(...) DFUNC(, __VA_ARGS__);
#endif

#define DFN(...) BOTH(__VA_ARGS__) SET_F(__VA_ARGS__)

このコードはファイル wrapper.h にあります。wrapper.c はコードの共通部分のみで構成されています。

関数を定義するには、wrapper.h に次のように記述します。

DFN(2, fillrandarr, size_t, float *)
DFN(6, bicubic_interp, float *, float *, size_t, size_t, size_t, size_t)
于 2013-01-17T13:04:23.107 に答える