2013-01-16 32 views
2

我编写的代码可以在GPU或CPU上运行。在CUDA存在封装的情况下尝试在GPU上运行功能。如果发生错误(例如无内存),则尝试在CPU上运行它。如果再次出现错误,则返回0,否则返回1. 如果CUDA退出包装只尝试在CPU上运行功能。有没有办法分割gcc宏参数?

这里是我的宏:

#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这个宏分裂参数组成FNSTRIP?即缩短以上定义为

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

+0

我希望你会使用这个宏更多的功能,那么你贴一个。他们都会有两个参数吗? – alk

+0

会有很多功能和参数的数量因功能而异。他们唯一常见的事情是他们返回int。 –

+0

Boost预处理器库可能可以做到这一点。 –

回答

1

您不能将预处理符号与预处理器分开,只能合并它们。这意味着“fillrandarr(sz,arr)”是预处理器的一个原子单位,因此不符合您的需求。你将不得不通过在参数列表分隔符号,就像

#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) 
+0

嘿嘿,那是第一步。你确定剩下的步骤可能吗? – Potatoswatter

+0

我想过了,但我想不出如何解析可变参数,以至于在一种情况下它们是成对的组,而在其他情况下,它们只有奇数。 –

1

你可以宣布你身边已经有了一个包装宏变量量对于使用不同数量的参数功能:

#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); 

这种方法肯定会针对较少冗余进行优化,使用slartibartfast计数#define的参数个数的建议。

+0

这是一个非常庞大的结构。还有一些我的功能有多达5-7个参数!但想法很好。谢谢。顺便说一句,在宏SET_F_X中写变量名是没有用的:它们可以由它自己设置。 –

+0

我做到了!代码在编辑后。 –

4

至于中午。在他的评论中写道:

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. 作为可变参数宏显然零个参数和一个单一的空参数不能区分,第一个宏总是包括函数名必须转向一个可变参数成更容易处理的数据结构,在这种情况下是一系列带括号的表达式。
  2. 接下来我们将该序列分成函数名和参数类型。
  3. 我们将参数类型序列转换为两个序列,一个用于函数定义,另一个用于函数调用。
  4. 对于函数定义,我们为每个参数名称加上其类型。
  5. 对于函数调用,我们忽略了类型并简单地编写了编号的参数名称。
  6. 接下来我们要确保我们正确处理空序列。对于调用,我们可以简单地写(),但是对于函数定义,我们必须改写(void)
  7. 所以我们检查序列是否有非零大小。如果是这样,我们将它转​​换为一个元组,即元素周围的括号和逗号之间的逗号。否则,我们使用提供的默认值。
  8. 现在我们按照您的要求组合一切。
+0

这很有趣。但我有几个问题:1)这将工作,例如使用gcc-none-eaby? 2)是否有关于boost预处理器指令的简短手册? –

+0

@Eddy_Em:我不知道你的意思是“gcc-none-eaby”。请解释一下。一般而言,boost通过各种常用编译器进行了高度可移植性,并且头文件包含许多用于区分编译器特定异常的案例区分。所以使用boost可能会比直接实现更具可移植性。例如,参见[variadic argument counting](http://tinyurl.com/akpoqph)中有关MSVC的特例。有关手册,请参阅[文档](http://tinyurl.com/ajccant),尤其是参考文献。 – MvG

+0

我指的是非x86处理器的编译器。 –

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) 
相关问题