OpenCL Создание буфера

Я довольно новичок в OpenCL и, хотя я все понял до сих пор, но мне трудно понять, как работают буферные объекты.

Я не понял, где хранится буферный объект. В этом вопросе Stackru указано, что:

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

Для меня это означает, что объекты буфера хранятся в памяти устройства. Однако, как указано в этом вопросе Stackru, если флаг CL_MEM_ALLOC_HOST_PTR используется в clCreateBufferиспользуемая память, скорее всего, будет закреплена. Насколько я понимаю, когда память закреплена, она не будет выгружена. Это означает, что закрепленная память ДОЛЖНА быть расположена в ОЗУ, а не в памяти устройства.

Так что же на самом деле происходит?

Что бы я хотел знать, что делают флаги:

  • CL_MEM_USE_HOST_PTR
  • CL_MEM_COPY_HOST_PTR
  • CL_MEM_ALLOC_HOST_PTR

подразумевать о расположении буфера.

Спасибо

2 ответа

Решение

Спецификация (намеренно?) Неопределенна по теме, оставляя большую свободу для разработчиков. Поэтому, если реализация OpenCL, на которую вы нацелены, не дает явных гарантий для флагов, вы должны рассматривать их как рекомендации.

Прежде всего, CL_MEM_COPY_HOST_PTR на самом деле не имеет ничего общего с распределением, это просто означает, что вы хотели бы clCreateBuffer предварительно заполнить выделенную память содержимым памяти на host_ptr Вы перешли на звонок. Это как если бы вы позвонили clCreateBuffer с host_ptr = NULL и без этого флага, а затем сделал блокировку clEnqueueWriteBuffer позвоните, чтобы написать весь буфер.

Что касается режимов распределения:

  • CL_MEM_USE_HOST_PTR - это означает, что вы предварительно распределили некоторую память, правильно выровняли и хотели бы использовать это в качестве резервной памяти для буфера. Реализация все еще может распределять память устройства и копировать туда и обратно между вашим буфером и выделенной памятью, если устройство не поддерживает прямой доступ к памяти хоста, или если драйвер решает, что теневое копирование в VRAM будет более эффективным, чем прямой доступ к системе объем памяти. В реализациях, которые могут считывать данные напрямую из системной памяти, это один из вариантов для буферов нулевого копирования.
  • CL_MEM_ALLOC_HOST_PTR - Это подсказка, чтобы сообщить реализации OpenCL, что вы планируете получить доступ к буферу со стороны хоста, сопоставив его с адресным пространством хоста, но в отличие от CL_MEM_USE_HOST_PTR вы оставляете само выделение для реализации OpenCL. Для реализаций, которые его поддерживают, это еще одна опция для нулевых буферов копирования: создайте буфер, сопоставьте его с хостом, получите алгоритм хоста или ввод / вывод для записи в отображенную память, затем снимите карту и используйте ее в ядре GPU, В отличие от CL_MEM_USE_HOST_PTR это оставляет дверь открытой для использования VRAM, который может быть сопоставлен непосредственно с адресным пространством ЦП (например, PCIe BAR).
  • По умолчанию (ни один из вышеперечисленных 2): выделите, где это наиболее удобно для устройства. Обычно VRAM, и если отображение памяти в память хоста не поддерживается устройством, это обычно означает, что если вы отобразите его в адресное пространство хоста, у вас получится 2 копии буфера, одна в VRAM и одна в системной памяти, в то время как реализация OpenCL внутренне копирует туда и обратно между 2.

Обратите внимание, что реализация может также использовать любые предоставленные флаги доступа (CL_MEM_HOST_WRITE_ONLY, CL_MEM_HOST_READ_ONLY, CL_MEM_HOST_NO_ACCESS, CL_MEM_WRITE_ONLY, CL_MEM_READ_ONLY, а также CL_MEM_READ_WRITE) влиять на решение, где выделить память.

Наконец, что касается "закрепленной" памяти: многие современные системы имеют IOMMU, и когда он активен, доступ к системной памяти с устройств может вызвать сбои страниц IOMMU, поэтому технически память хоста даже не должна быть резидентной. В любом случае реализация OpenCL обычно глубоко интегрирована с драйвером устройства уровня ядра, который обычно может фиксировать диапазоны системной памяти (исключая их из подкачки) по требованию. Так что если использовать CL_MEM_USE_HOST_PTR вам просто нужно убедиться, что вы предоставили должным образом выровненную память, а реализация позаботится о закреплении за вами.

Давайте сначала посмотрим на сигнатуру clCreateBuffer:

cl_mem clCreateBuffer(
    cl_context context,
    cl_mem_flags flags,
    size_t size,
    void *host_ptr,
    cl_int *errcode_ret)

Здесь нет аргумента, который бы предоставил среде выполнения OpenCL точное устройство, в память которого должен быть помещен буфер, поскольку контекст может иметь несколько устройств. Среда выполнения знает только, как только мы используем буферный объект, например, для чтения / записи из / в него, так как эти операции нуждаются в очереди команд, которая связана с конкретным устройством.

Каждый объект памяти находится либо в памяти хоста, либо в памяти устройства контекста, и среда выполнения может переносить его по мере необходимости. Таким образом, в общем, каждый объект памяти может иметь часть внутренней памяти хоста в среде выполнения OpenCL. На самом деле среда выполнения зависит от реализации, поэтому мы не можем не делать слишком много предположений и не получить переносимых гарантий. Это означает, что все о закреплении и т. Д. Зависит от реализации, и вы можете только надеяться на лучшее, но избегайте шаблонов, которые определенно предотвратят использование закрепленной памяти.

Почему мы хотим закрепить память? Прикрепленная память означает, что виртуальный адрес нашей страницы памяти в адресном пространстве нашего процесса имеет фиксированный перевод в адрес физической памяти ОЗУ. Это обеспечивает передачу данных DMA (прямой доступ к памяти) (которые работают по физическим адресам) между памятью устройства графического процессора и памятью процессора с использованием PCIe. DMA снижает нагрузку на процессор и, возможно, увеличивает скорость копирования. Поэтому мы хотим, чтобы внутреннее хранилище хоста наших объектов памяти OpenCL было закреплено, чтобы повысить производительность передачи данных между внутренним хранилищем хоста и памятью устройства объекта памяти OpenCL.

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

CL_MEM_USE_HOST_PTR

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

CL_MEM_ALLOC_HOST_PTR

Мы говорим среде выполнения выделить память хоста для объекта. Это может быть закреплено.

CL_MEM_COPY_HOST_PTR

Мы предоставляем хост-память для копирования-инициализации нашего буфера, а не для его внутреннего использования. Мы также можем объединить это с CL_MEM_ALLOC_HOST_PTR, Среда выполнения выделит память для внутреннего хранилища хоста. Это может быть закреплено.

Надеюсь, это поможет.

Другие вопросы по тегам