调用 Cuda/推力中所有组合的函子
Call functor for all combinations in Cuda/Thrust
我有两个索引集,一个在 [0, N] 范围内,一个在 [0, M] 范围内,其中 N != M。索引用于引用不同thrust::device_vector
中的值。
本质上,我想为这些索引的每个组合创建一个 GPU 线程,因此 N*M 个线程。每个线程应该根据索引组合计算一个值,并将结果存储在另一个thrust::device_vector
中,在同样基于输入组合的唯一索引处。
这似乎是一个相当标准的问题,但我无法找到一种方法来做到这一点。文档只提到问题,其中向量的元素 i 需要使用另一个向量的元素 i 计算某些内容。有thrust::permutation_iterator
,但据我了解,它只给了我重新排序数据的选项,我还必须指定顺序。
一些代码:
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <iostream>
int main()
{
// Initialize some data
const int N = 2;
const int M = 3;
thrust::host_vector<int> vec1_host(N);
thrust::host_vector<int> vec2_host(M);
vec1_host[0] = 1;
vec1_host[1] = 5;
vec2_host[0] = -3;
vec2_host[1] = 42;
vec2_host[2] = 9;
// Copy to device
thrust::device_vector<int> vec1_dev = vec1_host;
thrust::device_vector<int> vec2_dev = vec2_host;
// Allocate device memory to copy results to
thrust::device_vector<int> result_dev(vec1_host.size() * vec2_host.size());
// Create functor I want to call on every combination
struct myFunctor
{
thrust::device_vector<int> const& m_vec1;
thrust::device_vector<int> const& m_vec2;
thrust::device_vector<int>& m_result;
myFunctor(thrust::device_vector<int> const& vec1, thrust::device_vector<int> const& vec2, thrust::device_vector<int>& result)
: m_vec1(vec1), m_vec2(vec2), m_result(result)
{
}
__host__ __device__
void operator()(size_t i, size_t j) const
{
m_result[i + j * m_vec1.size()] = m_vec1[i] + m_vec1[j];
}
} func(vec1_dev, vec2_dev, result_dev);
// How do I create N*M threads, each of which calls func(i, j) ?
// Copy results back
thrust::host_vector<int> result_host = result_dev;
for(int i : result_host)
std::cout << i << ", ";
std::cout << std::endl;
// Expected output:
// -2, 2, 43, 47, 10, 14
return 0;
}
我很确定这很容易实现,我想我只是错过了正确的搜索词。无论如何,所有的帮助都表示赞赏:)
-
大概在你的函子运算符中,而不是这个:
m_result[i + j * m_vec1.size()] = m_vec1[i] + m_vec1[j]; ^ ^
你的意思是:
m_result[i + j * m_vec1.size()] = m_vec1[i] + m_vec2[j]; ^ ^
-
我认为可能有很多方法可以解决这个问题,但为了不争论与问题无关的事情,我会尽量接近你给定的代码。
在 设备代码中无法对向量执行
[]
等操作。 因此,我们必须将您的函子转换为处理原始数据指针,而不是直接推力向量操作。
有了这些警告,以及我们如何处理您的i
和j
指数的轻微修改,我认为您的要求并不困难。
基本策略是创建一个长度N*M
的结果向量,就像您建议的那样,然后在函子运算符中创建索引i
和j
。 在这样做时,我们只需要将一个索引传递给函子,例如使用thrust::transform
或thrust::for_each
来创建我们的输出:
$ cat t79.cu
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/for_each.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/execution_policy.h>
#include <iostream>
struct myFunctor
{
const int *m_vec1;
const int *m_vec2;
int *m_result;
size_t v1size;
myFunctor(thrust::device_vector<int> const& vec1, thrust::device_vector<int> const& vec2, thrust::device_vector<int>& result)
{
m_vec1 = thrust::raw_pointer_cast(vec1.data());
m_vec2 = thrust::raw_pointer_cast(vec2.data());
m_result = thrust::raw_pointer_cast(result.data());
v1size = vec1.size();
}
__host__ __device__
void operator()(const size_t x) const
{
size_t i = x%v1size;
size_t j = x/v1size;
m_result[i + j * v1size] = m_vec1[i] + m_vec2[j];
}
};
int main()
{
// Initialize some data
const int N = 2;
const int M = 3;
thrust::host_vector<int> vec1_host(N);
thrust::host_vector<int> vec2_host(M);
vec1_host[0] = 1;
vec1_host[1] = 5;
vec2_host[0] = -3;
vec2_host[1] = 42;
vec2_host[2] = 9;
// Copy to device
thrust::device_vector<int> vec1_dev = vec1_host;
thrust::device_vector<int> vec2_dev = vec2_host;
// Allocate device memory to copy results to
thrust::device_vector<int> result_dev(vec1_host.size() * vec2_host.size());
// How do I create N*M threads, each of which calls func(i, j) ?
thrust::for_each_n(thrust::device, thrust::counting_iterator<size_t>(0), (N*M), myFunctor(vec1_dev, vec2_dev, result_dev));
// Copy results back
thrust::host_vector<int> result_host = result_dev;
for(int i : result_host)
std::cout << i << ", ";
std::cout << std::endl;
// Expected output:
// -2, 2, 43, 47, 10, 14
return 0;
}
$ nvcc -std=c++11 -arch=sm_61 -o t79 t79.cu
$ ./t79
-2, 2, 43, 47, 10, 14,
$
回想起来,我认为这或多或少正是@eg0x20所建议的。
相关文章:
- 编译时未启用intel oneApi CUDA支持
- 如何在OMNET++中指定与命令行参数组合的输出文件名
- 可组合的lambda/std::函数与std::可选
- 在cuda线程之间共享大量常量数据
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 为什么即使使用-cudart-static进行编译,库用户仍然需要链接到cuda运行时
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- 混合组合和继承的C++问题
- 我需要将多个函数组合为一个函数
- 构建可组合有向图(扫描仪生成器的汤普森构造算法)
- CUDA内核和数学函数的显式命名空间
- 通过组合不同的类型来创建唯一的id
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 模板元编程:如何将参数包组合成新的参数包
- CUDA:统一内存和指针地址的更改
- 检查向量是否具有所有可能的字符组合
- CUDA 9 和 GCC4.3 的组合编译C++软件
- 调用 Cuda/推力中所有组合的函子
- 我什么时候应该首选写入组合 CUDA 分配的映射主机内存
- CUDA:内存限定符的非法组合