
Лекции / Лекция 14
.docТехнологии и методы программирования. Лекция 14.
Структура процесса разработки программ по стандарту OpenCL. Платформонезависимое программирование.
Этапы:
-
Разработка ядер. OpenCL основан на синтаксисе С и С++ с поддержкой параллельных вычислений. Программа может храниться в отдельном файле, определяться как константа типа строки или даже формироваться во время исполнения динамически.
Пример:
_const char *source=”_kernel void square (_global gloat *input, _global float *output, _const unsigned int count) {
int i=get_global_id(0); - определяем глобальный идентификатор элемента.
if (i<count){
output[i]=input[i]*input[i];
}
}
где kernel — спецификатор, void тип значения, _global — спецификатор данных.
-
Запрос доступных платформ и устройств. В рамках одной системы может быть несколько реализаций OpenCL, представляемых драйверами. Управляющее приложение должно выбрать наилучшую платформу для данной задачи.
cl_uint numplatform=0;
cl_Get_PlatformIdS(0, NULL, &numPlatforms); - получаем список платформ
cl_platform_id.platform=NULL;
if (0<numPlatforms){
cl_platform_id *platform=new cl_platform_id[numPlatform];
cl_Get_Platform(numplatforms, platforms, NULL); - заполняем массив платформ их идентификаторами.
platform=platforms[0]; - берём первую же платформу
delete []platforms; - а остальные удаляем.
Для выбора платформы нужно создать контекст и выбрать устройство. Эти действия начинаются с определения свойств контекста:
cl_context_properties props[s]=
{CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0}
Создаём контекст с этими свойствами:
cl_context context =clCreattteContextFromType(props, CL_DEVICE_TYPE_BPU, NULL, NULL, NULL);
Получаем список всех устройств в контексте:
size_t size=0;
cl_LetContextInfo(context, CL_CONTEXT_DEVICE, 0, NULL, &size);
cl_device device;
if (size>0){
cl_device_id *device = (cl_device_id *)allocal(size);
cl_LetContextInfo(context, CL_CONTEXT_DEVICE, size, device, NULL);
device = device[0];
}
-
Создание очереди команд.
Очередь команд реализует направление команд на устройство для выполнения итераций. Можно создать несколько очередей, и выполнять параллельно на разных устройствах.
cl_command_queue queue = clCreateQueue(context, device, 0, NULL);
4) Создание программного объекта - «типа данных», инкапсулирующего исходный код, исполняемый файл, параметры компиляции, журнал сообщений об ошибках и список устройств. Он может быть создан из исходного кода и скомпилирован при выполнении программы.
size_t strlen[] = {strlen(source)};
cl_program program = clCreateProgramWithSource(context, 1, &source, strlen, NULL);
cl_BuiltProgram(program 1, &device, NULL, NULL, NULL);
5) Создание объекта ядер — то есть объекта, инкапсулирующего ядро и аргументы.
cl_kernel kernel = clCreateKernel(program, “scmare”, NULL);
6) Инициализация данных и создание объектов в памяти. Объекты в памяти — указатели на области памяти в глобальном пространстве памяти устройства. Используются для ввода/вывода: для передачи чего-либо в ядро это надо упаковать в объект памяти. Существует два типа таких объектов: буферы (для вычисления) и изображения (как текстурная память в CUDA).
Float data[size];
float result[size];
cl_mem_input=clCreateBuffer(context, CL_MEM_READ_ONLY, sizeof(float),*size, NULL, NULL);
cl_mem_output=clCreateBuffer(context, CL_MEM_WRITE, sizeof(float)*size, NULL, NULL);