Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
CUDA扩展std::vector以管理主机和设备数据 我了解到STD::vector是C++中的原始数组的一个很好的包装,所以我开始使用它来管理我的CUDA应用程序中的主机数据[1 ]。由于必须手动分配和复制东西,使得代码更加复杂,可读性较差,因此我考虑扩展std::vector。因为我不是很有经验,我想知道你对它的看法。特别是天气正确的时候(例如:STD的析构函数::vector被隐式调用,对吗?),如果你认为它是个好主意。_C++_Stl_Cuda_Software Design - Fatal编程技术网

CUDA扩展std::vector以管理主机和设备数据 我了解到STD::vector是C++中的原始数组的一个很好的包装,所以我开始使用它来管理我的CUDA应用程序中的主机数据[1 ]。由于必须手动分配和复制东西,使得代码更加复杂,可读性较差,因此我考虑扩展std::vector。因为我不是很有经验,我想知道你对它的看法。特别是天气正确的时候(例如:STD的析构函数::vector被隐式调用,对吗?),如果你认为它是个好主意。

CUDA扩展std::vector以管理主机和设备数据 我了解到STD::vector是C++中的原始数组的一个很好的包装,所以我开始使用它来管理我的CUDA应用程序中的主机数据[1 ]。由于必须手动分配和复制东西,使得代码更加复杂,可读性较差,因此我考虑扩展std::vector。因为我不是很有经验,我想知道你对它的看法。特别是天气正确的时候(例如:STD的析构函数::vector被隐式调用,对吗?),如果你认为它是个好主意。,c++,stl,cuda,software-design,C++,Stl,Cuda,Software Design,我写了一个小例子来说明这一点 #include <vector> #include <cuda.h> #include <cstdio> void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); if( cudaSuccess != err) { fprintf(stderr, "Cuda error: %s: %s.\n", m

我写了一个小例子来说明这一点

#include <vector>
#include <cuda.h>

#include <cstdio>

void checkCUDAError(const char *msg)
{
    cudaError_t err = cudaGetLastError();
    if( cudaSuccess != err) {
        fprintf(stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString(err));
        exit(EXIT_FAILURE);
    }
}

// Wrapper around CUDA memory
template<class T>
class UniversalVector: public std::vector<T>
{
    T* devicePtr_;
    bool allocated;

public:

    // Constructor
    UniversalVector(unsigned int length)
        :std::vector<T>(length), 
         allocated(false)
    {}

    // Destructor
    ~UniversalVector()
     {
        if(allocated)
            cudaFree(devicePtr_);
     }

    cudaError_t allocateDevice()
    {
        if(allocated) free(devicePtr_);
        cudaError_t err = 
            cudaMalloc((void**)&devicePtr_, sizeof(T) * this->size());
        allocated = true;
        return err;
    }

    cudaError_t loadToDevice()
    {
        return cudaMemcpy(devicePtr_, &(*this)[0], sizeof(T) * this->size(),
            cudaMemcpyHostToDevice);
    }

    cudaError_t loadFromDevice()
    {
        return cudaMemcpy(&(*this)[0], devicePtr_, sizeof(T) * this->size(),
            cudaMemcpyDeviceToHost);
    }

    // Accessors

    inline T* devicePtr() {
        return devicePtr_;
    }

};

__global__ void kernel(int* a)
{
    int i = threadIdx.x;
    printf("%i\n", a[i]);
}

