【问题标题】:How to copy structured data allocated in device memory from device to host如何将设备内存中分配的结构化数据从设备复制到主机
【发布时间】:2013-10-22 10:44:33
【问题描述】:

我是 GPU 和 CUDA 编程的新手。我正在尝试将设备上动态分配的结构化数据从设备复制到主机。我从 GPU 编程指南中修改了一个简单的代码。编译代码时我没有收到任何错误,但我唯一有问题的是输出错误,即“0”。代码如下:

#include <stdlib.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>

typedef struct Point
{
    int2 pt;
};

#define NUMOFBLOCKS 1
#define THREDSPERBLOCK  16

__device__ Point* pnt[NUMOFBLOCKS];
Point dataptr_h[NUMOFBLOCKS][THREDSPERBLOCK];

__global__ void allocmem() 
{   
    if (threadIdx.x == 0)       
        pnt[blockIdx.x] = (Point*)malloc(1*blockDim.x * sizeof(Point)); 
    __syncthreads(); 
} 

__global__ void usemem() 
{ 
    Point* ptr = pnt[blockIdx.x]; 
    if (ptr != NULL) 
    {       
        ptr[threadIdx.x].pt.x = threadIdx.x; 
        ptr[threadIdx.x].pt.y = threadIdx.x;
        printf("Ptr = %d\t", ptr[threadIdx.x].pt.x);
    }
}

__global__ void freemem() 
{ 
    Point* ptr = pnt[blockIdx.x]; 
    if (ptr != NULL) 
        printf("Block %d, Thread %d: final value = %d\n", blockIdx.x, threadIdx.x, ptr[threadIdx.x]); 
    if (threadIdx.x == 0) 
        free(ptr); 
}


int main()
{
    Point* d_pt[NUMOFBLOCKS];
    for (int i = 0 ; i < NUMOFBLOCKS; i++)
        cudaMalloc(&d_pt[i], sizeof(Point)*16);  

    // Allocate memory  
    allocmem<<< NUMOFBLOCKS, THREDSPERBLOCK >>>();  
    // Use memory 
    usemem<<< NUMOFBLOCKS, THREDSPERBLOCK >>>(); 
    cudaMemcpyFromSymbol(d_pt, pnt, sizeof(d_pt));
    cudaMemcpy(dataptr_h, d_pt, sizeof(dataptr_h), cudaMemcpyDeviceToHost);

    for (int j = 0 ; j < 1; j++)
        for (int i = 0 ; i < 16; i++)
        {
            printf("\nPtr_h(%d,%d)->X = %d\t", j, i, dataptr_h[j][i].pt.x);
            printf("Ptr_h(%d,%d)->Y = %d", j, i, dataptr_h[j][i].pt.y);
        }

    freemem<<< NUMOFBLOCKS, THREDSPERBLOCK >>>();
    cudaDeviceSynchronize();
    return 0;
}

代码的输出是:

Ptr_h(0,0)->X = 0       Ptr_h(0,0)->Y = 0
Ptr_h(0,1)->X = 0       Ptr_h(0,1)->Y = 0
Ptr_h(0,2)->X = 0       Ptr_h(0,2)->Y = 0
Ptr_h(0,3)->X = 0       Ptr_h(0,3)->Y = 0
Ptr_h(0,4)->X = 0       Ptr_h(0,4)->Y = 0
Ptr_h(0,5)->X = 0       Ptr_h(0,5)->Y = 0
Ptr_h(0,6)->X = 0       Ptr_h(0,6)->Y = 0
Ptr_h(0,7)->X = 0       Ptr_h(0,7)->Y = 0
Ptr_h(0,8)->X = 0       Ptr_h(0,8)->Y = 0
Ptr_h(0,9)->X = 0       Ptr_h(0,9)->Y = 0
Ptr_h(0,10)->X = 0      Ptr_h(0,10)->Y = 0
Ptr_h(0,11)->X = 0      Ptr_h(0,11)->Y = 0
Ptr_h(0,12)->X = 0      Ptr_h(0,12)->Y = 0
Ptr_h(0,13)->X = 0      Ptr_h(0,13)->Y = 0
Ptr_h(0,14)->X = 0      Ptr_h(0,14)->Y = 0
Ptr_h(0,15)->X = 0      Ptr_h(0,15)->Y = 0

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

