Как использовать шаблоны С++ в ядрах OpenCL?

Я новичок в OpenCL.

У меня есть алгоритм, который использует шаблоны. Он хорошо работал с OpenMP-распараллеливанием, но теперь количество данных выросло, и единственный способ его обработки - переписать его для использования OpenCL. Я могу легко использовать MPI для его сборки для кластера, но графический процессор, подобный Tesla, намного дешевле, чем кластер:)

Можно ли использовать шаблоны С++ в ядре OpenCL?

Возможно ли каким-то образом расширить шаблоны с помощью компилятора С++ или какого-то инструмента, и после этого использовать так изменив функцию ядра?

ИЗМЕНИТЬ. Идея обходного пути заключается в том, чтобы каким-то образом создать C99-совместимый код из кода С++ из шаблона.

Я нашел следующее о Комо:

Comeau С++ 4.3.3 - это полный и истинный компилятор, который выполняет полную проверку синтаксиса, полную семантическую проверку, полную проверку ошибок и все другие обязанности компилятора. Код ввода С++ преобразуется во внутренние деревья компилятора и таблицы символов, не похожий на С++ или C. Кроме того, он генерирует внутреннюю проприетарную промежуточную форму. Но вместо использования запатентованного генератора кода конца кода, Comeau С++ 4.3.3 генерирует C-код в качестве своего вывода. Помимо технических преимуществ С++, C-генерирующие аспекты продуктов, таких как Comeau С++ 4.3.3, были рекламированы как причина успеха С++, поскольку его удалось привлечь на большое количество платформ из-за общей доступности компиляторов C.

Компилятор C используется просто и только ради получения собственной генерации кода. Это означает, что Comeau С++ предназначен для использования с конкретными компиляторами C на каждой соответствующей платформе. Обратите внимание, что это требование, которое должен выполнять пошив. В противном случае сгенерированный код C бессмыслен, поскольку он привязан к определенной платформе (где платформа включает в себя, по крайней мере, компилятор CPU, OS и C), и, кроме того, сгенерированный код C не является автономным. Поэтому он не может использоваться сам по себе (обратите внимание, что это и техническое и юридическое требование при использовании Comeau С++), и именно поэтому обычно нет возможности увидеть сгенерированный код C: он почти всегда бесполезен и процесс компиляции, включая его создание, следует рассматривать как внутренние этапы перевода.

Ответы

Ответ 1

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

Вот хорошее объяснение: http://arnold.uthar.net/index.php?n=Work.TemplatesC

Он по-прежнему намного более грязный, чем шаблоны С++: код должен быть разделен на несколько частей, и вам нужно явно создать экземпляр каждого экземпляра шаблона. Кроме того, кажется, что вы не можете делать некоторые полезные вещи, такие как реализация факториала в качестве рекурсивного шаблона.

Пример кода

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

Прежде всего нам нужен вспомогательный заголовок ( "templates.h" ):

#ifndef TEMPLATES_H_
#define TEMPLATES_H_

#define CAT(X,Y,Z) X##_##Y##_##Z   //concatenate words
#define TEMPLATE(X,Y,Z) CAT(X,Y,Z)

#endif

Затем мы пишем функцию шаблона в "NewtonRaphsonRsqrt.cl":

#include "templates.h"

real TEMPLATE(NewtonRaphsonRsqrt, real, iters) (real x, real a) {
    int i;
    for (i = 0; i<iters; i++) {
        x *= ((real)1.5 - (0.5*a)*x*x);
    }
    return x;
}

В основном файле .cl, создайте этот шаблон следующим образом:

#define real float
#define iters 2
#include "NewtonRaphsonRsqrt.cl"  //defining NewtonRaphsonRsqrt_float_2

#define real double
#define iters 3
#include "NewtonRaphsonRsqrt.cl"  //defining NewtonRaphsonRsqrt_double_3

#define real double
#define iters 4
#include "NewtonRaphsonRsqrt.cl"  //defining NewtonRaphsonRsqrt_double_4

И тогда можно использовать его следующим образом:

double prec = TEMPLATE(NewtonRaphsonRsqrt, double, 4) (1.5, 0.5);
float approx = TEMPLATE(NewtonRaphsonRsqrt, float, 2) (1.5, 0.5);

Ответ 2

Я написал экспериментальный инструмент преобразования С++ в OpenCL C. Инструмент компилирует исходный код С++ (даже некоторые STL) в байт-код LLVM и использует модифицированную версию LLVM 'C' для удаления байт-кода в OpenCL 'C'.

См. http://dimitri-christodoulou.blogspot.com/2013/12/writing-opencl-kernels-in-c.html

Например, этот код с использованием С++ 11 std:: enable_if может быть преобразован в OpenCL 'C', а затем выполнен на графическом процессоре:

#include <type_traits>

template<class T>
T foo(T t, typename std::enable_if<std::is_integral<T>::value >::type* = 0)
{
    return 1;
}

template<class T>
T foo(T t, typename std::enable_if<std::is_floating_point<T>::value >::type* = 0)
{
    return 0;
}

extern "C" void _Kernel_enable_if_int_argument(int* arg0, int* out)
{
    out[0] = foo(arg0[0]);
}

Ответ 3

Вы можете посмотреть VexCL, который использует шаблоны выражений для генерации ядер OpenCL. Вы можете получить некоторые идеи о том, как заставить OpenCL работать с шаблонами.

Другая библиотека, которая активно работает, - Boost.Compute, которая является слоем поверх OpenCL, чтобы разрешить общий код на С++.

Общая идея состоит в том, чтобы создать ядро ​​как строку C более или менее и передать его во время выполнения OpenCL для компиляции и выполнения.

Ответ 4

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

Другой способ - реализовать пользовательский бэкэнд для LLVM, основанный на текущем CBE, который будет генерировать чистый код OpenCL вместо C.

Ответ 5

Обратите внимание, что новый SYCL Стандарт Khronos имеет встроенную поддержку шаблонов С++ в OpenCL.

Ответ 6

PyOpenCL теперь использует Mako в качестве механизма шаблона. http://www.makotemplates.org/