▶ 向量前缀和

● 最简单的版本,代码

 #include <stdio.h>
#include <stdlib.h>
#include <cl.h> const char *programSource = " \
__kernel void prefixSum(__global int *input, int n) \
{ \
int offset, level, idx, lp, rp, temp; \
for (offset = , level = n / ; level > ; offset *= , level /= ) \
{ \
barrier(CLK_LOCAL_MEM_FENCE); \
for (idx = get_local_id(); idx < level; idx += get_local_size()) \
{ \
lp = offset * ( * idx + ) - ; \
rp = offset * ( * idx + ) - ; \
input[rp] = input[lp] + input[rp]; \
} \
} \
barrier(CLK_LOCAL_MEM_FENCE); \
if (get_local_id() == ) \
input[n - ] = ; \
\
for (level = ; level < n; level *= ) \
{ \
offset /= ; \
barrier(CLK_LOCAL_MEM_FENCE); \
for (idx = get_local_id(); idx < level; idx += get_local_size()) \
{ \
lp = offset * ( * idx + ) - ; \
rp = offset * ( * idx + ) - ; \
temp = input[lp]; \
input[lp] = input[rp]; \
input[rp] += temp; \
} \
} \
} \
"; int main()
{
const size_t nElement = , nWorkItem = , datasize = sizeof(int) * nElement;
const int n = nElement;
int i, *A, *C;
cl_int status; A = (int*)malloc(datasize);
C = (int*)malloc(datasize);
for (i = ; i < nElement; A[i] = , i++);
for (C[] = , i = ; i < nElement; C[i] = C[i - ] + A[i - ], i++); // 开前缀和
//for (C[0] = A[0], i = 1; i < nElement; C[i] = C[i - 1] + A[i], i++); // 闭前缀和 cl_uint nPlatform;
clGetPlatformIDs(, NULL, &nPlatform);
cl_platform_id *listPlatform = (cl_platform_id*)malloc(nPlatform * sizeof(cl_platform_id));
clGetPlatformIDs(nPlatform, listPlatform, NULL);
cl_uint nDevice = ;
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, , NULL, &nDevice);
cl_device_id *listDevice = (cl_device_id*)malloc(nDevice * sizeof(cl_device_id));
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, nDevice, listDevice, NULL);
cl_context context = clCreateContext(NULL, nDevice, listDevice, NULL, NULL, &status);
cl_command_queue queue = clCreateCommandQueue(context, listDevice[], , &status); cl_mem bufferA = clCreateBuffer(context, CL_MEM_READ_WRITE, datasize, NULL, &status);
clEnqueueWriteBuffer(queue, bufferA, CL_TRUE, , datasize, A, , NULL, NULL); cl_program program = clCreateProgramWithSource(context, , (const char**)&programSource, NULL, &status);
clBuildProgram(program, nDevice, listDevice, NULL, NULL, NULL);
cl_kernel kernel = clCreateKernel(program, "prefixSum", &status); clSetKernelArg(kernel, , sizeof(cl_mem), &bufferA);
clSetKernelArg(kernel, , sizeof(cl_int), &n);
status = clEnqueueNDRangeKernel(queue, kernel, , NULL, &nElement, &nWorkItem, , NULL, NULL);
clFinish(queue); clEnqueueReadBuffer(queue, bufferA, CL_TRUE, , datasize, A, , NULL, NULL);
for (i = ; i < nElement; i++)
{
if (A[i] != C[i])
break;
}
printf("Output is %s, %d.\n", (i == nElement) ? "correct" : "incorrect", i); free(A);
free(C);
free(listPlatform);
free(listDevice);
clReleaseContext(context);
clReleaseCommandQueue(queue);
clReleaseMemObject(bufferA);
clReleaseProgram(program);
clReleaseKernel(kernel);
getchar();
return ;
}

● 输出结果

Output is correct, .

● 核函数说明

 // 代码说明
void prefixSum(int *input, int n)
{
int offset, level, idx, lp, rp, temp;
for (offset = , level = n / ; level > ; offset *= , level /= )// level 为当前循环写入元素个数,每次循环处理所有跨度为 offset 的元素
{
barrier(CLK_LOCAL_MEM_FENCE);
for (idx = get_local_id(); idx < level; idx += get_local_size())// 每次循环处理 get_local_size(0) 对元素,靠前元素加到靠后元素上
{
lp = offset * ( * idx + ) - ;
rp = offset * ( * idx + ) - ;
input[rp] += input[lp];
}
}
barrier(CLK_LOCAL_MEM_FENCE);
if (get_local_id() == )// 主线程将最后一个元素置零,之后要向前传,注意到这里时 offset == n
input[n - ] = ;
for (level = ; level < n; level *= )// level 为当前循环写入元素对数,每次循环处理所有跨度为 offset 的元素
{
offset /= ;
barrier(CLK_LOCAL_MEM_FENCE);
for (idx = get_local_id(); idx < level; idx += get_local_size())// 每次循环处理 get_local_size(0) 对元素,靠前元素赋为靠后元素,靠后元素等于两者原值之和
{
lp = offset * ( * idx + ) - ;
rp = offset * ( * idx + ) - ;
temp = input[lp];
input[lp] = input[rp];
input[rp] += temp;
}
}
}