int main()
{
    UniversalVector<int> vec(3);
    vec.at(0) = 1;
    vec.at(1) = 2;
    vec.at(2) = 3;

    vec.allocateDevice();
    vec.loadToDevice();

    kernel<<<1, 3>>>(vec.devicePtr());

    checkCUDAError("Error when doing something");

    return 0;
}
#包括
#包括
#包括
无效检查CUDAERROR(常量字符*msg)
{
cudaError_t err=cudaGetLastError();
如果(cudaSuccess!=错误){
fprintf(标准,“Cuda错误:%s:%s.\n”,消息,cudaGetErrorString(err));
退出(退出失败);
}
}
//CUDA内存的包装器
样板
类UniversalVector:public std::vector
{
T*设备接口;
布尔分配;
公众:
//建造师
UniversalVector(无符号整数长度)
:std::向量(长度),
已分配(错误)
{}
//析构函数
~UniversalVector()
{
如果(已分配)
cudaFree(devicePtr_);
}
cudaError\u t allocateDevice()
{
如果(已分配)空闲(devicePtr_);
cudaError\u t err=
cudaMalloc((void**)和devicePtr_,sizeof(T)*此->大小();
分配=真;
返回错误;
}
cudaError\u t loadToDevice()
{
返回cudaMemcpy(devicePtr_,&(*this)[0],sizeof(T)*this->size(),
cudamemcpyhostodevice);
}
cudaError\u t loadFromDevice()
{
返回cudaMemcpy(&(*this)[0],devicePtr,sizeof(T)*this->size(),
cudaMemcpyDeviceToHost);
}
//访问者
内联T*devicePtr(){
返回装置;
}
};
__全局无效内核(int*a)
{
int i=threadIdx.x;
printf(“%i\n”,a[i]);
}
int main()
{
UniversalVector vec(3);
向量(0)=1;
(1)处的向量=2;
(2)处的向量=3;
vec.allocateDevice();
vec.loadToDevice();
内核(vec.devicePtr());
检查CUDAERROR(“做某事时出错”);
返回0;
}

[1] 在CUDA中,主机内存和设备内存是有区别的,其中主机内存是GPU可访问的内存,设备内存是GPU上的内存,程序员必须将内存从主机移到GPU再移回来。

您可能想看看。它为CUDA代码提供了一些STL容器。

您可能想看看。它为CUDA代码提供了一些STL容器。

您最好将
allocateDevice
loadToDevice
等函数作为自由函数,而不是从
std::vector
继承的类成员。它可以为您节省大量将其他库/类与您的资料集成在一起的时间。总体看起来不错。

您最好将
allocateDevice
loadToDevice
等函数作为自由函数,而不是从
std::vector
继承的类成员。它可以为您节省大量将其他库/类与您的资料集成在一起的时间。总体上看起来不错。

我看到的最大问题是,这并不能真正帮助管理GPU方面的事情,而且它在处理过程中混淆了许多非常重要的信息

虽然container类包含有关是否已分配设备指针的信息,但无法知道主机容器的内容是否已复制到它所持有的GPU内存,或者GPU内存是否已复制回设备。因此,每次希望在主机或设备代码中使用容器时,都必须调用
loadToDevice()
loadFromDevice()
方法。这可能意味着至少在某些时候不必要的PCI-e内存传输。由于您选择只包装同步CUDA内存复制例程,因此每次执行此操作时都会出现主机阻塞


最终,我看不到这个想法比一套精心设计的助手例程有多大的净收益,这些例程将CUDA API中最丑陋的部分抽象出来,并在标准STL类型上运行。

我看到的最大问题是,这实际上对管理GPU方面没有太大帮助,在这个过程中,它混淆了许多非常重要的信息

虽然container类包含有关是否已分配设备指针的信息,但无法知道主机容器的内容是否已复制到它所持有的GPU内存,或者GPU内存是否已复制回设备。因此,每次希望在主机或设备代码中使用容器时,都必须调用
loadToDevice()
loadFromDevice()
方法。这可能意味着至少在某些时候不必要的PCI-e内存传输。由于您选择只包装同步CUDA内存复制例程,因此每次执行此操作时都会出现主机阻塞


最终,我看不到与一组精心设计的助手例程相比,这个想法有多大的净收益,这些例程将CUDA API中最丑陋的部分抽象出来,并在标准STL类型上运行。

我将稍微扩展David Rodríguez-dribeas的评论:

为什么你应该更喜欢组合而不是继承(即使它需要额外的外观工作)这个问题已经被问过并回答了多次。一个很好的答案是:

决定因素是接口:您想要底层类的所有方法还是某些方法

在您的情况下,
std::vector
修改向量大小的方法,如
resize
push_back
pop_back
erase
insert
等,如果在调用
loadToDevice
之间调用,可能会造成混乱