C++ 使用cudamallocpatch分配一维数组,然后使用cudaMemcpy2D 3复制到设备

C++ 使用cudamallocpatch分配一维数组,然后使用cudaMemcpy2D 3复制到设备,c++,matrix,cuda,gpu,sparse-matrix,C++,Matrix,Cuda,Gpu,Sparse Matrix,我读过这篇文章,包括NVIDIA docs,但我无法让CudamAllocPicch与cudaMemcpy2D一起工作 我需要以数组格式复制一个非常大的矩阵(矩阵[width*height]),同时复制一个简单的数组来执行矩阵*向量运算。为了避免冲突和获得更好的性能,使用CudamAllocPicch对我来说不是可选的 因此,我首先尝试将矩阵(在我的例子中是向量)复制到设备上,并检查它是否被正确复制,但我的代码没有打印任何内容。如果我使用Cudamaloc和cudaMemcpy,一切都很好。但我

我读过这篇文章,包括NVIDIA docs,但我无法让CudamAllocPicch与cudaMemcpy2D一起工作

我需要以数组格式复制一个非常大的矩阵(矩阵[width*height]),同时复制一个简单的数组来执行矩阵*向量运算。为了避免冲突和获得更好的性能,使用CudamAllocPicch对我来说不是可选的

因此,我首先尝试将矩阵(在我的例子中是向量)复制到设备上,并检查它是否被正确复制,但我的代码没有打印任何内容。如果我使用Cudamaloc和cudaMemcpy,一切都很好。但我不知道如何处理CudamAllocPictch和cudaMemcpy2D

我能做些什么来解决这个问题

#include <stdio.h>
__global__ void kernel(size_t mpitch, double * A, int N)
{
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    while (idx < N)
    {
        double e = *(double *)(((char *) A + idx * mpitch) + N);
        printf("(%f)", e);
    }
}
int main()
{
    int N = 1500;
    double * A  = new double[N], * d_A;
    size_t pitch;

    for (int i = 0; i < N; ++i)
    {
        A[i] = i;
    }
    cudaMallocPitch(&d_A, &pitch,  sizeof(double) * N, 1);
    cudaMemcpy2D(d_A, pitch, A, N * sizeof(double), sizeof(double) * N, 1, cudaMemcpyHostToDevice);
    unsigned int blocksize = 1024;
    unsigned int nblocks = (N + blocksize - 1) / blocksize;
    kernel <<<nblocks, blocksize>>>(pitch, d_A, N);
    cudaFree(d_A);
    delete [] A;
    return 0;
}
#包括
__全局无效内核(大小为mpitch,双*A,整数N)
{
int idx=threadIdx.x+blockIdx.x*blockDim.x;
while(idx
错误检查可以在调试中起到很大的作用。你来这里之前一定要用它

不清楚是否需要行或列向量,即[1xN]或[Nx1]的矩阵

我已经添加了一个关于Talomnies建议的解释,但首先是“工作代码板”

这是[Nx1]

#include <cstdio>
#include <iostream>
#include <cuda.h>

using namespace std;

__global__ void kernel(size_t mpitch, double * A, int N)
{
    int idx = threadIdx.x + blockIdx.x * blockDim.x;
    if(idx>=N) return;
    double e = *(double *)(((char *) A + idx * mpitch));
    printf("(%f)", e);

}
int main()
{
    int N = 15;
    double * A  = new double[N], * d_A;
    size_t pitch;

    for (int i = 0; i < N; ++i)
    {
        A[i] = i;
    }

    cudaError_t err = cudaMallocPitch(&d_A, &pitch, sizeof(double), N);
    if(err!=cudaSuccess) cout<<"err0:"<<cudaGetErrorString(err)<<endl;

    err = cudaMemcpy2D(d_A, pitch, A, sizeof(double), sizeof(double), N, cudaMemcpyHostToDevice);
    if(err!=cudaSuccess) cout<<"err1:"<<cudaGetErrorString(err)<<endl;

    unsigned int blocksize = 1024;
    unsigned int nblocks = (N + blocksize - 1) / blocksize;
    kernel <<<nblocks, blocksize>>>(pitch, d_A, N);

    cudaDeviceSynchronize();
    err = cudaGetLastError();
    if(err!=cudaSuccess) cout<<"err2:"<<cudaGetErrorString(err)<<endl;

    cudaFree(d_A);
    delete [] A;
    return 0;
}
这对于行向量是正确的,因为API是
cudamallocitch(void***指针,size\u t*pitch\u返回,size\u t行宽度,以字节为单位,size\u t行计数)
但是如果我们想执行列向量正确调用

cudaMallocPitch(&d_A, &pitch, sizeof(double), N);
访问: 对于访问,您混淆了访问行和访问行中的元素

double e = *(double *)(((char *) A + idx * mpitch) + N);
再次坚持文档。Cudamallotch的API文档包括

T* pElement = (T*)((char*)BaseAddress + Row * pitch) + Column;
对我们来说,这意味着

int column=0;
double element=(double*) ((char*)A + idx * mpitch) + column;
为了完整性,我使用了
column=0
,因为我们没有多个列

复制

cudaMemcpy2D(d_A, pitch, A, N * sizeof(double), sizeof(double) * N, 1, cudaMemcpyHostToDevice);
对于这种情况,这是正确的。
cudaMemcpy2D
的API是

cudaMemcpy2D(void* destination, size_t pitch_from_mallocPitch, const void* source, size_t source_pitch_bytes, size_t src_width_in_bytes, size_t src_rows_count, enum type_of_xfer);

我猜它应该是
内核(size\u t mpitch,double*A,int N)
,对吗?正确。我已经编辑过了。谢谢。好吧,我的地址计算错了;但是,您仍然应该使用错误检查和检查您正在计算的索引,因为它们正在生成出界访问。非常感谢。你帮了我很多!是的,给你;)我得说我不喜欢这种回答。它只是一个工作代码板,完全无法解释什么是错误的,为什么是错误的,以及需要什么来修复它。当下一个有类似问题的人发现searxh的问题时,他们将被迫区分OP的代码和此答案中的版本,以查看更改是什么,然后尝试自己理解它们。我一直认为,如果一张图片能抵得上千言万语,那么一个针对这个主题的可编译的简短示例肯定能抵得上两千字。我学习更复杂问题的大部分方法是创建或查找这样的示例,然后慢慢地将其转换为我的应用程序。然而,我相信你是对的,对于一些人来说,用
文本板解释更重要的细节会很有用。
int column=0;
double element=(double*) ((char*)A + idx * mpitch) + column;
cudaMemcpy2D(d_A, pitch, A, N * sizeof(double), sizeof(double) * N, 1, cudaMemcpyHostToDevice);
cudaMemcpy2D(void* destination, size_t pitch_from_mallocPitch, const void* source, size_t source_pitch_bytes, size_t src_width_in_bytes, size_t src_rows_count, enum type_of_xfer);