● 使用局部内存优化吗,C++ 版本

 // kernel.cl
__kernel void reduce(__global uint4* input, __global uint4* output, int NUM)
{
__local uint4 resArray[];
unsigned int lid = get_local_id(), globalSize = get_global_size();
int i;
uint4 res = (uint4) { , , , }; for (i = get_global_id(); i < NUM / ; res += input[i], i += globalSize);// 在局部内存中做第一次规约
resArray[lid] = res;
barrier(CLK_LOCAL_MEM_FENCE); for (i = get_local_size() >> ; i > ; i >>= )// 分发
{
if (lid < i)
resArray[lid] += resArray[lid + i];
barrier(CLK_LOCAL_MEM_FENCE);
} if (lid == )
output[get_group_id()] = resArray[];
}
 // main.cpp
#include <cl.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <fstream> const char *filename = "kernel.cl"; using namespace std; int isVerify(int NUM, int groupNUM, int *res)// 校验结果
{
int i, sum;
for (i = sum = ; i < groupNUM * ; sum += res[i++]);
return sum == (NUM + ) * NUM / ;
} char* readSource(const char *filename)// 读取代码文件,C++ 版本
{
std::fstream f(filename, (std::fstream::in | std::fstream::binary));
if (!f.is_open())
{
cout << "<readSource> Error open file " << filename << "\n" << endl;
return nullptr;
}
f.seekg(, std::fstream::end);
size_t size = (size_t)f.tellg();
f.seekg(, std::fstream::beg);
char *str = new char[size + ];
if (str == nullptr)
{
cout << "<readSource> Error malloc memory\n" << endl;
f.close();
return nullptr;
}
f.read(str, size);
f.close();
str[size] = '\0';
return str;
} int main(int argc, char* argv[])
{
cl_int status;
cl_uint nPlatform;
clGetPlatformIDs(, NULL, &nPlatform);
cl_platform_id *listPlatform = (cl_platform_id*)malloc(nPlatform * sizeof(cl_platform_id));
clGetPlatformIDs(nPlatform, listPlatform, NULL);
cl_uint nDevice = ;
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, , NULL, &nDevice);
cl_device_id *listDevice = (cl_device_id*)malloc(nDevice * sizeof(cl_device_id));
clGetDeviceIDs(listPlatform[], CL_DEVICE_TYPE_ALL, nDevice, listDevice, NULL);
cl_context context = clCreateContext(NULL, nDevice, listDevice, NULL, NULL, &status);
cl_command_queue queue = clCreateCommandQueue(context, listDevice[], , &status); const char *source = readSource(filename);
const size_t sourceSize = strlen(source);
cl_program program = clCreateProgramWithSource(context, , &source, &sourceSize, NULL);
clBuildProgram(program, , listDevice, NULL, NULL, NULL);
cl_kernel kernel = clCreateKernel(program, "reduce", NULL); const int NUM = * ;
size_t global_work_size[] = { };
size_t local_work_size[] = { };
size_t groupNUM = global_work_size[] / local_work_size[];
int* input = new int[NUM];
for (int i = ; i < NUM; input[i] = i + , i++);
int* output = new int[(global_work_size[] / local_work_size[]) * ];
cl_mem inputBuffer = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, (NUM) * sizeof(int), (void *)input, NULL);
cl_mem outputBuffer = clCreateBuffer(context, CL_MEM_WRITE_ONLY, groupNUM * * sizeof(int), NULL, NULL); clSetKernelArg(kernel, , sizeof(cl_mem), (void *)&inputBuffer);
clSetKernelArg(kernel, , sizeof(cl_mem), (void *)&outputBuffer);
clSetKernelArg(kernel, , sizeof(int), &NUM);
cl_event enentPoint;
clEnqueueNDRangeKernel(queue, kernel, , NULL, global_work_size, local_work_size, , NULL, &enentPoint);
clWaitForEvents(, &enentPoint);
clReleaseEvent(enentPoint); clEnqueueReadBuffer(queue, outputBuffer, CL_TRUE, , groupNUM * * sizeof(int), output, , NULL, NULL);
cout << "The result is " << (isVerify(NUM, groupNUM, output) ? "Correct" : "Error") << ".\n" << endl; free(input);
free(output);
free(listDevice);
clReleaseContext(context);
clReleaseCommandQueue(queue);
clReleaseProgram(program);
clReleaseKernel(kernel);
clReleaseMemObject(inputBuffer);
clReleaseMemObject(outputBuffer);
getchar();
return ;
}

