▶ 照着书上的代码,写了几个一步归约的计算,只计算一步,将原数组归约到不超过 1024 个工作项

● 代码

 // kernel.cl
__kernel void reduce01(__global uint* input, __global uint* output, __local uint* sdata)
{
const unsigned int tid = get_local_id(), blockSize = get_local_size();
unsigned int s; sdata[tid] = input[get_global_id()];
barrier(CLK_LOCAL_MEM_FENCE); // 三种写法,用一种就够
// 1、模法,问题: % 运算很慢
for (s = ; s < blockSize; s <<= )
{
if (tid % ( * s) == )
sdata[tid] += sdata[tid + s];
barrier(CLK_LOCAL_MEM_FENCE);
}
// 2、间隔缩短法,问题:首次迭代只用一半的工作项,之后每次迭代活跃的工作项持续减少
for (s = blockSize / ; s > ; s >>= )
{
if (tid < s)
sdata[tid] += sdata[tid + s];
barrier(CLK_LOCAL_MEM_FENCE);
}
// 3、间隔增长法,问题:当间隔等于某几个数的时候会产生
unsigned int index;
for (s = ; s < blockSize; s <<= )
{
if ((index = * s * tid) < blockSize)
sdata[index] += sdata[index + s];
barrier(CLK_LOCAL_MEM_FENCE);
} if (tid == )
output[get_group_id()] = sdata[];
} __kernel void reduce02(__global uint* input, __global uint* output, __local uint* sdata)
{
const unsigned int tid = get_local_id(), bid = get_group_id(), blockSize = get_local_size();
const unsigned int index = bid * (blockSize * ) + tid;
unsigned int s; sdata[tid] = input[index] + input[index + blockSize];// 读入局部内存时就进行一次归约
barrier(CLK_LOCAL_MEM_FENCE); // 两种写法,用一种就够
// 1、不手动展开循环,仍然有工作项浪费的问题
for (s = blockSize / ; s > ; s >>= )
{
if (tid < s)
sdata[tid] += sdata[tid + s];
barrier(CLK_LOCAL_MEM_FENCE);
}
// 2、手动展开最后的循环
for (s = blockSize / ; s > ; s >>= )// BUG:如果从 64 开始手工归约,在这一行有且仅有一个工作项会算出 640 = 512 + 128 来,其他行却没问题
{
if (tid < s)
sdata[tid] += sdata[tid + s];
barrier(CLK_LOCAL_MEM_FENCE);
}
if (tid < ) // 手动展开最后的归约,注意同步,书中源代码中没有同步,计算结果是错的
{
if (blockSize >= )
sdata[tid] += sdata[tid + ];
barrier(CLK_LOCAL_MEM_FENCE);
if (blockSize >= )
sdata[tid] += sdata[tid + ];
barrier(CLK_LOCAL_MEM_FENCE);
if (blockSize >= )
sdata[tid] += sdata[tid + ];
barrier(CLK_LOCAL_MEM_FENCE);
if (blockSize >= )
sdata[tid] += sdata[tid + ];
barrier(CLK_LOCAL_MEM_FENCE);
if (blockSize >= )
sdata[tid] += sdata[tid + ];
barrier(CLK_LOCAL_MEM_FENCE);
if (blockSize >= )
sdata[tid] += sdata[tid + ];
barrier(CLK_LOCAL_MEM_FENCE);
} if (tid == )
output[bid] = sdata[];
}
 // main.c
