簡體   English   中英

如何在OpenCL內核中使用C ++模板?

[英]How to use C++ templates in OpenCL kernels?

我是OpenCL的新手。

我有一個使用模板的算法。 它在OpenMP並行化方面運行良好,但現在數據量已經增長,處理它的唯一方法是重寫它以使用OpenCL。 我可以輕松地使用MPI為集群構建它,但類似特斯拉的GPU比集群便宜得多:)

有沒有辦法在OpenCL內核中使用C ++模板?

是否有可能通過C ++編譯器或某些工具以某種方式擴展模板,然后使用如此改變的內核函數?

編輯。 解決方法的想法是以某種方式從模板中的C ++代碼生成C99兼容代碼。

我找到了一個關於Comeau的信息:

Comeau C ++ 4.3.3是一個完整而真實的編譯器,可執行完整的語法檢查,完整的語義檢查,完整的錯誤檢查以及所有其他編譯器職責。 輸入C ++代碼被轉換為內部編譯器樹和符號表,看起來不像C ++或C.同樣,它生成一個內部專有的中間形式。 但是,Comeau C ++ 4.3.3不是使用專有的后端代碼生成器,而是生成C代碼作為輸出。 除了C ++的技術優勢之外,Comeau C ++ 4.3.3等產品的C生成方面也被吹捧為C ++成功的原因,因為C編譯器的普遍可用性使其能夠被帶到大量平台。

C編譯器僅用於並且僅用於獲得本機代碼生成。 這意味着Comeau C ++專為與各個平台上的特定C編譯器一起使用而定制。 請注意,要求剪裁必須由Comeau完成。 否則,生成的C代碼沒有意義,因為它綁定到特定平台(其中平台至少包括CPU,OS和C編譯器),此外,生成的C代碼不是獨立的。 因此,它不能單獨使用(請注意,這在使用Comeau C ++時是技術和法律要求),這就是為什么通常沒有選項來查看生成的C代碼:它幾乎總是無用的和編譯過程包括其代,應被視為翻譯的內部階段。

有一種舊方法可以用純C語言模擬模板。 它基於多次包含單個文件(不包括保護)。 由於OpenCL具有功能齊全的預處理器並允許包含文件,因此可以使用此技巧。

這是一個很好的解釋: http//arnold.uthar.net/index.php?n = WORK.TemplatesC

它仍然比C ++模板更麻煩:代碼必須分成幾個部分,你必須顯式實例化每個模板實例。 此外,似乎你不能做一些有用的事情,如實現factorial作為遞歸模板。

代碼示例

讓我們將這個想法應用於OpenCL。 假設我們想通過Newton-Raphson迭代計算逆平方根(通常不是一個好主意)。 但是,浮點類型和迭代次數可能會有所不同。

首先,我們需要一個幫助頭(“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);

我已經為OpenCL C源代碼轉換工具編寫了一個實驗性的C ++。 該工具將C ++源代碼(甚至一些STL)編譯為LLVM字節代碼,並使用修改后的LLVM“C”后端版本將字節代碼反匯編為OpenCL“C”。

請參閱http://dimitri-christodoulou.blogspot.com/2013/12/writing-opencl-kernels-in-c.html

例如,使用C ++ 11的std :: enable_if的代碼可以轉換為OpenCL'C',然后在GPU上執行:

#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]);
}

您可以查看使用表達式模板生成OpenCL內核的VexCL 您可以了解如何使OpenCL與模板很好地協作。

正在積極處理的另一個庫是Boost.Compute ,它是OpenCL之上的一個層,允許使用通用C ++代碼。

一般的想法是將內核或多或少地創建為C字符串,並將其傳遞給OpenCL運行時以進行編譯和執行。

如果你真的決心要完成它,你可以重新定位你選擇的C ++編譯器來生成NVidia PTX(並且Clang很可能很快就能做到)。 但是這樣你就可以將你的代碼綁定到NVidia硬件了。

另一種方法是基於當前的CBE實現LLVM的自定義后端,它將生成純OpenCL代碼而不是C.

請注意,新的SYCL Khronos標准在OpenCL中對C ++模板具有本機支持。

PyOpenCL現在使用Mako作為它的模板引擎。 http://www.makotemplates.org/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM