Почему cudaMalloc выдает ошибку, когда я знаю, что в памяти достаточно места? - PullRequest
5 голосов
/ 18 января 2012

У меня есть Tesla C2070, который должен иметь 5636554752 байта памяти.

Однако, это дает мне ошибку:

int *buf_d = NULL;

err = cudaMalloc((void **)&buf_d, 1000000000*sizeof(int));

if( err != cudaSuccess)
{
     printf("CUDA error: %s\n", cudaGetErrorString(err));
     return EXIT_ERROR;
}

Как это возможно? Это как-то связано с максимальным шагом памяти? Вот спецификации GPU:

Device 0: "Tesla C2070" 
CUDA Driver Version:    3.20 
CUDA Runtime Version:   3.20 
CUDA Capability Major/Minor version number: 2.0 
Total amount of global memory:  5636554752 bytes 
Multiprocessors x Cores/MP = Cores: 14 (MP) x 32 (Cores/MP) = 448 (Cores) 
Total amount of constant memory:    65536 bytes Total amount of shared memory per block:    49152 bytes Total number of registers available per block: 32768 Warp size: 32 
Maximum number of threads per block:    1024 
Maximum sizes of each dimension of a block: 1024 x 1024 x 64 
Maximum sizes of each dimension of a grid:  65535 x 65535 x 1
Maximum memory pitch: 2147483647 bytes

Что касается машины, на которой я работаю, она имеет 24 процессора Intel® Xeon® X565 с дистрибутивом Linux Rocks 5.4 (Maverick).

Есть идеи? Спасибо!

1 Ответ

11 голосов
/ 19 января 2012

Основная проблема в названии вашего вопроса - вы на самом деле не знаете , что у вас достаточно памяти, вы предполагаете, что у вас есть. API времени выполнения включает в себя функцию cudaMemGetInfo, которая будет возвращать объем свободной памяти на устройстве. Когда контекст устанавливается на устройстве, драйвер должен зарезервировать пространство для кода устройства, локальной памяти для каждого потока, буферов fifo для поддержки printf, стека для каждого потока и кучи для ядра malloc / new звонки (см. этот ответ для получения дополнительной информации). Все это может занимать довольно много памяти, в результате чего после резервирования ECC, которое вы предполагаете быть доступным для своего кода, у вас будет намного меньше, чем максимальная доступная память. API также включает cudaDeviceGetLimit, который можно использовать для запроса объема памяти, который потребляется при поддержке устройства во время выполнения. Существует также сопутствующий вызов cudaDeviceSetLimit, который позволяет изменить объем памяти, который будет зарезервирован каждым компонентом поддержки времени выполнения.

Даже после того, как вы настроили объем оперативной памяти по своему вкусу и получили реальное значение свободной памяти от драйвера, все еще есть соображения по гранулярности и фрагментации размера страницы. Редко можно выделить каждый байт того, что API сообщит как бесплатное. Обычно я делаю что-то подобное, когда цель состоит в том, чтобы попытаться выделить каждый доступный байт на карте:

const size_t Mb = 1<<20; // Assuming a 1Mb page size here

size_t available, total;
cudaMemGetInfo(&available, &total);

int *buf_d = 0; 
size_t nwords = total / sizeof(int);
size_t words_per_Mb = Mb / sizeof(int);

while(cudaMalloc((void**)&buf_d,  nwords * sizeof(int)) == cudaErrorMemoryAllocation)
{
    nwords -= words_per_Mb;
    if( nwords  < words_per_Mb)
    {
        // signal no free memory
        break;
    }
}

// leaves int buf_d[nwords] on the device or signals no free memory

(примечание никогда не было рядом с компилятором, только безопасно для CUDA 3 или новее). Неявно предполагается, что ни один из очевидных источников проблем с большими распределениями не применим здесь (32-разрядная операционная система хоста, платформа Windows WDDM без включенного режима TCC, более старые известные проблемы с драйверами).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...