【问题标题】:cuda - Zero-copy memory, memory-mapped filecuda - 零拷贝内存,内存映射文件
【发布时间】:2015-06-13 15:51:10
【问题描述】:

我正在尝试创建一个包含uint32_ts 的映射内存文件,然后将其用作零拷贝固定内存,如下所示的 CUDA。我在获取设备指针、分配空间并从文件映射内存时得到cudaErrorInvalidValue。我知道错误消息(来自 API)意味着:

这表明传递给 API 调用的一个或多个参数不在可接受的值范围内。

但我很难弄清楚为什么我会遇到这个问题......有什么想法吗?提前致谢。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

    …

int main(void) 
{
  struct stat buf;

    …

  uint32_t *data, *dev_data;

  cudaDeviceProp cuda_prop;
  cudaGetDeviceProperties(&cuda_prop, 0);
  if (!cuda_prop.canMapHostMemory) 
    exit(EXIT_FAILURE);

  cudaSetDeviceFlags(cudaDeviceMapHost);


  int data_file = open(data_file_name, O_RDONLY);
  int stat = fstat(sa_file, &buf);
  int data_file_size = buf.st_size;

  err = cudaHostAlloc((void**)&data, data_file_size, cudaHostAllocMapped);
  if (err == cudaErrorMemoryAllocation) exit(EXIT_FAILURE);

  data = (uint32_t*) mmap(0, data_file_size, PROT_READ, MAP_PRIVATE, data_file, 0);

  err = cudaHostGetDevicePointer((void**)&dev_data, (void*)data, 0);
  if (err == cudaErrorMemoryAllocation)
  {
    printf("cudaHostGetDevicePointer - Mem Alloc Err\n"); 
    exit(EXIT_FAILURE);
  }
  else if (err == cudaErrorInvalidValue) //ERROR HERE.
  {
    printf("cudaHostGetDevicePointer - Invalid Val Err\n"); 
    exit(EXIT_FAILURE);
  }

    …

}

【问题讨论】:

  • cudaHostAllocdata 分配了一个值,然后您用data = mmap(...) 行覆盖了该值。 cudaHostGetDevicePointer 不知道如何处理 mmap 提供的 data 的新值,因为 CUDA API 没有提供该值。您可以尝试摆脱 cudaHostAlloc 行,然后在 mmap 行之后的 data 上执行 cudaHostRegister。我不知道这是否可行。
  • 如果 GPU 驱动程序可以从映射文件注册虚拟分配,我会感到非常惊讶

标签: c memory memory-management cuda mmap


【解决方案1】:

一个问题是你的程序的逻辑顺序不正确。此行为 CUDA API 提供的data 赋值:

err = cudaHostAlloc((void**)&data, data_file_size, cudaHostAllocMapped);

这一行然后覆盖那个值,用一个新值:

data = (uint32_t*) mmap(0, data_file_size, PROT_READ, MAP_PRIVATE, data_file, 0);

此时,data 的值不再被 CUDA API 识别为固定内存空间,所以当你调用它时:

err = cudaHostGetDevicePointer((void**)&dev_data, (void*)data, 0);

您收到错误,因为 data 中包含的值无法识别。

编辑:(基于this question) 除了这个问题,似乎如果您将文件处理从只读更改为读写,则可以使此过程正常工作(不会引发运行时错误)。这是一个完整的代码(不包含上述逻辑缺陷),演示了这一点(我之前创建了一个大小为 566316 字节的test.dat 文件):

$ cat t706.cu
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

int main(void)
{
  struct stat buf;

  char *dev_data;

  cudaDeviceProp cuda_prop;
  cudaGetDeviceProperties(&cuda_prop, 0);
  if (!cuda_prop.canMapHostMemory)
    exit(EXIT_FAILURE);

  cudaSetDeviceFlags(cudaDeviceMapHost);


  int data_file = open("test.dat", O_RDWR);
  int stat = fstat(data_file, &buf);
  int data_file_size = buf.st_size;
  printf("data_file_size = %d\n", data_file_size);
  char *data = (char *) mmap(0, data_file_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, data_file, 0);
  if (data == MAP_FAILED) {
    printf("mmap failure\n");
    exit(EXIT_FAILURE);}
  cudaError_t err = cudaHostRegister(data, data_file_size, cudaHostRegisterDefault);
  if (err != cudaSuccess) { //ERROR HERE.
    printf("cudaHostRegister fail\n");
    exit(EXIT_FAILURE);}

  err = cudaHostGetDevicePointer((void**)&dev_data, (void*)data, 0);
  if (err == cudaErrorMemoryAllocation)
  {
    printf("cudaHostGetDevicePointer - Mem Alloc Err\n");
    exit(EXIT_FAILURE);
  }
  else if (err == cudaErrorInvalidValue)
  {
    printf("cudaHostGetDevicePointer - Invalid Val Err\n");
    exit(EXIT_FAILURE);
  }

}
$ nvcc -arch=sm_30 -o t706 t706.cu
$ ./t706
data_file_size = 566316
$

【讨论】:

  • 感谢您的尝试,并更正了主机分配逻辑!我想解决这个问题的最简单方法可能是freading 而不是使用mmap...
  • 将标志cudaHostRegisterReadOnly 传递给cudaHostRegister() 允许映射内存而不需要标记PROT_WRITE。这不仅使编码更清晰,而且似乎还提供了不错的减速带,至少在我的测试设置中是这样。
猜你喜欢
  • 2020-01-05
  • 2011-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
相关资源
最近更新 更多