● 输出结果

The result is correct.

OpenCL 前缀和的更多相关文章

  1. 基于SoCkit的opencl实验1-基础例程

    基于SoCkit的opencl实验1-基础例程 准备软硬件 Arrow SoCkit Board 4GB or larger microSD Card Quartus II v14.1 SoCEDS ...

  2. OpenCL与CUDA,CPU与GPU

    OpenCL OpenCL(全称Open Computing Language,开放运算语言)是第一个面向异构系统通用目的并行编程的开放式.免费标准,也是一个统一的编程环境,便于软件开发人员为高性能计 ...

  3. Android AARCH64 平台的 OpenCL 配置

    原文地址:Android AARCH64 平台的 OpenCL 配置 Android AARCH64 平台的 OpenCL 配置 开发环境 IDE: Android Studio 3.4.1 Andr ...

  4. HDU1671——前缀树的一点感触

    题目http://acm.hdu.edu.cn/showproblem.php?pid=1671 题目本身不难,一棵前缀树OK,但是前两次提交都没有成功. 第一次Memory Limit Exceed ...

  5. 【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed

    之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码: //将字符串"a"写入流,再拿到流的 ...

  6. ASP.NET Core MVC 配置全局路由前缀

    前言 大家好,今天给大家介绍一个 ASP.NET Core MVC 的一个新特性,给全局路由添加统一前缀.严格说其实不算是新特性,不过是Core MVC特有的. 应用背景 不知道大家在做 Web Ap ...

  7. 如何处理CSS3属性前缀

    今天闲来无聊,重新来说说CSS3前缀的问题.在春节前和@一丝姐姐说起Sass中有关于gradient的mixins.姐姐说: 为什么还要用mixin呢?为什么不使用Autoprefixer?使用Aut ...

  8. context:component-scan" 的前缀 "context" 未绑定。

    SpElUtilTest.testSpELLiteralExpressiontestSpELLiteralExpression(cn.zr.spring.spel.SpElUtilTest)org.s ...

  9. 解决adobe air sdk打包 apk后自动在包名前面加上air. (有个点)前缀的问题

    早就找到了这个方法,但是一直忙没心思写博客. 默认情况下,所有 AIR Android 应用程序的包名称都带 air 前缀.若不想使用此默认行为,可将计算机环境变量 AIR_NOANDROIDFLAI ...

随机推荐

  1. Rails 5 Test Prescriptions(everday Rspectest作者推荐) 目录 1-3章

    总文档连接: RSpec.info/documentation/ 如何使用TDD 和 自动化测试来建立一个Rails app. TDD让你用测试来探索代码的设计.你将学习可利用的工具,并学习用什么工具 ...

  2. 【Demo】jQuery 图片放大镜效果——模仿淘宝图片放大效果

    实现功能: 模仿淘宝图片放大效果,鼠标移动到小图片的某一处,放大镜对应显示大图片的相应位置. 实现效果: 实现代码: <!DOCTYPE html> <html> <he ...

  3. 局域网内web地图的简单实现

    首先,我先说一下这次的主要目的.我们的想法是在不连互联网的局域网中搭起来一个地图服务,类似于百度地图的网页版本,功能最少要有看地图.放缩.标记.批量标记.实时经纬度坐标.这个东西还是让我费了一番力气( ...

  4. linux 常用操作以及概念

    一.常用操作以及概念 查看LINUX发行版的名称及其版本号的命令: lsb_release -a cat /etc/redhat-release(针对redhat,Fedora) 0.rpm包路径:/ ...

  5. notepad++个人专注

    notepad++个人专注   快捷键 功能 1 Ctrl>>>>>>>>>>    Ctrl + b  匹配括号 Ctrl + d  选中 ...

  6. mysql迁移oracle

    有很多应用项目, 刚起步的时候用MYSQL数据库基本上能实现各种功能需求,随着应用用户的增多,数据量的增加,MYSQL渐渐地出现不堪重负的情况:连接很慢甚至宕机,于是就有把数据从MYSQL迁到Orac ...

  7. jQuery实现鼠标划过展示大图的方法

    这篇文章主要介绍了jQuery实现鼠标划过展示大图的方法,实例分析了jQuery操作鼠标事件及图片处理的技巧,具有一定参考借鉴价值,需要的朋友可以参考下 本文实例讲述了jQuery实现鼠标划过展示大图 ...

  8. delphi从dll中调用图片资源

    假定你的一个dll中有bmp图片,其中图片的别名为'img'(如何将图片放入dll中百度上有图文教程) 当想将dll中的bmp导出时,可以用如下实例代码: procedure TForm1.FormC ...

  9. BOM之其他浏览器对象的使用

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  10. 【转】Selenium2 API详解

    [转自]http://blog.csdn.net/wuxuehong0306/article/details/49762961 打开浏览器 Ø  打开firefox浏览器 WebDriver driv ...