В чем разница между общей и глобальной памятью CUDA?

я путаюсь в том, как использовать общую и глобальную память в CUDA, особенно в отношении следующего:

  • при использовании cudaMalloc(), мы получим указатель на общий или глобальный память?
  • глобальная память находится на хосте или устройстве?
  • есть ограничение размера для любого из них?
  • что быстрее для доступа?
  • - хранение переменная в общей памяти такая же, как передача ее адреса через ядро? Т. е. вместо

    __global__ void kernel() {
       __shared__ int i;
       foo(i);
    }
    

    почему бы не сделать то же самое

    __global__ void kernel(int *i_ptr) {
       foo(*i_ptr);
    }
    
    int main() {
       int *i_ptr;
       cudaMalloc(&i_ptr, sizeof(int));
       kernel<<<blocks,threads>>>(i_ptr);
    }
    

было много вопросов о конкретных проблемах скорости в глобальной vs общей памяти, но ни один из них не охватывает обзор того, когда использовать любой из них на практике.

большое спасибо

3 ответов


  • когда мы используем cudaMalloc()

    для хранения данных на gpu, которые могут быть переданы обратно на хост, нам нужно иметь выделенную память, которая живет, пока она не будет освобождена, см. глобальную память как пространство кучи с жизнью, пока приложение не закроется или не будет освобождено, оно видно любому потоку и блоку, которые имеют указатель на эту область памяти. Общую память можно рассматривать как пространство стека со сроком службы до завершения блока ядра, видимость ограничена только для потоков внутри одного блока. Так cudaMalloc используется для выделения пространства в глобальной памяти.

  • получаем ли мы указатель на общую или глобальную память?

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

  • глобальная память находится на хосте или устройстве?

    глобальная память находится на устройстве. Однако есть способы использовать память хоста как "глобальную" память с использованием сопоставленной памяти, см.: CUDA нулевая копия памяти соображения однако это может быть медленная скорость из-за ограничений скорости передачи шины.

  • существует ли ограничение размера для любого из них?

    размер глобальной памяти зависит от карты на карту, ничего от none до 8GB. В то время как общая память зависит от вычислительной способности. Все, что ниже вычислительной способности 2.X имеет максимум 16 КБ общей памяти в многопроцессорных(где количество мультипроцессоров варьируется от карта к карте). И карты с вычислительной способностью 2.x и выше имеют максимум 48 КБ общей памяти на мультипроцессор.

    Если вы используете сопоставленную память, единственным ограничением является то, сколько хост-машина имеет в памяти.

  • что быстрее для доступа?

    С точки зрения необработанных чисел, общая память намного быстрее (общая память ~1.7 ТБ/с, а глобальная память ~ 150 Гбит/с). Тем не менее, для того, чтобы сделать все, что вам нужно, чтобы заполнить общий памяти с чем-то, вы обычно тянете из глобальной памяти. Если доступ к глобальной памяти объединен (неслучайно), вы получите скорость до 150-200GB/s в зависимости от карты и ее интерфейса памяти.

    использование общей памяти-это когда вам нужно в блоке потоков повторно использовать данные, уже извлеченные или оцененные из глобальной памяти. Поэтому вместо того, чтобы снова вытаскивать из глобальной памяти, вы помещаете ее в общую память для других потоков в том же блоке, чтобы видеть и повторное использование.

  • сохраняет ли переменная в общей памяти то же самое, что и передача ее адреса через ядро?

    нет, если вы передаете адрес чего-либо, это всегда адрес глобальной памяти. С хоста вы не можете установить общую память, если вы не передадите ее либо как константу, где ядро устанавливает общую память на эту константу, либо передадите ей адрес в глобальную память, где она будет вытягиваться ядром, когда это необходимо.


содержимое глобальной памяти отображается для всех потоков сетки. Любой поток может читать и записывать в любое место глобальной памяти.

общая память является отдельной для каждого блока сетки. Любой поток блока может читать и записывать в общую память этого блока. Нить в одном блоке не может получить доступ к общей памяти другого блока.

  1. cudaMalloc всегда выделяет глобальную память.
  2. глобальная память находится на устройство.
  3. очевидно, что каждая память имеет ограничение на размер. Глобальная память-это общий объем DRAM используемого GPU. e.g я использую GTX460M, который имеет 1536 MB DRAM, поэтому 1536 MB глобальной памяти. Общая память определяется архитектурой устройства и измеряется на основе каждого блока. Устройства вычислительной способности 1.0-1.3 имеют 16 KB/Block, вычислить 2.0 до 7.0 есть 48 KB/Block общая память.
  4. общая память порядков быстрее, чем к глобальной памяти. Свой как локальный кэш, разделяемый между потоками блока.
  5. нет. Только глобальные адреса памяти могут быть переданы ядру, запущенному с хоста. В первом примере переменная считывается из общей памяти, а во втором-из глобальной памяти.

обновление:

устройства вычислительной мощности 7.0 (Volta Architecture) позволяют распределять общую память до 96 КБ на блок при условии выполнения следующих условий довольны.

  • общая память выделяется динамически
  • перед запуском ядра указывается максимальный размер динамической общей памяти с помощью функции cudaFuncSetAttribute следующим образом.

__global__ void MyKernel(...)
{
    extern __shared__ float shMem[];
}

int bytes = 98304; //96 KB
cudaFuncSetAttribute(MyKernel, cudaFuncAttributeMaxDynamicSharedMemorySize, bytes);

MyKernel<<<gridSize, blockSize, bytes>>>(...);

CUDA shared memory-это память, разделяемая между потоками внутри блока, т. е. между блоками в сетке содержимое общей памяти не определено. Его можно рассматривать как управляемый вручную кэш L2.

обычно глобальная память находится на устройстве, но последние версии CUDA (если устройство поддерживает его) могут отображать память хоста в адресное пространство устройства, вызывая передачу in-situ DMA от хоста к памяти устройства в таких случаях.

существует ограничение по размеру общая память, в зависимости от устройства. Его сообщили в возможностях устройства, полученных при перечислении устройств CUDA. Глобальная память ограничена общей памятью, доступной GPU. Например, GTX680 предлагает 48kiB общей памяти и 2gib памяти устройства.

доступ к общей памяти быстрее, чем к глобальной памяти, но шаблоны доступа должны быть тщательно выровнены (как для общей, так и для глобальной памяти), чтобы быть эффективными. Если вы не можете правильно выровнять шаблоны доступа, используйте текстуры (также глобальная память, но доступ через другую окружность и кэш, который может иметь дело лучше с не выровненным доступом).

сохраняет ли переменную в общей памяти так же, как передает ее адрес через ядро?

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