▶ 照着书上的代码,写了几个一步归约的计算,只计算一步,将原数组归约到不超过 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. 不要使用 Dispatcher.Invoke,因为它可能在你的延迟初始化 Lazy 中导致死锁

    WPF 中为了 UI 的跨线程访问,提供了 Dispatcher 线程模型.其 Invoke 方法,无论在哪个线程调用,都可以让传入的方法回到 UI 线程. 然而,如果你在 Lazy 上下文中使用了 ...

  2. Omar Loves Candies

    题目大意:在一个N * M的格子中,放有一些糖,这些糖有的会损害健康,有的对健康有益.有损害的被记为负数,有益的会记为正数.另外,对于每一个糖而言,他都比左边的糖和上面的糖更健康. 现在我要在在N*M ...

  3. Windows10 解决“装了 .NET Framework 4.5.2/4.6.1/4.7.1等等任何版本 或版本更高的更新”问题

    ========================================================= 系统自带的.net framework版本为4.7,自己安装.NET Framewo ...

  4. java泛型(一)、泛型的基本介绍和使用

    现在开始深入学习java的泛型了,以前一直只是在集合中简单的使用泛型,根本就不明白泛型的原理和作用.泛型在java中,是一个十分重要的特性,所以要好好的研究下. 泛 型的定义:泛型是JDK 1.5的一 ...

  5. LG2024 [NOI2001]食物链

    拆点法 用并查集维护每种动物的同类.天敌.食物群 #include<cstdio> int fa[300005]; int n,k,ans; inline int read() { int ...

  6. harbor helm 仓库使用

    harbor 已经支持helm 私服仓库了,还是比较方便的 安装 下载在线安装包 wget https://storage.googleapis.com/harbor-releases/release ...

  7. statik golang 静态资源嵌入二进制文件工具使用(docker 构建)

      将静态资源打包进二进制文件有好多方便的地方 方便客户演示 代码简单加密 运行方便 statik 就是一款在golang 中用的比较多,nodejs 有一款pkg (oclif 就推荐使用此工具) ...

  8. FastAdmin composer json 版本说明

    来源于 FastAdmin 执行 composer update 后将 ThinkPHP 升级到了 V5.1. FastAdmin  是基于 ThinkPHP 5.0.x 开发的,而 ThinkPHP ...

  9. opencv中的滤波

    以前的时候,为了过滤图像中的一些噪点,学过一些简单的滤波,比如中值滤波,均值滤波,也是自己实现的. 在opencv中有现成的函数可以调用,实现滤波的操作. 函数的原型如下: CVAPI(void) c ...

  10. Eclipse设置相同变量背景色高亮显示

    在Eclipse中,鼠标选中或者光标移动到java类的变量名时,相同变量会被标识显示(设置背景色高亮), 并且侧边滚动条会标出变量的位置, 查找变量十分方便. 1.相同变量标识高亮显示: Window ...