Кажущаяся магия CUDA

Я использую CUDA (на самом деле я использую pyCUDA, если разница имеет значение) и выполняю некоторые вычисления над массивами. Я запускаю ядро ​​с сеткой из 320 * 600 потоков. Внутри ядра я объявляю два линейных массива из 20000 компонентов, используя:

float test[20000]
float test2[20000]

С этими массивами я выполняю простые вычисления, например, наполняя их постоянными значениями. Дело в том, что ядро работает нормально а также правильно выполнять вычисления (Вы можете видеть это, заполняя массив случайным компонентом теста и отправляя этот массив на хост с устройства).

Проблема в том, что моя карта NVIDIA имеет только 2 ГБ памяти, а общий объем памяти для выделения массивов test и test2 составляет 320 * 600 * 20000 * 4 байта, что намного больше, чем 2 ГБ.

Откуда эта память? и как CUDA может выполнять вычисления в каждом потоке?

Спасибо за ваше время

0

Решение

Фактический размер требований к локальной / стековой памяти не такой, как вы предполагаете (для всей сетки, все сразу), но на самом деле основан на формуле, описанной @njuffa Вот.

По сути, размер локальной / стековой памяти определяется в зависимости от максимальной мгновенной емкости устройства, на котором вы работаете, а не от размера сетки.

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

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

Для вашего первого случая:

float test[20000];
float test2[20000];

Общая сумма составляет 160 КБ (на поток), поэтому максимальный предел составляет 512 КБ на поток. Как насчет 2-го лимита?

GTX 650м имеет 2 SM cc 3.0 (kepler) (каждый Kepler SM имеет 192 ядра). Следовательно, второй предел выше дает, если все память GPU была имеется в наличии:

2 ГБ / 2/2048 = 512 КБ

(Кеплер имеет Максимум 2048 потоков на мультипроцессор)
так что это тот же предел в этом случае. Но это предполагает, что вся память GPU доступна.

Так как вы предлагаете в комментариях, что эта конфигурация терпит неудачу:

float test[40000];
float test2[40000];

т. е. 320 КБ, я бы пришел к выводу, что ваша фактическая доступная память графического процессора находится в точке этой попытки массового выделения где-то выше (160/512) * 100%, т.е. выше 31%, но ниже (320/512) * 100%, т.е. ниже 62,5% 2 ГБ, поэтому я бы пришел к выводу, что ваша доступная память графического процессора на момент запроса массового выделения для стекового кадра будет меньше, чем 1,25 ГБ.

Вы можете попытаться выяснить, так ли это, позвонив cudaGetMemInfo прямо перед запуском ядра (хотя я не знаю, как это сделать в Pycuda). Даже если ваш графический процессор начинается с 2 ГБ, если вы используете дисплей с него, вы, скорее всего, начинаете с цифры, близкой к 1,5 ГБ. И динамический (например, cudaMalloc) или статический (например, __device__) распределения, которые происходят до этого запроса массового выделения при запуске ядра, будут влиять на доступную память.

Это все, чтобы объяснить некоторые особенности. Общий ответ на ваш вопрос заключается в том, что «волшебство» возникает из-за того, что GPU не обязательно выделяет кадр стека и локальную память для всех потоков в сетке, все сразу. Нужно только выделить то, что требуется для максимальная мгновенная емкость устройства (то есть SMs * max потоков на SM), которое может быть числом, которое значительно меньше, чем то, что потребуется для всей сетки.

4

Другие решения


По вопросам рекламы [email protected]