【OpenCL】
OpenCL（Open Computing Language，开放计算语言）是一个为异构平台编写程序的框架，此异构平台可由CPU、GPU、DSP、FPGA或其他类型的处理器与硬体加速器所组成。OpenCL由一门用于编写kernels（在OpenCL设备上运行的函数）的语言（基于C99）和一组用于定义并控制平台的API组成。OpenCL提供了基于任务分割和数据分割的并行计算机制。
OpenCL类似于另外两个开放的工业标准OpenGL和OpenAL，这两个标准分别用于三维图形和计算机音频方面。OpenCL扩充了GPU图形生成之外的能力。OpenCL由非盈利性技术组织Khronos Group掌管。
== 历史 ==
OpenCL最初由苹果公司开发，拥有其商标权，并在与AMD，IBM，Intel和NVIDIA技术团队的合作之下初步完善。随后，苹果将这一草案提交至Khronos Group。
2008年6月16日，Khronos的通用计算工作小组成立。5个月后的2008年11月18日，该工作组完成了OpenCL 1.0规范的技术细节。该技术规范在由Khronos成员进行审查之后，于2008年12月8日公开发表。2010年6月14日，OpenCL 1.1发布。
== 范例 ==
=== 快速傅立叶变换 ===
一个快速傅立叶变换的式子：
// create a compute context with GPU device
context = clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU, NULL, NULL, NULL);
// create a command queue
queue = clCreateCommandQueue(context, NULL, 0, NULL);
// allocate the buffer memory objects
memobjs0 = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float)*2*num_entries, srcA, NULL);
memobjs1 = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float)*2*num_entries, NULL, NULL);
// create the compute program
program = clCreateProgramWithSource(context, 1, &fft1D_1024_kernel_src, NULL, NULL);
// build the compute program executable
clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
// create the compute kernel
kernel = clCreateKernel(program, "fft1D_1024", NULL);
// set the args values
clSetKernelArg(kernel, 0, sizeof(cl_mem),(void *)&memobjs0);
clSetKernelArg(kernel, 1, sizeof(cl_mem),(void *)&memobjs1);
clSetKernelArg(kernel, 2, sizeof(float)*(local_work_size0+1)*16, NULL);
clSetKernelArg(kernel, 3, sizeof(float)*(local_work_size0+1)*16, NULL);
// create N-D range object with work-item dimensions and execute kernel
global_work_size0 = num_entries;
local_work_size0 = 64;
clEnqueueNDRangeKernel(queue, kernel, 1, NULL, global_work_size, local_work_size, 0, NULL, NULL);
真正的运算：（基于 Fitting FFT onto the G80 Architecturedate=20120304225100 ）
// This kernel computes FFT of length 1024. The 1024 length FFT is decomposed into
// calls to a radix 16 function, another radix 16 function and then a radix 4 function
__kernel void fft1D_1024(__global float2 *in, __global float2 *out,
__local float *sMemx, __local float *sMemy){
int tid = get_local_id(0);
int blockIdx = get_group_id(0) * 1024 + tid;
float2 data16;
// starting index of data to/from global memory
in = in + blockIdx;  out = out + blockIdx;
globalLoads(data, in, 64); // coalesced global reads
fftRadix16Pass(data);      // in-place radix-16 pass
twiddleFactorMul(data, tid, 1024, 0);
// local shuffle using local memory
localShuffle(data, sMemx, sMemy, tid, (((tid & 15)* 65) +(tid >> 4)));
fftRadix16Pass(data);               // in-place radix-16 pass
twiddleFactorMul(data, tid, 64, 4); // twiddle factor multiplication
localShuffle(data, sMemx, sMemy, tid, (((tid >> 4)* 64) +(tid & 15)));
// four radix-4 function calls
fftRadix4Pass(data);      // radix-4 function number 1
fftRadix4Pass(data + 4);  // radix-4 function number 2
fftRadix4Pass(data + 8);  // radix-4 function number 3
fftRadix4Pass(data + 12); // radix-4 function number 4
// coalesced global writes
globalStores(data, out, 64);
}
Apple的网站上可以发现傅立叶变换的例子
=== 平行合并排序法 ===
使用 Python 3.x 搭配 PyOpenCL 与 NumPy
import io
import random
import numpy as np
import pyopencl as cl
def dump_step(data, chunk_size):
"""显示排序过程"""
msg = io.StringIO()
div = io.StringIO()
for idx, item in enumerate(data):
if idx % chunk_size == 0:
if idx > 0:
msg.write('
')
div.write('   ')
div.write(' --')
else:
msg.write('   ')
div.write('------')
msg.write(' {:2d}'.format(item))
out = msg.getvalue()
if chunk_size == 1: print(' ' + '-' * (len(out) - 1))
print(out)
print(div.getvalue())
msg.close()
div.close()
def cl_merge_sort_sbs(data_in):
"""平行合并排序"""
# OpenCL kernel 函数程式码
CL_CODE =
kernel void merge(int chunk_size, int size, global long* data, global long* buff) {
// 取得分组编号
const int gid = get_global_id(0);
// 根据分组编号计算责任范围
const int offset = gid * chunk_size;
const int real_size = min(offset + chunk_size, size) - offset;
global long* data_part = data + offset;
global long* buff_part = buff + offset;
// 设定合并前的初始状态
int r_beg = chunk_size >> 1;
int b_ptr = 0;
int l_ptr = 0;
int r_ptr = r_beg;
// 进行合并
while (b_ptr = real_size) {
// 若右侧没有资料，取左侧资料堆入缓冲区
buff_partb_ptr = data_partl_ptr++;
} else if (l_ptr == r_beg) {
// 若左侧没有资料，取右侧资料堆入缓冲区
buff_partb_ptr = data_partr_ptr++;
} else {
// 若两侧都有资料，取较小资料堆入缓冲区
if (data_partl_ptr
执行结果：
--------------------------------------------------------------------------------------
85
41
64
40
90
29
38
41
64
17
20
41
16
65
83
--    --    --    --    --    --    --    --    --    --    --    --    --    --    --
41    85
40    64
29    90
38    41
17    64
20    41
16    65
83
--------    --------    --------    --------    --------    --------    --------    --
40    41    64    85
29    38    41    90
17    20    41    64
16    65    83
--------------------    --------------------    --------------------    --------------
29    38    40    41    41    64    85    90
16    17    20    41    64    65    83
--------------------------------------------    --------------------------------------
16    17    20    29    38    40    41    41    41    64    64    65    83    85    90
--------------------------------------------------------------------------------------
== 参考文献 ==
== 外部连结 ==
*  支援OpenCL的产品date=20180629130825
*  开源GPU社区