2015-03-02 2 views
1

Я прочитал в документации NVIDIA (http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications, таблица № 12), что количество локальной памяти на поток составляет 512 кодов для моего GPU (GTX 580, вычислительная способность 2.0).Количество локальной памяти в потоке CUDA

Я безуспешно пытался проверить этот лимит на Linux с помощью CUDA 6.5.

Вот код, который я использовал (его единственная цель состоит в том, чтобы проверить локальный предел памяти, он не делает никаких вычислений полезную):

#include <iostream> 
#include <stdio.h> 

#define MEMSIZE 65000 // 65000 -> out of memory, 60000 -> ok 

inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=false) 
{ 
    if (code != cudaSuccess) 
    { 
     fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line); 
     if(abort) 
      exit(code); 
    } 
} 

inline void gpuCheckKernelExecutionError(const char *file, int line) 
{ 
    gpuAssert(cudaPeekAtLastError(), file, line); 
    gpuAssert(cudaDeviceSynchronize(), file, line);  
} 


__global__ void kernel_test_private(char *output) 
{ 
    int c = blockIdx.x*blockDim.x + threadIdx.x; // absolute col 
    int r = blockIdx.y*blockDim.y + threadIdx.y; // absolute row 

    char tmp[MEMSIZE]; 
    for(int i = 0; i < MEMSIZE; i++) 
     tmp[i] = 4*r + c; // dummy computation in local mem 
    for(int i = 0; i < MEMSIZE; i++) 
     output[i] = tmp[i]; 
} 

int main(void) 
{ 
    printf("MEMSIZE=%d bytes.\n", MEMSIZE); 

    // allocate memory 
    char output[MEMSIZE]; 
    char *gpuOutput; 
    cudaMalloc((void**) &gpuOutput, MEMSIZE); 

    // run kernel 
    dim3 dimBlock(1, 1); 
    dim3 dimGrid(1, 1); 
    kernel_test_private<<<dimGrid, dimBlock>>>(gpuOutput); 
    gpuCheckKernelExecutionError(__FILE__, __LINE__); 

    // transfer data from GPU memory to CPU memory 
    cudaMemcpy(output, gpuOutput, MEMSIZE, cudaMemcpyDeviceToHost); 

    // release resources 
    cudaFree(gpuOutput); 
    cudaDeviceReset(); 

    return 0; 
} 

И команду компиляции строка:

nvcc -o cuda_test_private_memory -Xptxas -v -O2 --compiler-options -Wall cuda_test_private_memory.cu 

компиляция нормально, и отчеты:

ptxas info : 0 bytes gmem 
ptxas info : Compiling entry function '_Z19kernel_test_privatePc' for 'sm_20' 
ptxas info : Function properties for _Z19kernel_test_privatePc 
    65000 bytes stack frame, 0 bytes spill stores, 0 bytes spill loads 
ptxas info : Used 21 registers, 40 bytes cmem[0] 

я получил «из памяти» ошибка во время выполнения на GTX 580, когда я достиг 65000 байт на поток. Вот точный вывод программы в консоли:

MEMSIZE=65000 bytes. 
GPUassert: out of memory cuda_test_private_memory.cu 48 

я также сделал тест с GTX 770 GPU (на Linux с помощью CUDA 6.5). Он работал без ошибок для MEMSIZE = 200000, но ошибка «вне памяти» произошла во время выполнения для MEMSIZE = 250000.

Как это объяснить? Я делаю что-то неправильно ?

+1

версию CUDA вы используете? Это Linux или это окна? Вы получаете ошибку «из памяти», когда ** компилируете ** код или когда ** запускаете ** код? (вставьте точный текст ошибки в вопрос) Какую командную строку вы используете для компиляции кода?Я предполагаю, что вы компилируете для архитектуры pre-cc2.0. Если я скомпилирую этот код для архитектуры cc1.1, я получаю ошибку «из памяти» при компиляции, потому что устройства cc1.x имеют еще меньший предел для локальной памяти на поток (16 КБ). Если я компилирую для архитектуры cc2.0, ваш код компилируется и работает нормально для меня. –

+1

Ваша проблема также может возникать из этой строки кода: 'char output [MEMSIZE];' Этот (хост-код) создает распределение на основе стека, и эти типы распределений могут быть ограничены в зависимости от платформы. Вставка точного текста ошибки в вопрос поможет. (вы можете отредактировать свой вопрос.) –

+0

@RobertCrovella Спасибо за интерес к моему вопросу. Я редактировал свой вопрос, чтобы добавить недостающую информацию. Точный текст ошибки, о котором сообщает cudaGetErrorString() во время выполнения, является «вне памяти». – devel484

ответ

5

Кажется, вы работаете в не локальное ограничение памяти, но ограничение на размер стека:

ptxas информация: Функциональные свойства для _Z19kernel_test_privatePc

65000 байт стека кадра, 0 байт разливами магазины, 0 bytes spill load

Переменная, которую вы намеревались быть локальной, находится в стеке (GPU thread) в этом случае.

На основе информации, предоставленной @njuffa here, доступный предельный размер стека является меньшим из:

  1. Максимальный размер локальной памяти (512 Кбайт для cc2.x и выше) памяти
  2. GPU/(# OF SMs)/(максимальные потоки на SM)

Очевидно, что первое ограничение не является проблемой. Я предполагаю, что у вас есть «стандартный» GTX580, который имеет 1,5 ГБ памяти и 16 SM. Устройство cc2.x имеет максимум 1536 резидентных потоков на мультипроцессор. Это означает, что мы имеем 1536MB/16/1536 = 1MB/16 = 65536 байт. Существует некоторое накладное и другое использование памяти, которое вычитается из общей доступной памяти, поэтому ограничение размера стека составляет некоторую сумму ниже 65536, где-то между 60000 и 65000 в вашем случае, по-видимому.

Я подозреваю, подобный расчет на вашем GTX770 даст аналогичный результат, т.е. максимальный размер стека между 200000 и 250000.

+1

Благодарим вас за разъяснение. Я сделал те же вычисления для GTX 770 (4 ГБ ОЗУ, 8 SM, максимум 2048 потоков на SM) и получил размер стека 262144 байт. Это соответствует пределу, с которым я столкнулся на GTX 770 между 200000 байтами и 250000 байт (точнее между 242000 байтами и 245000 байтами). Я также заменил статическое распределение в ядре динамическим распределением с помощью malloc(): тогда я смог выделить 512 Ko локальной памяти (и даже больше, до 7 Mo!). – devel484

+0

, если вам требуется больше памяти, чем в ядре 'malloc', просмотрите [документацию] (http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#dynamic-global- memory-allocation-and-operations), чтобы увеличить ограничение распределения памяти кучи. –

+0

Хорошо. Я думал, что вызов in-kernel в 'malloc' будет выделять ** локальную ** память. Теперь я понимаю, что in-kernel 'malloc' выделяет глобальную кучу памяти, размер которой по умолчанию равен 8 Mo. – devel484

Смежные вопросы