-ta=tesla:managed:cuda8, ​​но cuMemAllocManaged вернул ошибку 2: Недостаточно памяти

Я новичок в OpenACC. Мне это очень нравится, поскольку я знаком с OpenMP.

У меня есть 2 карты 1080Ti по 9 ГБ каждая и 128 ГБ оперативной памяти. Я пытаюсь провести очень простой тест, чтобы выделить массив, инициализировать его, а затем суммировать его параллельно. Это работает для 8 ГБ, но когда я увеличиваю до 10 ГБ, я получаю сообщение об ошибке нехватки памяти. Насколько я понял, с объединенной памятью Pascal (которой являются эти карты) и CUDA 8 я мог бы выделить массив, больший, чем память графического процессора, и аппаратное обеспечение будет выгружать и выгружать страницы по запросу.

Вот мой полный тест кода 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;
}

Согласно разделу «Включение единой памяти» этой статьи Я скомпилирую его с помощью:

$ 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. Я ожидал, что 10GB будет работать (несмотря на карту GPU с 9 ГБ) благодаря Pascal 1080Ti и CUDA 8.

Я неправильно понимаю или что я делаю не так? Заранее спасибо.

$ 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

person Matt Dowle    schedule 02.05.2017    source источник
comment
Я с подозрением отношусь к этому: size_t n = GB*1024*1024*1024/sizeof(float); Когда я компилирую это с помощью GNU g++ 4.8.2, я получаю предупреждение о целочисленном переполнении. Что произойдет, если вы распечатаете n и s сразу после их назначения? Когда я это делаю, я получаю слишком большие числа. Попробуйте добавить ULL после всех ваших констант.   -  person Robert Crovella    schedule 02.05.2017
comment
@RobertCrovella Как неловко. Да, это было так. Работает сейчас. Спасибо!   -  person Matt Dowle    schedule 02.05.2017


Ответы (2)


Я считаю, что проблема здесь:

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

когда я компилирую эту строку кода с помощью g++, я получаю предупреждение о целочисленном переполнении. По какой-то причине компилятор PGI не предупреждает, но под капотом происходит то же самое. После объявлений s и n, если я добавлю такую ​​распечатку:

  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, с 16 ГБ), я получаю такой вывод:

$ 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
$

так что очевидно, что n и s не то, что вы хотели.

Мы можем исправить это, пометив все эти константы 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. Это необходимо, чтобы сохранить в некоторой степени «разумные» результаты при выполнении очень большого сокращения для очень малых количеств.

И, как указал @MatColgrove в своем ответе, я пропустил еще несколько вещей.

person Robert Crovella    schedule 02.05.2017
comment
Огромное спасибо. Действительно, это было так, и теперь он отлично работает. - person Matt Dowle; 02.05.2017

Помимо того, что упомянул Боб, я сделал еще несколько исправлений.

Во-первых, вы на самом деле не создаете вычислительную область OpenACC, поскольку у вас есть только директива «#pragma acc loop». Это должно быть "параллельный цикл #pragma acc". Вы можете увидеть это в сообщениях обратной связи компилятора, где он показывает только оптимизацию кода хоста.

Во-вторых, индекс «i» должен быть объявлен как «длинный». В противном случае вы переполните индекс.

Наконец, вам нужно добавить «cc60» к вашим параметрам целевого ускорителя, чтобы указать компилятору ориентироваться на графический процессор на основе Pascal.

% 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
person Mat Colgrove    schedule 02.05.2017
comment
Отлично - большое спасибо! Я прочитал в man pgcc предложение Specifying cc60 also implies the cuda8.0 option и мне стало интересно, что такое cc60. Тогда я буду использовать cc60 вместо cuda8.0. Есть ли что-то вроде -mtune=native, которое просто определяет оборудование для меня? - person Matt Dowle; 03.05.2017
comment
Да, вы правы, что cc60 (Compute Capability 6.0, он же Pascal) подразумевает CUDA 8.0. На стороне хоста компилятор автоматически определяет архитектуру ЦП, если она явно не задана с помощью флага -tp. Для устройства pgcc по умолчанию ориентируется на Fermi, Kepler и Maxwell, т.е. -ta=tesla:cc30,cc35,cc50, но не определяет автоматически, какое устройство находится в системе (часто в системе компиляции нет подключенного устройства). ). Мы не хотели добавлять устройства Pascal по умолчанию, так как многие наши клиенты не перешли на использование драйверов CUDA 8.0. - person Mat Colgrove; 03.05.2017
comment
Ок имеет смысл. Спасибо. - person Matt Dowle; 03.05.2017
comment
Есть шанс, что вы знаете ответ на мой следующий вопрос здесь. Ответ немного запутанный об объединенной памяти в cuda6, но я конкретно спрашиваю о новых улучшенных аппаратных возможностях Pascal и CUDA8 при сбое страницы: stackoverflow.com/questions/43768717/ - person Matt Dowle; 04.05.2017
comment
Похоже, другие люди подскочили с текущим ответом вызова cudaMemAdvice и cudaMemPrefetch. В PGI мы ищем способы улучшить взаимодействие с пользователем. Однако, учитывая, что это все еще находится на стадии исследования, я, к сожалению, не могу сообщить подробности, кроме того, что мы изучаем это. - person Mat Colgrove; 04.05.2017