在我的unary_op.operator
中,我需要创建一个临时数组
我想cudaMalloc
是要走的路
但是,它是否具有性能效率还是有更好的设计?
struct my_unary_op
{
__host__ __device__ int operator()(const int& index) const
{
int* array;
cudaMalloc((void**)&array, 10*sizeof(int));
for(int i = 0; i < 10; i++)
array[i] = index;
int sum=0;
for(int i=0; i < 10 ; i++)
sum += array[i];
return sum;
};
};
int main()
{
thrust::counting_iterator<int> first(0);
thrust::counting_iterator<int> last = first+100;
my_unary_op unary_op = my_unary_op();
thrust::plus<int> binary_op;
int init = 0;
int sum = thrust::transform_reduce(first, last, unary_op, init, binary_op);
return 0;
};
答案 0 :(得分:2)
您将无法在cudaMalloc()
函数中编译__device__
,因为它是仅限主机的函数。但是,您可以使用普通malloc()
或new
(在计算能力&gt; = 2.0的设备上),但这些在设备上运行时效率不高。有两个原因。第一个是在内存分配调用期间并发运行的线程被序列化。第二个是调用以块的方式分配全局内存,这些块以这样的方式排列:当warp中的32个线程运行内存加载和存储指令时,它们不相邻,因此你没有得到正确的合并内存访问。
您可以在__device__
函数中使用固定大小的C样式数组(即int array[10];
)来解决这两个问题。小型固定大小的数组有时可以通过编译器进行优化,以便将它们存储在寄存器文件中,以实现极快的访问速度。如果编译器将它们存储在全局内存中,它将使用本地内存。本地内存存储在全局内存中,但它以交错方式交错,当warp中的32个线程运行加载或存储指令时,每个线程访问内存中的相邻位置,使事务完全合并。
如果您在运行时不知道C数组的大小是多少,请在数组中分配一个最大大小并保留一些未使用的大小。
我认为固定大小的数组使用的内存总量将取决于GPU上并发处理的线程总数,而不是内核启动的线程总数。在this answer @mharris中显示了如何计算最大可能的并发线程数,对于GTX580来说是24,576。因此,如果固定大小的数组是16个32位值,则阵列使用的最大内存量为1536KiB。
如果需要多种数组大小,可以使用模板编译具有多种不同大小的内核。然后,在运行时,选择一个能够容纳您需要的大小。但是,如果您只是简单地分配可能需要的最大值,则内存使用率可能不会是您可以启动的线程数量的限制因素。