【问题讨论】:

  • 您应该对所有 CUDA API 调用和内核调用执行正确的cuda error checking。它将指出您遇到问题的代码行。由于您的内核 printf 语句没有显示出来,因此很明显您的内核没有正确执行。使用cuda-memcheck 运行您的代码可能会对此有所了解。
  • 事实上,当我运行你的代码时,你的一些内核 printf 语句确实出现了。因此,如果您没有看到Ptr = 0 Ptr = 1 ...,那么您可能还有另一个问题(机器配置)。但适当的 cuda 错误检查将帮助您发现是否也是这种情况。
  • 感谢罗伯特的评论。但是 printf 在内核中运行良好,我可以看到 Ptr = 0 Ptr = 1 ...唯一的问题是该数据没有传递/复制到主机。我正在尝试关注您的下一个答案...

标签: c++ cuda gpu


【解决方案1】:

您不能将设备 malloc 操作创建的指针与 CUDA 运行时 API 一起使用(即 cudaMemcpy

所以这行代码有问题:

cudaMemcpy(dataptr_h, d_pt, sizeof(dataptr_h), cudaMemcpyDeviceToHost);

d_pt 包含从pnt 提取的指针。 pnt 的值由设备 malloc 设置。

相反,您需要创建使用cudaMalloc 正确分配的区域,然后首先将您想要的数据复制到这些区域(从设备上的一个区域到另一个区域),然后使用cudaMemcpy 复制到主机。

在我进一步解释您的下一个反对意见之前,让我们明确一下,以上是您的意图(使用在设备malloc 操作中创建的指针作为cudaMemcpy 的目标之一)。这是不合法的。

“但是我用过 cudaMalloc ??”

d_pt 是一个存在于主机内存中的指针数组。您使用cudaMalloc 获取了这些指针中的每一个并为其分配了一个值(设备内存中的一个指向位置)。

那么这行代码:

cudaMemcpyFromSymbol(d_pt, pnt, sizeof(d_pt));

重写所有你用从设备内存中其他地方获得的指针设置的指针,特别是设备malloc分配的指针。虽然这在技术上是合法的(那行代码不会引发错误),但这些指针在主机上是无用的(无论如何,与运行时 API 一起使用)。

【讨论】:

  • 感谢您的解释。如果我们不能将设备 操作创建的指针与 CUDA 运行时 API () 一起使用,那么替代方法是什么?那么 会做什么呢?我的意思是,如果该函数没有传递设备中分配的指针,它的目的是什么?
  • 另一种方法是使用cudaMalloc 分配内存区域并使用这些区域而不是设备分配区域。我已经在回复中指出了这一点。 cudaMemcpyFromSymbol 将数据从 __device__ 区域/变量复制到主机。它的用途类似于cudaMemcpy
  • 我尝试使用 cuaMalloc 分配内存,但无法通过...此外,我在 CUDA 编程指南 4.2 中读到可以使用运行时复制通过 malloc() 分配的内存(即通过调用任何复制内存函数)。请参考section B.17.2 of CUDA C Programming Guide 4.2
  • 所以,我现在有点困惑。我的理解(我可能是错的)是如果我们从设备(即符号pnt)复制到主机dataptr_h,内存副本应该使用cudaMemcpyFromSymbol,正如您所解释的那样cudaMemcpyFromSymbol__device__复制数据区域到主机。但它在这里不起作用。
  • 所以您参考了 CUDA 4.2 编程指南。您使用的是 CUDA 4.2 吗?
猜你喜欢
  • 2017-08-27
  • 2021-07-22
  • 2017-03-23
  • 2011-08-24
  • 1970-01-01
  • 2012-10-14
  • 1970-01-01
  • 2016-07-25
  • 2011-11-30
相关资源
最近更新 更多