如何在 Cuda 设备函数中使用 C++11 中的闭包参数声明函数?
How to declare function with argument that is a closure in C++11 in a Cuda device function?
我正在使用 C++11 开发 Cuda(我认为 Cuda 还不支持更高的 C++ 版本)。我有一个传递给函数 Process()
的闭包对象,它为每次迭代调用闭包。
我了解 std::
功能在 Cuda 中通常不可用。例如,当我尝试使用 std::function< float(uint32_t) >
时,出现此错误:
error: calling a host function("std::function ::function< ::, void, void> ") from a global function("_NV_ANON_NAMESPACE::LargeKernel") is not allowed
我可以用什么替换 lookupFunc
以便在 std::function
不可用的情况下进行编译?我能够通过创建一个函数模板来推断 lambda 函数的类型来解决这个问题。
此代码有效并显示了我所采用的工作:
//using lookupFunc = std::function< float(uint32_t) >;
template< typename Lambda > // Work around with function template
__device__
void Process(float * const outData,
const int32_t locationX,
const Lambda /* lookupFunc */ lambda)
{
float answer = 0.f;
for( int32_t offset = -1 ; ++offset < 1024 ; )
{
const float value = lambda( offset );
answer += value;
}
outData[ locationX ] = answer;
}
__global__
void LargeKernel(const float * const inData,
float * const outData)
{
constexpr uint32_t cellStride = 1;
const int32_t locationX = threadIdx.x + blockDim.x * blockIdx.x;
const auto lambda
= [locationX, inData, cellStride](const int32_t offset)
{
return inData[ locationX + offset + cellStride ];
};
Process( outData, locationX, lambda );
}
我也试过:
using lookupFunc = float(* const)(uint32_t);
但这给出了错误:
error: no suitable conversion function from "const lambda ->float" to "float (*)(uint32_t)" exists
如何在不使用模板的情况下声明 Process()
的第三个参数的类型?
有必要使用 lambda 吗?
否则,你可以模拟它声明一个struct
struct noLambda
{
std::int32_t const locationX;
float const * const inData;
std::uint32_t const cellStride;
noLambda (std::int32_t l0, float const * const i0, std::uint32_t c0)
: locationX{l0}, inData{i0}, cellStride{c0}
{ }
float operator() (std::int32_t const offset) const
{ return inData[ locationX + offset + cellStride ]; }
};
所以进程的签名变成
void Process(float * const outData,
const int32_t locationX,
const noLambda lambda)
并且可以如下调用
Process( outData, locationX, noLambda{locationX, inData, cellStride} );
(注意:代码未经测试)
相当于 std::function
的 CUDA 是 nvstd::function
。
从 CUDA 8.0 开始,nvstd::function
可用于主机和设备代码 - 但 "instances cannot be passed from host code to device code (and vice versa) at run time"。
CUDA programming guide.
中解释了它的使用
我正在使用 C++11 开发 Cuda(我认为 Cuda 还不支持更高的 C++ 版本)。我有一个传递给函数 Process()
的闭包对象,它为每次迭代调用闭包。
我了解 std::
功能在 Cuda 中通常不可用。例如,当我尝试使用 std::function< float(uint32_t) >
时,出现此错误:
error: calling a host function("std::function ::function< ::, void, void> ") from a global function("_NV_ANON_NAMESPACE::LargeKernel") is not allowed
我可以用什么替换 lookupFunc
以便在 std::function
不可用的情况下进行编译?我能够通过创建一个函数模板来推断 lambda 函数的类型来解决这个问题。
此代码有效并显示了我所采用的工作:
//using lookupFunc = std::function< float(uint32_t) >;
template< typename Lambda > // Work around with function template
__device__
void Process(float * const outData,
const int32_t locationX,
const Lambda /* lookupFunc */ lambda)
{
float answer = 0.f;
for( int32_t offset = -1 ; ++offset < 1024 ; )
{
const float value = lambda( offset );
answer += value;
}
outData[ locationX ] = answer;
}
__global__
void LargeKernel(const float * const inData,
float * const outData)
{
constexpr uint32_t cellStride = 1;
const int32_t locationX = threadIdx.x + blockDim.x * blockIdx.x;
const auto lambda
= [locationX, inData, cellStride](const int32_t offset)
{
return inData[ locationX + offset + cellStride ];
};
Process( outData, locationX, lambda );
}
我也试过:
using lookupFunc = float(* const)(uint32_t);
但这给出了错误:
error: no suitable conversion function from "const lambda ->float" to "float (*)(uint32_t)" exists
如何在不使用模板的情况下声明 Process()
的第三个参数的类型?
有必要使用 lambda 吗?
否则,你可以模拟它声明一个struct
struct noLambda
{
std::int32_t const locationX;
float const * const inData;
std::uint32_t const cellStride;
noLambda (std::int32_t l0, float const * const i0, std::uint32_t c0)
: locationX{l0}, inData{i0}, cellStride{c0}
{ }
float operator() (std::int32_t const offset) const
{ return inData[ locationX + offset + cellStride ]; }
};
所以进程的签名变成
void Process(float * const outData,
const int32_t locationX,
const noLambda lambda)
并且可以如下调用
Process( outData, locationX, noLambda{locationX, inData, cellStride} );
(注意:代码未经测试)
相当于 std::function
的 CUDA 是 nvstd::function
。
从 CUDA 8.0 开始,nvstd::function
可用于主机和设备代码 - 但 "instances cannot be passed from host code to device code (and vice versa) at run time"。
CUDA programming guide.