-ta=tesla:managed:cuda8 但 cuMemAllocManaged 返回错误 2:内存不足

-ta=tesla:managed:cuda8 but cuMemAllocManaged returned error 2: Out of memory

我是 OpenACC 的新手。就我对OpenMP的熟悉程度而言,我非常喜欢它。

我有 2 张 1080Ti 卡,每张 9GB,内存为 128GB。我正在尝试一个非常基本的测试来分配一个数组,初始化它,然后并行地总结它。这适用于 8 GB,但当我增加到 10 GB 时,出现内存不足错误。我的理解是,使用 Pascal(这些卡是)和 CUDA 8 的统一内存,我可以分配一个大于 GPU 内存的数组,并且硬件将按需调入调出。

这是我的完整 C 代码测试:

$ cat firstAcc.c 

#include <stdio.h>
#include <openacc.h>
#include <stdlib.h>

#define GB 10

int main()
{
  float *a;
  size_t n = GB*1024*1024*1024/sizeof(float);
  size_t s = n * sizeof(float);
  a = (float *)malloc(s);
  if (!a) { printf("Failed to malloc.\n"); return 1; }
  printf("Initializing ... ");
  for (int i = 0; i < n; ++i) {
    a[i] = 0.1f;
  }
  printf("done\n");
  float sum=0.0;
  #pragma acc loop reduction (+:sum)
  for (int i = 0; i < n; ++i) {
    sum+=a[i];
  }
  printf("Sum is %f\n", sum);
  free(a);
  return 0;
}

根据 this article 的 "Enable Unified Memory" 部分,我用 :

编译它
$ pgcc -acc -fast -ta=tesla:managed:cuda8 -Minfo firstAcc.c
main:
 20, Loop not fused: function call before adjacent loop
     Generated vector simd code for the loop
 28, Loop not fused: function call before adjacent loop
     Generated vector simd code for the loop containing reductions
     Generated a prefetch instruction for the loop

我需要了解这些消息,但目前我认为它们不相关。那我运行吧:

$ ./a.out
malloc: call to cuMemAllocManaged returned error 2: Out of memory
Aborted (core dumped)

如果我将 GB 更改为 8,则可以正常工作。由于 Pascal 1080Ti 和 CUDA 8,我希望 10GB 可以工作(尽管 GPU 卡有 9GB)。

我是不是理解错了,或者我做错了什么?提前致谢。

$ pgcc -V
pgcc 17.4-0 64-bit target on x86-64 Linux -tp haswell 
PGI Compilers and Tools
Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.

$ cat /usr/local/cuda-8.0/version.txt 
CUDA Version 8.0.61

我认为这里有问题:

size_t n = GB*1024*1024*1024/sizeof(float);

当我用 g++ 编译那行代码时,我收到了关于整数溢出的警告。出于某种原因,PGI 编译器没有警告,但同样的错误正在发生。在 sn 的声明之后,如果我添加这样的打印输出:

  size_t n = GB*1024*1024*1024/sizeof(float);
  size_t s = n * sizeof(float);
  printf("n = %lu, s = %lu\n", n, s);  // add this line

并使用 PGI 17.04 和 运行(在 P100 上,16GB)编译,我得到这样的输出:

$ pgcc -acc -fast -ta=tesla:managed:cuda8 -Minfo m1.c
main:
     16, Loop not fused: function call before adjacent loop
         Generated vector simd code for the loop
     22, Loop not fused: function call before adjacent loop
         Generated vector simd code for the loop containing reductions
         Generated a prefetch instruction for the loop
$ ./a.out
n = 4611686017890516992, s = 18446744071562067968
malloc: call to cuMemAllocManaged returned error 2: Out of memory
Aborted
$

所以很明显 ns 不是您想要的。

我们可以通过用 ULL 标记所有这些常量来解决这个问题,然后事情似乎对我来说是正确的:

$ cat m1.c
#include <stdio.h>
#include <openacc.h>
#include <stdlib.h>

#define GB 20ULL

int main()
{
  float *a;
  size_t n = GB*1024ULL*1024ULL*1024ULL/sizeof(float);
  size_t s = n * sizeof(float);
  printf("n = %lu, s = %lu\n", n, s);
  a = (float *)malloc(s);
  if (!a) { printf("Failed to malloc.\n"); return 1; }
  printf("Initializing ... ");
  for (int i = 0; i < n; ++i) {
    a[i] = 0.1f;
  }
  printf("done\n");
  double sum=0.0;
  #pragma acc loop reduction (+:sum)
  for (int i = 0; i < n; ++i) {
    sum+=a[i];
  }
  printf("Sum is %f\n", sum);
  free(a);
  return 0;
}
$ pgcc -acc -fast -ta=tesla:managed:cuda8 -Minfo m1.c
main:
     16, Loop not fused: function call before adjacent loop
         Generated vector simd code for the loop
     22, Loop not fused: function call before adjacent loop
         Generated vector simd code for the loop containing reductions
         Generated a prefetch instruction for the loop
$ ./a.out
n = 5368709120, s = 21474836480
Initializing ... done
Sum is 536870920.000000
$

请注意,我还在上面进行了另一项更改。我将 sum 累积变量从 float 更改为 double。当对非常小的数量进行非常大的减少时,这对于保留一些 "sensible" 结果是必要的。

而且,正如@MatColgrove 在他的回答中指出的那样,我还错过了其他一些事情。

除了 Bob 提到的,我还做了一些修复。

首先,您实际上并没有生成 OpenACC 计算区域,因为您只有一个“#pragma acc loop”指令。这应该是“#pragma acc parallel loop”。您可以在仅显示主机代码优化的编译器反馈消息中看到这一点。

其次,"i" 索引应声明为 "long"。否则,您将溢出索引。

最后,您需要将 "cc60" 添加到您的目标加速器选项中,以告知编译器以基于 Pascal 的 GPU 为目标。

% cat mi.c  
#include <stdio.h>
#include <openacc.h>
#include <stdlib.h>

#define GB 20ULL

int main()
{
  float *a;
  size_t n = GB*1024ULL*1024ULL*1024ULL/sizeof(float);
  size_t s = n * sizeof(float);
  printf("n = %lu, s = %lu\n", n, s);
  a = (float *)malloc(s);
  if (!a) { printf("Failed to malloc.\n"); return 1; }
  printf("Initializing ... ");
  for (int i = 0; i < n; ++i) {
    a[i] = 0.1f;
  }
  printf("done\n");
  double sum=0.0;
  #pragma acc parallel loop reduction (+:sum)
  for (long i = 0; i < n; ++i) {
    sum+=a[i];
  }
  printf("Sum is %f\n", sum);
  free(a);
  return 0;
}

% pgcc -fast -acc -ta=tesla:managed,cuda8.0,cc60 -Minfo=accel mi.c
main:
     21, Accelerator kernel generated
         Generating Tesla code
         21, Generating reduction(+:sum)
         22, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */
     21, Generating implicit copyin(a[:5368709120])
% ./a.out
n = 5368709120, s = 21474836480
Initializing ... done
Sum is 536870920.000000