#include <stdio.h>
#include <stdlib.h>
#include <cl.h> #define BLOCK_SIZE 256 // 工作组内最大工作项数为 1024
#define DATA_SIZE (BLOCK_SIZE * 1024) // 一维最大工作组数为1024 const char *sourceText = "D:/Code/OpenCL/OpenCLProjectTemp/OpenCLProjectTemp/kernel.cl"; int readText(const char* kernelPath, char **pcode)// 读取文本文件放入 pcode,返回字符串长度
{
FILE *fp;
int size;
//printf("<readText> File: %s\n", kernelPath);
fopen_s(&fp, kernelPath, "rb");
if (!fp)
{
printf("Open kernel file failed\n");
getchar();
exit(-);
}
if (fseek(fp, , SEEK_END) != )
{
printf("Seek end of file failed\n");
getchar();
exit(-);
}
if ((size = ftell(fp)) < )
{
printf("Get file position failed\n");
getchar();
exit(-);
}
rewind(fp);
if ((*pcode = (char *)malloc(size + )) == NULL)
{
printf("Allocate space failed\n");
getchar();
exit(-);
}
fread(*pcode, , size, fp);
(*pcode)[size] = '\0';
fclose(fp);
return size + ;
} int main()
{
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[], CL_QUEUE_PROFILING_ENABLE, &status); //const unsigned int nGroup = DATA_SIZE / BLOCK_SIZE; // reduce01 使用
const unsigned int nGroup = DATA_SIZE / BLOCK_SIZE / ; // reduce02 使用
int *hostA = (cl_int*)malloc(sizeof(cl_int) * DATA_SIZE);
int *hostB = (cl_int*)malloc(sizeof(cl_int) * nGroup);
int i;
unsigned long refSum;
srand();
for (i = , refSum = 0L; i < DATA_SIZE; refSum += (hostA[i++] = ));// rand()));
memset(hostB, , sizeof(int) * nGroup);
cl_mem deviceA = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(cl_int) * DATA_SIZE, hostA, &status);
cl_mem deviceB = clCreateBuffer(context, CL_MEM_WRITE_ONLY, sizeof(cl_int) * nGroup, NULL, &status); char *code;
size_t codeLength = readText(sourceText, &code);
cl_program program = clCreateProgramWithSource(context, , (const char**)&code, &codeLength, &status);
status = clBuildProgram(program, nDevice, listDevice, NULL, NULL, NULL);
if (status)
{
char info[];
clGetProgramBuildInfo(program, listDevice[], CL_PROGRAM_BUILD_LOG, , info, NULL);
printf("\n%s\n", info);
}
//cl_kernel kernel = clCreateKernel(program, "reduce01", &status);
cl_kernel kernel = clCreateKernel(program, "reduce02", &status); clSetKernelArg(kernel, , sizeof(cl_mem), (void*)&deviceA);
clSetKernelArg(kernel, , sizeof(cl_mem), (void*)&deviceB);
clSetKernelArg(kernel, , BLOCK_SIZE * sizeof(cl_int), NULL); size_t globalSize = DATA_SIZE, localSize = BLOCK_SIZE;
cl_event ev;
//cl_ulong startTime, endTime;
status = clEnqueueNDRangeKernel(queue, kernel, , NULL, &globalSize, &localSize, , NULL, &ev);
clFinish(queue);
//clGetEventProfilingInfo(ev, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &startTime, NULL); // 不启用计时,因为一趟归约时间太短
//clGetEventProfilingInfo(ev, CL_PROFILING_COMMAND_START, sizeof(cl_ulong), &endTime, NULL);
//printf("Time:%lu.%lu\n", (endTime - startTime) / 1000000000, (endTime - startTime) % 1000000000); clEnqueueReadBuffer(queue, deviceB, CL_TRUE, , sizeof(cl_int) * nGroup, hostB, , NULL, NULL);
for (i = ; i < nGroup; refSum -= hostB[i++]);
printf("Result %s.\n", (refSum == ) ? "correct" : "error"); free(hostA);
free(hostB);
free(code);
free(listPlatform);
free(listDevice);
clReleaseContext(context);
clReleaseCommandQueue(queue);
clReleaseProgram(program);
clReleaseKernel(kernel);
clReleaseEvent(ev);
clReleaseMemObject(deviceA);
clReleaseMemObject(deviceB);
getchar();
return ;
}

● 输出结果

Result correct.

