Лучше или то же самое: CPU memcpy () против устройства cudaMemcpy () на закрепленной, отображенной памяти в CUDA?

У меня есть:

  • Память хоста, которая была успешно закреплена и отображена с помощью cudaHostAlloc(..., cudaHostAllocMapped) или cudaHostRegister(..., cudaHostRegisterMapped);
  • Указатели устройств были получены с использованием cudaHostGetDevicePointer(...).

Я инициирую cudaMemcpy(..., cudaMemcpyDeviceToDevice) на указателях устройств src и dest, которые указывают на две разные области закрепленной + отображаемой памяти, полученной с помощью описанной выше техники. Все нормально работает.

Вопрос: следует ли мне продолжать это делать или просто использовать традиционный стиль ЦП memcpy(), поскольку все равно все находится в системной памяти? ... или они одинаковы (т.е. cudaMemcpy отображается на прямой memcpy, когда оба src и dest закреплены)?

(Я все еще использую метод cudaMemcpy, потому что раньше все было в глобальной памяти устройства, но с тех пор переключился на закрепленную память из-за ограничений размера gmem)


person mikepcw    schedule 17.09.2012    source источник
comment
Это интересный вопрос. Если вы используете оптимизированный memcpy, ЦП, вероятно, лучше - в конце концов, память принадлежит ему - а способность дискретного графического процессора выполнять memcpy хоста ограничена пропускной способностью PCIe. Но если в противном случае графический процессор простаивал бы, почему бы и нет?   -  person ArchaeaSoftware    schedule 18.09.2012
comment
Я надеюсь, что графический процессор не будет копировать. Я надеюсь, что среда выполнения увидит, что указатели являются как указателями хоста, так и вызовут хост memcpy. Я попросил узнать, что происходит на самом деле.   -  person harrism    schedule 18.09.2012


Ответы (2)


С cudaMemcpy драйвер CUDA обнаруживает, что вы копируете указатель хоста на указатель хоста, и копирование выполняется на CPU. Вы, конечно, можете сами использовать memcpy на процессоре, если хотите.

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

В системе UVA вы можете просто использовать cudaMemcpyDefault, как говорит талонми в своем ответе. Но если у вас нет UVA (sm_20 + и 64-битная ОС), вам нужно вызвать правильную копию (например, cudaMemcpyDeviceToDevice). Если вы cudaHostRegister() все, что вас интересует, cudaMemcpyDeviceToDevice в конечном итоге сделает следующее в зависимости от того, где расположена память:

  • Хост ‹-> Хост: выполняется ЦП (memcpy)
  • Хост ‹-> Устройство: DMA (механизм копирования устройства)
  • Устройство ‹-> Устройство: ядро ​​Memcpy CUDA (работает на SM, запускается драйвером)
person harrism    schedule 18.09.2012
comment
очень интересно, у вас есть какой-нибудь источник, где вы нашли информацию? - person chris-kuhr; 02.06.2017
comment
Кажется, я спросил у своих коллег из NVIDIA подробности реализации. - person harrism; 07.06.2017

Если вы работаете на платформе с UVA (унифицированная виртуальная адресация), я настоятельно рекомендую использовать cudaMemcpy с cudaMemcpyDefault. Таким образом, вся эта борьба за самый быстрый путь становится внутренней деталью реализации API, о которой вам не нужно беспокоиться.

person talonmies    schedule 17.09.2012
comment
Да и нет, я часто работаю на C1060, но имею доступ к C2050 / 70's. Так что насчет моего вопроса о закрепленной памяти - знаете ли вы, что cudaMemcpyDefault делает за кулисами в этом случае? Это в значительной степени ответит на вопрос. - person mikepcw; 17.09.2012
comment
Я не работаю на NVIDIA, поэтому я не видел никакого кода, но, похоже, посмотрите на указатели источника и назначения и соответственно. Вы получите копию на стороне хоста с указателем хоста и копию устройства на устройство с указателем устройства. - person talonmies; 17.09.2012