▶ 照着书上的代码,写了几个一步归约的计算,只计算一步,将原数组归约到不超过 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. Codeforces 208A:Dubstep(字符串)

    题目链接:http://codeforces.com/problemset/problem/208/A 题意 给出一个字符串,将字符串中的WUB给删去,如果两个字母间有WUB,则这两个字母用空格隔开 ...

  2. 使用pip install XX 命令时报错

    在使用pip命令安装的时候,我遇到这样的报错: C:\Users\86962>pip install Appium-Python-Client Collecting Appium-Python- ...

  3. CSS 属性用法备忘录

    ☆ margin: 0; padding: 0; :{ 顺时针 margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: ...

  4. IIS目录

    一.目录浏览 一般网站部署后,需要禁用目录浏览, 若启用目录浏览的话,可以自定义开启哪些目录(只能根目录),和影藏哪些目录 iis中限制访问某个文件或某个类型的文件配置方法 注意:图片目录不要隐藏,不 ...

  5. Django的DateTimeField和DateField

    一.DateField: class DateField(auto_now=False, auto_now_add=False, **options)[source] auto_now:每次保存时,都 ...

  6. PipelineDB 1.0.0 docker 运行

    PipelineDB 1.0 是基于标准的pg 扩展来做的,安装也更方便了,目前还没有对应的docker 镜像 所以参考timescaledb 做了一个,方便测试以及使用 参考地址 https://g ...

  7. linux下 mysql主从备份

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/czh0423/article/details/26720539 一.准备 用两台server做測试: ...

  8. python 之 python3内置函数

    一. 简介 python内置了一系列的常用函数,以便于我们使用,python英文官方文档详细说明:点击查看, 为了方便查看,将内置函数的总结记录下来. 二. 使用说明 以下是Python3版本所有的内 ...

  9. Oracle 表空间与数据文件

    -============================== --Oracle 表空间与数据文件 --============================== /* 一.概念 表空间:是一个或多 ...

  10. mac上安装nginx

    终端执行: brew install nginx nginx 默认安装在 /usr/local/Cellar/nginx/1.12.2 conf 文件默认安装在 /usr/local/etc/ngin ...