在全球范围内拥有 thrust::device_vector
Having thrust::device_vector in global scope
我正在编写一个程序来计算三角形网格数据的许多属性。其中一些属性,我想使用 thrust:: 方法来计算,其他属性需要使用 CUDA 内核中的原始内存指针来计算。
为了将数据传输到 GPU,我在 transfer.cu 文件中得到了这个,(自从在普通 C++ 中创建和操作 thrust::device_vector
s不支持代码):
// thrust vectors (global)
thrust::host_vector<glm::vec3> trianglethrust_host;
thrust::device_vector<glm::vec3> trianglethrust_device;
extern "C" void trianglesToGPU_thrust(const trimesh::TriMesh *mesh, float** triangles) {
// fill host vector
for (size_t i = 0; i < mesh->faces.size(); i++) {
// PUSHING DATA INTO HOST_VECTOR HERE (OMITTED FOR CLARITY)
}
// copy to GPU by assigning host vector to device vector, like in the Thrust documentation
trianglethrust_device = trianglethrust_host;
// save raw pointer
*triangles = (float*)thrust::raw_pointer_cast(&(trianglethrust_device[0]));
}
此函数trianglestoGPU_thrust
是从我的 C++ 程序的主要方法中调用的。
一切正常,花花公子,直到程序退出,并且(全局定义的)trianglethrust_device 向量超出范围。 Thrust 试图释放它,但 CUDA 上下文已经消失,导致 cudaErrorInvalidDevicePointer
对于我的问题,什么是最佳实践?
TL;DR: 我想要一个 thrust::device_vector 在我的程序运行期间一直存在,因为我也想向它添加 thrust:: 函数(如转换等)通过 CUDA 中的原始指针访问读取和操作它。
解法:
就我而言,我显然是在过程中进一步使用原始数据指针进行释放。删除那个免费的,并用
结束我的主循环
trianglethrust_device.clear();
trianglethrust_device.shrink_to_fit();
trianglethrust_device.device_vector~;
在 CUDA 运行时被拆除之前强制清除该向量。这行得通,但可能仍然是一种非常丑陋的方法。
我推荐罗伯特的回答,并将其标记为有效。
正如您已经发现的,推力矢量容器本身不能放置在文件范围内。
一个可能的解决方案是在 main
的开头简单地创建您需要的向量,然后将对这些向量的引用传递给任何需要它们的函数。
如果你真的想要 "global behavior" 你可以在 global/file 范围内放置指向向量的指针,然后在 main 的开头初始化所需的向量,并将全局范围内的指针设置为指向在 main.
中创建的向量
根据评论中的问题,我猜 important/desirable 主文件是用主机编译器编译的 .cpp
文件。因此,我们可以将前面提到的概念与堆上的向量分配结合使用,以避免在程序终止之前重新分配。这是一个完整的例子:
$ cat main.cpp
#include "transfer.h"
int main(){
float **triangles, *mesh;
triangles = new float *[1];
mesh = new float[4];
mesh[0] = 0.1f; mesh[1] = 0.2f; mesh[2] = 0.3f;
trianglesToGPU_thrust(mesh, triangles);
do_global_work(triangles);
finish();
}
$ cat transfer.h
void trianglesToGPU_thrust(const float *, float **);
void do_global_work(float **);
void finish();
$ cat transfer.cu
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include "transfer.h"
#include <iostream>
#include <cstdio>
#include <thrust/copy.h>
__global__ void k(float *data, size_t ds){
for (int i = 0; i < ds; i++) printf("%f,", data[i]);
}
// thrust vectors (global)
thrust::host_vector<float> *trianglethrust_host;
thrust::device_vector<float> *trianglethrust_device;
void trianglesToGPU_thrust(const float *mesh, float** triangles) {
//create vectors
trianglethrust_host = new thrust::host_vector<float>;
trianglethrust_device = new thrust::device_vector<float>;
// fill host vector
size_t i = 0;
while (mesh[i] != 0.0f) {
(*trianglethrust_host).push_back(mesh[i++]);
}
// copy to GPU by assigning host vector to device vector, like in the Thrust documentation
*trianglethrust_device = *trianglethrust_host;
// save raw pointer
*triangles = (float*)thrust::raw_pointer_cast(&((*trianglethrust_device)[0]));
}
void do_global_work(float** triangles){
std::cout << "from device vector:" << std::endl;
thrust::copy((*trianglethrust_device).begin(), (*trianglethrust_device).end(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl << "from kernel:" << std::endl;
k<<<1,1>>>(*triangles, (*trianglethrust_device).size());
cudaDeviceSynchronize();
std::cout << std::endl;
}
void finish(){
if (trianglethrust_host) delete trianglethrust_host;
if (trianglethrust_device) delete trianglethrust_device;
}
$ nvcc -c transfer.cu
$ g++ -c main.cpp
$ g++ -o test main.o transfer.o -L/usr/local/cuda/lib64 -lcudart
$ ./test
from device vector:
0.1,0.2,0.3,
from kernel:
0.100000,0.200000,0.300000,
$
这是另一种方法,类似于之前的方法,在全局范围内使用 std::vector
个推力容器(只有 transfer.cu
文件与前面的示例不同,main.cpp
和transfer.h
相同):
$ cat transfer.cu
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include "transfer.h"
#include <iostream>
#include <cstdio>
#include <thrust/copy.h>
#include <vector>
__global__ void k(float *data, size_t ds){
for (int i = 0; i < ds; i++) printf("%f,", data[i]);
}
// thrust vectors (global)
std::vector<thrust::host_vector<float> > trianglethrust_host;
std::vector<thrust::device_vector<float> > trianglethrust_device;
void trianglesToGPU_thrust(const float *mesh, float** triangles) {
//create vectors
trianglethrust_host.resize(1);
trianglethrust_device.resize(1);
// fill host vector
size_t i = 0;
while (mesh[i] != 0.0f) {
trianglethrust_host[0].push_back(mesh[i++]);
}
// copy to GPU by assigning host vector to device vector, like in the Thrust documentation
trianglethrust_device[0] = trianglethrust_host[0];
// save raw pointer
*triangles = (float*)thrust::raw_pointer_cast(trianglethrust_device[0].data());
}
void do_global_work(float** triangles){
std::cout << "from device vector:" << std::endl;
thrust::copy(trianglethrust_device[0].begin(), trianglethrust_device[0].end(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl << "from kernel:" << std::endl;
k<<<1,1>>>(*triangles, trianglethrust_device[0].size());
cudaDeviceSynchronize();
std::cout << std::endl;
}
void finish(){
trianglethrust_host.clear();
trianglethrust_device.clear();
}
$ nvcc -c transfer.cu
$ g++ -o test main.o transfer.o -L/usr/local/cuda/lib64 -lcudart
$ ./test
from device vector:
0.1,0.2,0.3,
from kernel:
0.100000,0.200000,0.300000,
$
我正在编写一个程序来计算三角形网格数据的许多属性。其中一些属性,我想使用 thrust:: 方法来计算,其他属性需要使用 CUDA 内核中的原始内存指针来计算。
为了将数据传输到 GPU,我在 transfer.cu 文件中得到了这个,(自从在普通 C++ 中创建和操作 thrust::device_vector
s不支持代码):
// thrust vectors (global)
thrust::host_vector<glm::vec3> trianglethrust_host;
thrust::device_vector<glm::vec3> trianglethrust_device;
extern "C" void trianglesToGPU_thrust(const trimesh::TriMesh *mesh, float** triangles) {
// fill host vector
for (size_t i = 0; i < mesh->faces.size(); i++) {
// PUSHING DATA INTO HOST_VECTOR HERE (OMITTED FOR CLARITY)
}
// copy to GPU by assigning host vector to device vector, like in the Thrust documentation
trianglethrust_device = trianglethrust_host;
// save raw pointer
*triangles = (float*)thrust::raw_pointer_cast(&(trianglethrust_device[0]));
}
此函数trianglestoGPU_thrust
是从我的 C++ 程序的主要方法中调用的。
一切正常,花花公子,直到程序退出,并且(全局定义的)trianglethrust_device 向量超出范围。 Thrust 试图释放它,但 CUDA 上下文已经消失,导致 cudaErrorInvalidDevicePointer
对于我的问题,什么是最佳实践?
TL;DR: 我想要一个 thrust::device_vector 在我的程序运行期间一直存在,因为我也想向它添加 thrust:: 函数(如转换等)通过 CUDA 中的原始指针访问读取和操作它。
解法: 就我而言,我显然是在过程中进一步使用原始数据指针进行释放。删除那个免费的,并用
结束我的主循环trianglethrust_device.clear();
trianglethrust_device.shrink_to_fit();
trianglethrust_device.device_vector~;
在 CUDA 运行时被拆除之前强制清除该向量。这行得通,但可能仍然是一种非常丑陋的方法。
我推荐罗伯特的回答,并将其标记为有效。
正如您已经发现的,推力矢量容器本身不能放置在文件范围内。
一个可能的解决方案是在 main
的开头简单地创建您需要的向量,然后将对这些向量的引用传递给任何需要它们的函数。
如果你真的想要 "global behavior" 你可以在 global/file 范围内放置指向向量的指针,然后在 main 的开头初始化所需的向量,并将全局范围内的指针设置为指向在 main.
中创建的向量根据评论中的问题,我猜 important/desirable 主文件是用主机编译器编译的 .cpp
文件。因此,我们可以将前面提到的概念与堆上的向量分配结合使用,以避免在程序终止之前重新分配。这是一个完整的例子:
$ cat main.cpp
#include "transfer.h"
int main(){
float **triangles, *mesh;
triangles = new float *[1];
mesh = new float[4];
mesh[0] = 0.1f; mesh[1] = 0.2f; mesh[2] = 0.3f;
trianglesToGPU_thrust(mesh, triangles);
do_global_work(triangles);
finish();
}
$ cat transfer.h
void trianglesToGPU_thrust(const float *, float **);
void do_global_work(float **);
void finish();
$ cat transfer.cu
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include "transfer.h"
#include <iostream>
#include <cstdio>
#include <thrust/copy.h>
__global__ void k(float *data, size_t ds){
for (int i = 0; i < ds; i++) printf("%f,", data[i]);
}
// thrust vectors (global)
thrust::host_vector<float> *trianglethrust_host;
thrust::device_vector<float> *trianglethrust_device;
void trianglesToGPU_thrust(const float *mesh, float** triangles) {
//create vectors
trianglethrust_host = new thrust::host_vector<float>;
trianglethrust_device = new thrust::device_vector<float>;
// fill host vector
size_t i = 0;
while (mesh[i] != 0.0f) {
(*trianglethrust_host).push_back(mesh[i++]);
}
// copy to GPU by assigning host vector to device vector, like in the Thrust documentation
*trianglethrust_device = *trianglethrust_host;
// save raw pointer
*triangles = (float*)thrust::raw_pointer_cast(&((*trianglethrust_device)[0]));
}
void do_global_work(float** triangles){
std::cout << "from device vector:" << std::endl;
thrust::copy((*trianglethrust_device).begin(), (*trianglethrust_device).end(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl << "from kernel:" << std::endl;
k<<<1,1>>>(*triangles, (*trianglethrust_device).size());
cudaDeviceSynchronize();
std::cout << std::endl;
}
void finish(){
if (trianglethrust_host) delete trianglethrust_host;
if (trianglethrust_device) delete trianglethrust_device;
}
$ nvcc -c transfer.cu
$ g++ -c main.cpp
$ g++ -o test main.o transfer.o -L/usr/local/cuda/lib64 -lcudart
$ ./test
from device vector:
0.1,0.2,0.3,
from kernel:
0.100000,0.200000,0.300000,
$
这是另一种方法,类似于之前的方法,在全局范围内使用 std::vector
个推力容器(只有 transfer.cu
文件与前面的示例不同,main.cpp
和transfer.h
相同):
$ cat transfer.cu
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include "transfer.h"
#include <iostream>
#include <cstdio>
#include <thrust/copy.h>
#include <vector>
__global__ void k(float *data, size_t ds){
for (int i = 0; i < ds; i++) printf("%f,", data[i]);
}
// thrust vectors (global)
std::vector<thrust::host_vector<float> > trianglethrust_host;
std::vector<thrust::device_vector<float> > trianglethrust_device;
void trianglesToGPU_thrust(const float *mesh, float** triangles) {
//create vectors
trianglethrust_host.resize(1);
trianglethrust_device.resize(1);
// fill host vector
size_t i = 0;
while (mesh[i] != 0.0f) {
trianglethrust_host[0].push_back(mesh[i++]);
}
// copy to GPU by assigning host vector to device vector, like in the Thrust documentation
trianglethrust_device[0] = trianglethrust_host[0];
// save raw pointer
*triangles = (float*)thrust::raw_pointer_cast(trianglethrust_device[0].data());
}
void do_global_work(float** triangles){
std::cout << "from device vector:" << std::endl;
thrust::copy(trianglethrust_device[0].begin(), trianglethrust_device[0].end(), std::ostream_iterator<float>(std::cout, ","));
std::cout << std::endl << "from kernel:" << std::endl;
k<<<1,1>>>(*triangles, trianglethrust_device[0].size());
cudaDeviceSynchronize();
std::cout << std::endl;
}
void finish(){
trianglethrust_host.clear();
trianglethrust_device.clear();
}
$ nvcc -c transfer.cu
$ g++ -o test main.o transfer.o -L/usr/local/cuda/lib64 -lcudart
$ ./test
from device vector:
0.1,0.2,0.3,
from kernel:
0.100000,0.200000,0.300000,
$