OpenCL 归约 1的更多相关文章

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

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

  2. OPenCL

    OpenCLhttp://baike.baidu.com/link?url=7uHWCVUYB3Sau_xh3OOKP-A08_IvmT1SJixdAXKezCuCfkzeSQDiSmesGyVGk8 ...

  3. kaggle数据挖掘竞赛初步--Titanic<派生属性&维归约>

    完整代码: https://github.com/cindycindyhi/kaggle-Titanic 特征工程系列: Titanic系列之原始数据分析和数据处理 Titanic系列之数据变换 Ti ...

  4. Opencl 并行求和

    上周尝试用opencl求极大值,在网上查到大多是求和,所谓的reduction算法.不过思路是一样的. CPP: ; unsigned ; ; ; int nGroup = nGroupSize / ...

  5. opencl初体验

    总结一下,opencl的步骤差不多是这些 先要获取平台的id clGetPlatformIDs(nPlatforms, platform_id, &num_of_platforms) 然后获取 ...

  6. Altera OpenCL用于计算机领域的13个经典案例(转)

    英文出自:Streamcomputing 转自:http://www.csdn.net/article/2013-10-29/2817319-the-application-areas-opencl- ...

  7. 面向OPENCL的ALTERA SDK

    面向OPENCL的ALTERA SDK 使用面向开放计算语言 (OpenCL™) 的 Altera® SDK,用户可以抽象出传统的硬件 FPGA 开发流程,采用更快.更高层面的软件开发流程.在基于 x ...

  8. OpenCV GPU CUDA OpenCL 配置

    首先,正确安装OpenCV,并且通过测试. 我理解GPU的环境配置由3个主要步骤构成. 1. 生成关联文件,即makefile或工程文件 2. 编译生成与使用硬件相关的库文件,包括动态.静态库文件. ...

  9. CUDA/OpenCL 学习资料

    VS2010 NVIDIA OpenCL 开发环境配置 CUDA 在线课程 [经典培训] 全球首套中文CUDA 教程-胡文美教授主讲

随机推荐

  1. cf 557D 二分图黑白染色

    题意:给出一个 n 点 m 边的图,问最少加多少边使其能够存在奇环,加最少边的情况数有多少种 奇环和偶环其实就是二分图的性质:二分图不存在奇环,所以只要判断这张图是否是二分图就行了: 如果本身就不是二 ...

  2. Cassandra 数据库, python cqlsh命令

    ★  cql操作数据库(cqlsh.bat: python cqlsh命令操作<优缺点:https://blog.csdn.net/vbirdbest/article/details/77662 ...

  3. LG3377 【模板】左偏树(可并堆)

    好博客 1 2 上面那个用数组写的跑的快,且便于封装,就用他的代码了. 代码 #include<cstdlib> #include<cstdio> #include<cm ...

  4. ioctl命令

    _IO._IOR._IOW._IOWR 宏的使用说明 驱动程序中 ioctl  函数传递的变量 cmd 是应用程序向驱动程序请求处理的命令.cmd 除了用于区别不同命令的数值,还可包含有助于处理的几种 ...

  5. fork 开源项目后如何参与项目

    好的开源项目都很想参与到开源活动中,并且会 fork 一份. 经过几个月的学习,大概明白了如果参与开源项目. 当完成 fork 后,就需要在本地 git clone 一份. 有新的功能或需要修复的就开 ...

  6. file-loader 与 url-loader 的区别

    url-loader是对file-loader的一个封装,比如webpack中对图片的加载器配置 {test: /\.(png|jpg)$/, loader: 'url-loader?limit=81 ...

  7. postman 中 form-data、x-www-form-urlencoded、raw、binary的区别

    区别 form-data: 就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开.既可以上传键值对,也可以上传文件.当上传的字段是文件 ...

  8. LwIP:处理链路状态改变

    [文/告别年代   Email:byeyear@hotmail.com] 重大修订记录 ----------------------------------------- 2016.11.03 感谢@ ...

  9. wxWidgets:菜单

    和菜单有关的类主要有两个:wxMenuItem和wxMenu.wxMenuItem用于表示一个菜单项,而wxMenu是wxMenuItem的弹出或下拉列表. 现在让我们看看如何给我们的框架类加上菜单: ...

  10. git提交忽略不必要的文件或文件夹

    创建maven项目,使用git提交,有时需要忽略不必要的文件或文件夹,只保留一些基本. 例如如下截图,实际开发中我们只需提交:src,.gitignore,pom.xml 而自己项目文件一般都保留,但 ...