CUDA 4.0-cudaHostUnregister运行缓慢

CUDA 4.0-cudaHostUnregister运行缓慢,c,cuda,paging,C,Cuda,Paging,我一直在使用cudaHostRegister和cudaHostUnregister函数,我注意到后者需要很长时间。即使将cudaHostUnregister与同一数据上的cudaMemcpy进行比较,也需要很长时间,即使没有为memcpy使用页面锁定内存也是如此 我制作了以下简短节目: #include <stdio.h> #include <time.h> #include <assert.h> #include <stdlib.h> stat

我一直在使用cudaHostRegister和cudaHostUnregister函数,我注意到后者需要很长时间。即使将cudaHostUnregister与同一数据上的cudaMemcpy进行比较,也需要很长时间,即使没有为memcpy使用页面锁定内存也是如此

我制作了以下简短节目:

#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <stdlib.h>

static struct timespec tp;
static clockid_t clk = CLOCK_REALTIME;

static void tu_timer_start(void)
{
  int res = clock_gettime(clk, &tp);
  assert(!res);
}

static long long tu_timer_stop(void)
{
  struct timespec tp_new;
  long long elapsed;
  int res = clock_gettime(clk, &tp_new);

  assert(!res);

  elapsed = 1000000000LL * (tp_new.tv_sec - tp.tv_sec) + tp_new.tv_nsec - tp.tv_nsec;
  tp = tp_new;

  return elapsed;
}

int main() {
  const int length = 999424;
  const int pagesize = 4096;

  // Allocating page-aligned host data and filling it with zeroes.
  int *paged, *locked;
  posix_memalign((void**) &paged, pagesize, length * sizeof(int));
  posix_memalign((void**) &locked, pagesize, length * sizeof(int));
  memset(paged, 0, length * sizeof(int));
  memset(locked, 0, length * sizeof(int));

  // Allocating device data.
  int *devPaged, *devLocked;
  tu_timer_start();
  printf("%20d\n", cudaMalloc(&devPaged, length * sizeof(int)));
  printf("%20d\n", cudaMalloc(&devLocked, length * sizeof(int)));
  printf("Initialization:   %12lld ns\n", tu_timer_stop());

  // Measure copy time with pageable data.
  tu_timer_start();
  printf("%20d\n", cudaMemcpy(devPaged, paged, length * sizeof(int), cudaMemcpyHostToDevice));
  printf("Copy pageable:    %12lld ns\n", tu_timer_stop());

  // Measure time to page-lock host data.
  tu_timer_start();
  printf("%20d\n", cudaHostRegister(locked, length * sizeof(int), 0));
  printf("Host register:    %12lld ns\n", tu_timer_stop());

  // Measure copy time with page-locked data.
  tu_timer_start();
  printf("%20d\n", cudaMemcpy(devLocked, locked, length * sizeof(int), cudaMemcpyHostToDevice));
  printf("Copy page-locked: %12lld ns\n", tu_timer_stop());

  // Measure time to release page-lock on host data.
  tu_timer_start();
  cudaHostUnregister(locked);
  printf("Host unregister:  %12lld ns\n", tu_timer_stop());  

  return 0;
}
这说明了我的问题。在我的实际程序中,更糟糕的是,我经常测量cudaHostUnregister,大约需要3460000纳秒。这意味着它在并发异步memcopies或内核运行时表现不佳,而且速度较慢

为什么这个功能需要这么长时间,有没有办法加快它?它真的不能与memcopies和内核并行工作吗?如果可以,为什么不能


或者有更好的方法来并行化memcopies和内核运行吗?

它依赖于平台,但是当您调用cuMemHostUnregister()/cudaHostUnregister()时,无法回避您要求驱动程序执行的操作:取消GPU的内存映射,并再次将其标记为可由主机操作系统分页。这些操作可能涉及以下内容:

1) 与GPU同步,因为驱动程序很难判断挂起的GPU命令是否需要内存; 2) 执行内核thunk,因为GPU页表只能在内核模式下编辑; 3) 更新硬件寄存器以取消映射内存

一旦不再为GPU映射内存,驱动程序就可以取消页锁定。这也可能是一项昂贵的操作,其性能取决于平台

我的建议是为CUDA保留“已注册”的内存,根据启发式方法取消注册(例如,垃圾收集注册,或者在注册失败时“腾出空间”)


请注意,如果存在多个GPU且统一虚拟寻址有效,则驱动程序必须对系统中的每个GPU执行这些操作。

这取决于平台,但无法回避调用cumeHostUnregister()/cudaHostUnregister()时要驱动程序执行的操作:取消GPU的内存映射,并再次将其标记为主机操作系统可分页。这些操作可能涉及以下内容:

1) 与GPU同步,因为驱动程序很难判断挂起的GPU命令是否需要内存; 2) 执行内核thunk,因为GPU页表只能在内核模式下编辑; 3) 更新硬件寄存器以取消映射内存

一旦不再为GPU映射内存,驱动程序就可以取消页锁定。这也可能是一项昂贵的操作,其性能取决于平台

我的建议是为CUDA保留“已注册”的内存,根据启发式方法取消注册(例如,垃圾收集注册,或者在注册失败时“腾出空间”)

请注意,如果存在多个GPU且统一虚拟寻址有效,则驱动程序必须对系统中的每个GPU执行这些操作。

Crossposted at.Crossposted at。
Initialization:       81027005 ns
Copy pageable:         1263236 ns
Host register:          436132 ns
Copy page-locked:       706051 ns
Host unregister:       2139736 ns