-Nan значение для общей суммы элементов массива с кодом GPU

Я работаю над кодом OpenCL, который вычисляет сумму элементов массива. Каждый работает нормально до размера 1,024 * 1e+8 для входного массива 1D, но с 1,024 * 1e+9 окончательное значение равно «-Nan».

Вот исходный код по этой ссылке

Код ядра находится по этой ссылке.

и Makefile по этой ссылке

Вот результат для последнего размера массива, который работает (последнее значение размера, которое работает, равно 1,024 * 1e+8):

$ ./sumReductionGPU 102400000 

Max WorkGroup size = 4100
Number of WorkGroups = 800000

  Problem size = 102400000

  Final Sum Sequential = 5.2428800512000000000e+15

  Final Sum GPU = 5.2428800512000000000e+15

  Initializing Arrays : Wall Clock = 0 second 673785 micro

  Preparing GPU/OpenCL : Wall Clock = 1 second 925451 micro

  Time for one NDRangeKernel call and WorkGroups final Sum  : Wall Clock = 0 second 30511 micro

  Time for Sequential Sum computing  : Wall Clock = 0 second 398485 micro

Я взял local_item_size = 128, поэтому, как указано выше, у меня есть 800000 Work-Groups за NWorkItems = 1.024 * 1e+8.

Теперь, если я возьму 1,024 * 10 ^ 9, частичные суммы больше не вычисляются, я получаю значение «-nan» для общей суммы элементов массива.

$ ./sumReductionGPU 1024000000

Max WorkGroup size = 4100
Number of WorkGroups = 8000000

  Problem size = 1024000000

  Final Sum Sequential = 5.2428800006710899200e+17

  Final Sum GPU =                 -nan

  Initializing Arrays : Wall Clock = 24 second 360088 micro

  Preparing GPU/OpenCL : Wall Clock = 19 second 494640 micro

  Time for one NDRangeKernel call and WorkGroups final Sum  : Wall Clock = 0 second 481910 micro

  Time for Sequential Sum computing  : Wall Clock = 166 second 214384 micro

Возможно, я достиг предела того, что может вычислить блок GPU. Но я хотел бы получить ваш совет, чтобы подтвердить это.

Если double равно 8 bytes, для входного массива потребуется 1,024 * 1e9 * 8 ~ 8 ГБ: не слишком ли это много? У меня всего 8 ГБ оперативной памяти.

Из вашего опыта, откуда может появиться эта проблема?

Спасибо


person youpilat13    schedule 19.02.2016    source источник
comment
Проверьте, не произошел ли сбой одного из вызовов malloc или clCreateBuffer из-за нехватки памяти. Также проверьте, является ли size_t 32-битным или 64-битным целым числом на вашей платформе.   -  person Martin Zabel    schedule 20.02.2016
comment
Спасибо, проблема возникает из-за clCreateBuffer, который не работает для 1,024 * 1e9 рабочих элементов.   -  person youpilat13    schedule 21.02.2016


Ответы (1)


Как вы уже выяснили, ваш одномерный входной массив требует много памяти. Таким образом, выделение памяти с помощью malloc или clCreateBuffer может привести к сбою.

Для malloc я предлагаю использовать вспомогательную функцию checked_malloc, которая обнаруживает неудачное выделение памяти, выводит сообщение и завершает работу программы.

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

void * checked_malloc(size_t size, const char purpose[]) {
  void *result = malloc(size);
  if(result == NULL) {
    fprintf(stderr, "ERROR: malloc failed for %s\n", purpose);
    exit(1);
  }
  return result;
}

int main()
{
  double *p1 = checked_malloc(1e8 * sizeof *p1, "array1");
  double *p2 = checked_malloc(64 * 1e9 * sizeof *p2, "array2");
  return 0;
}

На моем ПК, у которого всего 48 ГБ виртуальной памяти, второе выделение не удается, и программа печатает:

ERROR: malloc failed for array2

Вы можете применить эту схему и для clCreateBuffer. Но вы все равно должны проверять результат каждого вызова OpenCL. Итак, я рекомендую использовать для этого макрос:

#define CHECK_CL_ERROR(result) if(result != CL_SUCCESS) { \
    fprintf(stderr, "OpenCL call failed at: %s:%d with code %d\n", __FILE__, __LINE__, result); }

Пример использования:

cl_mem inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY,
    nWorkItems * sizeof(double), NULL, &ret);
CHECK_CL_ERROR(ret);
person Martin Zabel    schedule 21.02.2016
comment
Спасибо за ваши советы - person youpilat13; 27.02.2016