Объекты памяти в OS X OpenCL
OpenCL использует память по-другому, чем стандартные программы. Эта глава представляет буферы памяти и изображения, поскольку они используются приложениями OpenCL. Посмотрите Создание и Управление Объектами изображения В OpenCL и Создании и Управлении Буферными Объектами В OpenCL для специфических особенностей об управлении видеопамятью и буферной памятью соответственно.
Посмотрите Используя IOSurfaces С OpenCL для специфических особенностей об использовании IOSurfaces с OpenCL.
Обзор
Как все вычислительные процессы, процессы, работающие на устройствах OpenCL, состоят из:
-
Данные
Данные, к которым получают доступ инструкции OpenCL, существуют как
cl_image
объекты памяти и буферы памяти. Используйте объекты изображения для представления два - или трехмерные изображения (см. Создание и Управление Объектами изображения В OpenCL). Используйте буферные объекты содержать другие типы универсальных данных (см. Создание и Управление Буферными Объектами В OpenCL). -
Инструкции в программе OpenCL, управляющие данными.
Для многих устройств (таких как GPUs), память OpenCL помещена в корпус в физически отличном куске кремния. Для других устройств память устройства находится физически на той же микросхеме. Независимо от его физического расположения память устройства может только быть считана и записана кодом ядра OpenCL, и память хоста может только быть считана и записана узлом.
Другими словами, даже если узел и память OpenCL физически непрерывны, память хоста отлична от памяти OpenCL. Ядра могут только получить доступ к данным в памяти устройств OpenCL. Главный компьютер может читать и записать в память устройства, но только устанавливать его и получать результаты. Во время вычисления устройство выглядит только в памяти устройства, и узел остается вне своего пути.
Когда данные были переданы ядру узлом, данные находятся на устройстве OpenCL во время выполнения. Ядро не может читать или записать в память хоста; это может только получить доступ к данным в собственной отдельной области памяти устройства.
Видимость памяти
В типичной среде мультиустройства память распределяется между устройствами. Никакое устройство не может получить доступ ко всей памяти. Рисунок 7-1 иллюстрирует пространства памяти в системе OpenCL. Каждое пространство памяти имеет различную видимость к узлу и ядру.
-
Частная память является памятью, к которой может только получить доступ одна единица работы.
Узел не имеет никакой возможности считать или записать частную память, ни могут другие единицы работы.
-
Локальная память является памятью, которую могут совместно использовать единицы работы в рабочей группе. Если больше чем одна единица работы в группе должна получить доступ к определенному блоку глобальной памяти, локальная память полезна. Можно записать программу OpenCL так, чтобы одна единица работы загрузила данные с глобальной памяти на локальную память; остальная часть единиц работы, которым нужна та часть данных, может тогда получить доступ к локальной копии.
Устройствам GPU требуется намного меньше времени для доступа к локальной памяти, чем к глобальной памяти доступа. Узел не имеет никакой возможности считать или записать локальную память.
-
Глобальная память является (относительно) крупным блоком памяти устройства, которую могут «видеть» все единицы работы. Любая единица работы может чтение-запись к буферу, который, как объявляют, был в глобальной памяти.
Узел может также читать и записать в глобальную память.
-
Постоянная память является специализированным разделом глобальной памяти, используемой для данных, которые Вы знаете, не изменится в течение выполнения Вашего ядра. Это обычно более ограничено в размере, чем другие типы глобальной памяти, но быстрее к доступу на многих устройствах, чем другая глобальная память.
Узел может читать и записать в постоянную память.
Например, ядро OpenCL выполняется на отдельном пространстве памяти от узла, вызывающего его. Для ядра для доступа к данным это должно обработать, данные должны быть перемещены в память устройства. Однако передача данных между областями памяти, чтобы позволить различным устройствам работать может привести к значительным издержкам. Для оптимизации производительности минимизируйте переданный объем данных.
Узел указывает пространство памяти для данного буфера, когда это объявляет каждый параметр ядра.
Непротиворечивость памяти
Изменяется единица работы сделала к глобальной или локальной памяти, может не сразу стать видимым к другим единицам работы в рабочей группе. Непротиворечивость системы говорит Вам, когда изменения, которые единица работы внесла в глобальную или локальную память, становятся видимыми к другим единицам работы в рабочей группе.
OpenCL использует то, что вызывают расслабленной моделью непротиворечивости памяти, что означает что:
-
Единицы работы могут получить доступ к данным в своих собственных частных, локальных, постоянных пробелах, и глобальной памяти.
-
Единицы работы могут совместно использовать локальную память во время выполнения рабочей группы. Однако память, как только гарантируют, будет непротиворечивой после определенных точек синхронизации.
Если единица работы должна считать что-то, что записала другая единица работы, вызовите барьер встроенная функция в Вашем коде ядра OpenCL в точке, где Вы хотите, чтобы память была непротиворечивой:
barrier(CLK_LOCAL_MEM_FENCE);
barrier(CLK_GLOBAL_MEM_FENCE);
barrier(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);
Барьер остановит любую единицу работы в точке, где это вызывает барьер, пока не «нагнали» все другие единицы работы. Вот почему это работает: каждая единица работы в рабочей группе записала свою память к тому времени, когда это достигает барьера, таким образом, можно безопасно считать что-либо, что любая единица работы в группе записала.
Поток операций управления памятью
Рисунок 7-2 иллюстрирует поток операций управления основной памятью в OpenCL.
Поток операций основной памяти с OpenCL:
-
Узел создает объекты памяти для использования OpenCL.
Узел запрашивает, чтобы память была обойдена для него на устройстве. Узел может попросить столько объектов памяти, сколько он хочет и получает их, пока существует доступная память. Можно создать отдельные объекты памяти для ввода и вывода, но это не требование. Единственный буферный объект мог использоваться для обоих вводов и выводов, если это целесообразно для Вашего алгоритма. Изображения, однако, более ограничиваются. Изображение может использоваться для любого ввода или вывода в ядре, но не обоих сразу.
-
Узел инициализирует содержание объектов памяти.
Узел может передать данные устройству, которое будет сохранено в его объектах памяти. Это - данные, которые могут быть обработаны ядром. Узел может также сообщить, что устройство для отъезда некоторых объектов памяти деинициализировало так, чтобы, когда ядро работает на устройстве, это могло заполнить эти объекты памяти выводом.
Узел дает устройству команду выполнять ядро, передавая его, память возражает, что это создало на устройстве OpenCL как параметры. В то время как ядро работает, но продолжает выполнять другую работу, узел не ожидает.
-
Ядро работает на устройстве, обрабатывая данные, производя вывод.
-
Чтения узла следуют из объектов памяти.
Когда узел обнаруживает, что ядро выполнило свои задачи, это копирует результаты памяти ядра в память, к которой может получить доступ узел.
-
Узел уничтожает объекты памяти.
Как только все ядра, которым нужны объекты памяти, были выполнены, узел дает устройству команду высвобождать память, которую это отложило для ядра для использования. Например, в сценарии, где один буфер привык для ввода ко многим ядрам, каждое из которых работает много раз, код узла освобождает память, когда каждое выполнение ядра, для которого был нужен тот объект памяти, ставилось в очередь. Можно указать финализатор для объектов. Финализатор вызовет сборщик «мусора», когда это уничтожит объект. Посмотрите Установку финализатора.
Установка финализатора
Можно указать финализатор, функциональный элемент класса ссылки, который вызывает автоматически сборщик «мусора» при уничтожении объекта. Указать финализатор, который OpenCL вызовет когда память, указанная object
параметр должен быть освобожден, вызвать:
void gcl_set_finalizer(void *object, |
void (*gcl_pfn_finalizer)(void *object, void *user_data), |
void *user_data); |
Параметр |
Описание |
---|---|
|
Буферная память или видеопамять возражают, к которому должен быть присоединен финализатор. |
|
Функция обратного вызова, которая будет выполняться сборщиком «мусора», когда это уничтожит указанное
|
| |
|
Перечисление 7-1 является примером того, как Вы использовали бы gcl_set_finalizer
функция.
Перечисление 7-1 Используя gcl_set_finalizer
// This is the finalizer function you want OpenCL to call when the object is freed. |
void my_finalizer(void* memObj, // This is a pointer to the object whose |
// destruction triggered calling of this |
// finalizer. |
void* importantData // Pointer to data the finalizer will use. |
) |
{ |
// do something with memObj |
// do something with importantData |
} |
... |
void main() { |
// Do stuff ... |
void* my_mem_object = gcl_malloc(128, NULL, 0); // GCL memory object |
struct foo *special_data = |
(struct foo*)malloc(sizeof(struct foo)); // Some program-specific data |
// Specify your finalizer callback. |
gcl_set_finalizer(my_mem_object, // Call the finalizer function when |
// my_mem_object is about to be freed. |
my_finalizer, // In particular, call the my_finalizer function |
// when my_my_object is about to be freed. |
special_data // Pass this special_data to the my_finalizer |
// function before my_mem_object is freed. |
); |
// Do more stuff ... |
// ... |
// and then, at some point, free the my_mem_object. |
gcl_free(my_mem_object); // Before the my_mem_object object is actually freed, |
// OpenCL will call my_finalizer, and pass it |
// my_mem_object and special_data. |
} |
Параметры, описывающие изображения и буферы в OS X OpenCL
Несколько функций, управляющих изображениями и буферами в OpenCL API, принимают источник, область и параметры шага строки.
На рисунке 7-3 память, содержащая изображение, представлена чередуемым прямоугольником, ограниченным шириной и высотой, и включает область существенного цвета в свой центр. Область (представленный существенным розовым прямоугольником, ограниченным шириной области и высотой области), указывает форму и размер части изображения, которым Вы хотите управлять. Другими словами, область является просто определенной суммой памяти, живущей при данном смещении (или источник) в изображение. Источник (x, y, z) позиция области в изображении.
Шаг строки является шириной области получения. Шаг строки является длиной в байтах в одной строке изображения. Обычно, шаг строки равен ширине в пикселях времен изображения размер каждого пикселя в байтах. Но иногда, по причинам производительности, это помогает использовать большую область памяти для хранения изображения, чем строго необходимо. Это проиллюстрировано на рисунке 7-3, где шаг строки немного больше, чем ширина изображения. Например, если бы изображение было 1 000 пикселей шириной, и каждый пиксель составлял 4 байта, то Ваш row_pitch составил бы 4 000 байтов. Но могло бы быть более эффективно для аппаратных средств обработать 4 096 байтов за строку, когда Вы могли указать row_pitch
параметр как 4096
.
slice_pitch параметр использовал в некотором OpenCL многомерные буферные функции манипулирования такой как gcl_memcpy_rect
(см. Создание и Управление Буферными Объектами В OpenCL), размер в байтах 2D части, формирующей один уровень 3D изображения. Другими словами, подача части является числом байтов в шаге строки, умноженном на число байтов в высоте изображения. Установите slice_pitch
параметр к 0
если изображение является двумерным.
Значение подачи части должно быть больше, чем или равным шагу строки, умноженному на высоту. Если Вы указываете slice_pitch
параметр как 0
, OpenCL вычисляет надлежащую подачу части, чтобы быть шагом строки, умноженным на высоту.