我正在尝试将cuda后端添加到20k loc c ++表达式模板库中。到目前为止,它运行良好,但是我完全被虚假的“警告:不允许从__host__
函数调用__host__ __device__
函数”警告所淹没。
大多数代码可以总结如下:
template<class Impl>
struct Wrapper{
Impl impl;
// lots and lots of decorator code
__host__ __device__ void call(){ impl.call();};
};
//Guaranteed to never ever be used on gpu.
struct ImplCPU{
void call();
};
//Guaranteed to never ever be used on cpu.
struct ImplGPU{
__host__ __device__ void call();//Actually only __device__, but needed to shut up the compiler as well
};
Wrapper<ImplCPU> wrapCPU;
Wrapper<ImplGPU> wrapGPU;
在所有情况下,包装器中的call()都是微不足道的,而包装器本身是相当复杂的野兽(仅包含元信息的主机函数)。 条件编译不是一种选择,两条路径都打算并排使用。
我离“ --disable-warnings”仅一步之遥,因为老实说,复制和维护1万个可怕的模板魔术的成本超过了警告的好处。
根据实现是针对gpu还是cpu的使用,有条件地使呼叫成为设备或主机的一种方式,我将感到非常高兴(因为Impl知道它是什么) )
只是为了证明它是不好的。一个警告:
/home/user/Remora/include/remora/detail/matrix_expression_classes.hpp(859): warning: calling a __host__ function from a __host__ __device__ function is not allowed
detected during:
instantiation of "remora::matrix_matrix_prod<MatA, MatB>::size_type remora::matrix_matrix_prod<MatA, MatB>::size1() const [with MatA=remora::dense_triangular_proxy<const float, remora::row_major, remora::lower, remora::hip_tag>, MatB=remora::matrix<float, remora::column_major, remora::hip_tag>]"
/home/user/Remora/include/remora/cpu/../assignment.hpp(258): here
instantiation of "MatA &remora::assign(remora::matrix_expression<MatA, Device> &, const remora::matrix_expression<MatB, Device> &) [with MatA=remora::dense_matrix_adaptor<float, remora::row_major, remora::continuous_dense_tag, remora::hip_tag>, MatB=remora::matrix_matrix_prod<remora::dense_triangular_proxy<const float, remora::row_major, remora::lower, remora::hip_tag>, remora::matrix<float, remora::column_major, remora::hip_tag>>, Device=remora::hip_tag]"
/home/user/Remora/include/remora/cpu/../assignment.hpp(646): here
instantiation of "remora::noalias_proxy<C>::closure_type &remora::noalias_proxy<C>::operator=(const E &) [with C=remora::matrix<float, remora::row_major, remora::hip_tag>, E=remora::matrix_matrix_prod<remora::dense_triangular_proxy<const float, remora::row_major, remora::lower, remora::hip_tag>, remora::matrix<float, remora::column_major, remora::hip_tag>>]"
/home/user/Remora/Test/hip_triangular_prod.cpp(325): here
instantiation of "void Remora_hip_triangular_prod::triangular_prod_matrix_matrix_test(Orientation) [with Orientation=remora::row_major]"
/home/user/Remora/Test/hip_triangular_prod.cpp(527): here
答案 0 :(得分:1)
很抱歉,您在滥用语言并误导读者。包装器类具有__host__ __device__
方法是不正确的。您的意思是说它具有 一种__host__
方法或一种__device__
方法。您应该将警告视为错误。
因此,您不能仅将示例模板实例化用于ImplCPU
和ImplGPU
;但是-您可以这样做吗?
template<typename Impl> struct Wrapper;
template<> struct Wrapper<ImplGPU> {
ImplGPU impl;
__device__ void call(){ impl.call();};
}
template<> struct Wrapper<ImplCPU> {
ImplGPU impl;
__host__ void call(){ impl.call();};
}
或者如果您想变得更加学究,可以是:
enum implementation_device { CPU, GPU };
template<implementation_device ImplementationDevice> Wrapper;
template<> Wrapper<CPU> {
__host__ void call();
}
template<> Wrapper<GPU> {
__device__ void call();
}
已经说过-您期望使用单个Wrapper类,在这里我告诉您您不能这样做。我怀疑您的问题提出了X-Y problem,您应该真正考虑使用该包装程序的整个方法。也许您需要针对CPU或GPU使用不同模板的代码。也许您需要在某个地方进行类型擦除。但这不会。
答案 1 :(得分:0)
与此同时,我提出的解决方案是,用更少的代码重复来用函数级替换调用:
template<class Impl, class Device>
struct WrapperImpl;
template<class Impl>
struct WrapperImpl<Impl, CPU>{
typename Impl::Functor f;
__host__ operator()(){ f();}
};
//identical to CPU up to __device__
template<class Impl>
struct WrapperImpl<Impl, GPU>{
typename Impl::Functor f;
__device__ operator()(){ f();}
};
template<class Impl>
struct Wrapper{
typedef WrapperImpl<Impl, typename Impl::Device> Functor;
Impl impl;
// lots and lots of decorator code that i now do not need to duplicate
Functor call_functor()const{
return Functor{impl.call_functor();};
}
};
//repeat for around 20 classes
Wrapper<ImplCPU> wrapCPU;
wrapCPU.call_functor()();
答案 2 :(得分:0)
这个问题实际上是CUDA语言扩展中非常不幸的缺陷。
处理这些警告的标准方法(在Thrust和类似的CUDA库模板中)是通过使用#pragma hd_warning_disable
或在较新的CUDA(9.0或更高版本)中禁用导致警告的函数/方法{ {1}}。
因此,您的情况应该是:
#pragma nv_exec_check_disable