Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.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
C++ CUDA:查明主机缓冲区是否已固定(页面锁定)_C++_Memory_Cuda_Gpu - Fatal编程技术网

C++ CUDA:查明主机缓冲区是否已固定(页面锁定)

C++ CUDA:查明主机缓冲区是否已固定(页面锁定),c++,memory,cuda,gpu,C++,Memory,Cuda,Gpu,我的问题简要描述如下: 我开发了一个调用CUDA内核的函数。我的函数接收一个指向主机数据缓冲区(内核的输入和输出)的指针,并且不能控制这些缓冲区的分配 -->主机数据可能是通过malloc或cudaHostAlloc分配的。我的函数没有被明确告知使用了哪种分配方法 问题是:对于我的函数来说,什么是确定主机缓冲区是否被锁定/页面锁定(cudaHostAlloc)的可行方法(常规malloc) 我询问的原因是,如果它们没有页面锁定,我希望使用cudahosterRegister()使它们(缓冲区)成

我的问题简要描述如下:

我开发了一个调用CUDA内核的函数。我的函数接收一个指向主机数据缓冲区(内核的输入和输出)的指针,并且不能控制这些缓冲区的分配

-->主机数据可能是通过malloc或cudaHostAlloc分配的。我的函数没有被明确告知使用了哪种分配方法

问题是:对于我的函数来说,什么是确定主机缓冲区是否被锁定/页面锁定(cudaHostAlloc)的可行方法(常规malloc)

我询问的原因是,如果它们没有页面锁定,我希望使用cudahosterRegister()使它们(缓冲区)成为页面锁定,从而使它们适合流

我尝试了三种失败的方法: 1-始终应用cudaHostRegister():如果主机缓冲区已固定,则这种方法不好 2-运行cudaPointerGetAttribute(),如果返回错误为cudaSuccess,则缓冲区已被锁定,无需执行任何操作;否则,如果是cudaErrorInvalidValue,则应用cudahosterRegister:由于某种原因,这种方式会导致内核执行返回错误 3-运行cudaHostGetFlags(),如果返回不成功,则应用cudaHostRegister:与2-相同的行为

在2-和3-的情况下,错误为“invalid argumentn”

请注意,我的代码当前没有使用流,而是始终为整个主机缓冲区调用cudaMemcpy()。如果不使用上述三种方法中的任何一种,则无论主机缓冲区是否固定,代码都会一直运行到完成

有什么建议吗?非常感谢。

您的方法2应该有效(我认为方法3也应该有效)。在这种情况下,您可能会对如何进行正确的CUDA错误检查感到困惑

由于运行时API调用失败,如果在内核调用后执行类似于
cudaGetLastError
的操作,它将显示先前在
cudaPointerGetAttributes()调用上发生的运行时API失败。对你来说,这不一定是灾难性的。您要做的是清除该错误,因为您知道它发生了,并且已经正确地处理了它。您可以通过额外调用
cudaGetLastError
(对于这种类型的“非粘性”API错误,即不意味着CUDA上下文已损坏的API错误)来实现这一点

下面是一个充分发挥作用的示例:

$ cat t642.cu
#include <stdio.h>
#include <stdlib.h>

#define DSIZE 10
#define nTPB 256

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

__global__ void mykernel(int *data, int n){

  int idx = threadIdx.x+blockDim.x*blockIdx.x;
  if (idx < n) data[idx] = idx;
}

int my_func(int *data, int n){

  cudaPointerAttributes my_attr;
  if (cudaPointerGetAttributes(&my_attr, data) == cudaErrorInvalidValue) {
    cudaGetLastError(); // clear out the previous API error
    cudaHostRegister(data, n*sizeof(int), cudaHostRegisterPortable);
    cudaCheckErrors("cudaHostRegister fail");
    }
  int *d_data;
  cudaMalloc(&d_data, n*sizeof(int));
  cudaCheckErrors("cudaMalloc fail");
  cudaMemset(d_data, 0, n*sizeof(int));
  cudaCheckErrors("cudaMemset fail");
  mykernel<<<(n+nTPB-1)/nTPB, nTPB>>>(d_data, n);
  cudaDeviceSynchronize();
  cudaCheckErrors("kernel fail");
  cudaMemcpy(data, d_data, n*sizeof(int), cudaMemcpyDeviceToHost);
  cudaCheckErrors("cudaMemcpy fail");
  int result = 1;
  for (int i = 0; i < n; i++) if (data[i] != i) result = 0;
  return result;
}

int main(int argc, char *argv[]){

  int *h_data;
  int mysize = DSIZE*sizeof(int);
  int use_pinned = 0;
  if (argc > 1) if (atoi(argv[1]) == 1) use_pinned = 1;
  if (!use_pinned) h_data = (int *)malloc(mysize);
  else {
    cudaHostAlloc(&h_data, mysize, cudaHostAllocDefault);
    cudaCheckErrors("cudaHostAlloc fail");}
  if (!my_func(h_data, DSIZE)) {printf("fail!\n"); return 1;}
  printf("success!\n");
  return 0;
}

$ nvcc -o t642 t642.cu
$ ./t642
success!
$ ./t642 1
success!
$

如果您省略了这一步(您可以尝试注释它),那么当您在案例0中运行代码时(即,在函数调用之前不要使用固定内存),那么您将在下一个错误检查步骤(在我的案例中是下一个API调用,但在您的案例中可能在内核调用之后)出现“伪”错误。

谢谢!你的回答对我来说很有效,也很清楚。非常感谢。请注意,方法3-在使用您指出的技巧时也有效。
// clear out the previous API error