设为首页
优惠IDC
收藏本站
六狼博客
六狼论坛
开启辅助访问
切换到窄版
用户名
Email
自动登录
找回密码
密码
登录
立即注册
只需一步,快速开始
只需一步,快速开始
快捷导航
门户
首页
BBS
云计算
大数据
手机
移动开发android,ios,windows phone,windows mobile
编程
编程技术java,php,python,delphi,ruby,c,c++
前端
WEB前端htmlcss,javascript,jquery,html5
数据库
数据库开发Access,mysql,oracle,sql server,MongoDB
系统
操作系统windows,linux,unix,os,RedHat,tomcat
架构
项目管理
软件设计,架构设计,面向对象,设计模式,项目管理
企业
服务
运维实战
神马
搜索
搜索
热搜:
php
java
python
ruby
hadoop
sphinx
solr
ios
android
windows
centos
本版
帖子
用户
六狼论坛
»
首页
›
项目管理
›
计算机图形学
›
OpenCL 学习step by step (11) 数组求和(reduction) ...
返回列表
查看:
826
|
回复:
0
OpenCL 学习step by step (11) 数组求和(reduction)
[复制链接]
迈克老狼2012
迈克老狼2012
当前离线
积分
474
窥视卡
雷达卡
升级
91.33%
当前用户组为
举人
当前积分为
474
, 升到下一级还需要 26 点。
154
主题
154
主题
154
主题
举人
举人, 积分 474, 距离下一级还需 26 积分
举人, 积分 474, 距离下一级还需 26 积分
积分
474
发消息
楼主
|
发表于 2012-12-30 11:52:46
|
显示全部楼层
|
阅读模式
OpenCL 学习step by step (11) 数组求和(reduction)
<div class="postbody"><div id="cnblogs_post_body">
     本篇教程中,我们学习一下如何用opencl有效实现数组求和,也就是通常所说的reduction问题。
     在程序中,我们设置workgroup size为256,kernel的输入、输出缓冲参数都用uint4的格式,这样我们原始求和的数组大小为256*4的倍数,数据类型为uint。我们设定每个workgroup处理处理512个uint,即2048个uint
     为了简便期间,我们输出数组长度定为4096,即需要2个workgruop来处理。
   
kernel代码如下:
__kernel void reduce(__global uint4* input, __global uint4* output, __local uint4* sdata)
{
   
// 把数据装入lds
    unsigned int tid = get_local_id(0);
    unsigned int bid = get_group_id(0);
    unsigned int gid = get_global_id(0);
    unsigned int localSize = get_local_size(0);
    unsigned int stride = gid * 2;
    sdata[tid] = input[stride] + input[stride + 1];
    barrier(CLK_LOCAL_MEM_FENCE);
   
// 在lds中进行reduction操作,得到数组求和的结果
    for(unsigned int s = localSize >> 1; s > 0; s >>= 1)
    {
        if(tid < s)
        {
            sdata[tid] += sdata[tid + s];
        }
        barrier(CLK_LOCAL_MEM_FENCE);
    }
  
// 把一个workgroup计算的结果输出到输出缓冲,是一个uint4,还需要在host端再进行一次reduction过程
    if(tid == 0) output[bid] = sdata[0];
}
     在程序中,global和local的NDRange,我们都用一维的形式。下面以图的方式看下kernel代码是如何执行的:
   
  对第一个workgroup中的第一个thread的来说,它首先进行一次reduction操作,把两个uint4相加,放到lds(shared memory)中,然后再在lds中进行reduction操作,此时要从global memory中取数据,可以看出连续的thread访问连续的global memory,这时可以利用合并读写。
      申请的shared memory大小为groupsize*sizeof(uint4),相加后uint4放入32bank的lds中,放置的方式应该是如下图所示,因为放入的是uint4,所以会放入连续的4个bank中(每个bank都是dword宽),可见只能同时有8个thread访问lds,所以会有一定程序的bank conflit。从App profiler session,我们可以看到:
      接下来,kernel会通过一个for循环迭代执行reduction操作,求得一个workgroup中的uint4的和。
迭代的第一次s=128,这时会执行如下图的两两相加,workgroup中同时执行的thread为128,thread local id大于等于128的线程都不会做什么事情,在每个循环的末尾,有一个barrier来同步所有thread,以便所有thread都完成这次循环后再进入下一次循环。
 
   第二次迭代的时候,只剩下前面128个uint4,workgroup中同时执行的thread为64。最后,当s=1时候,完成迭代reduction操作,然后把thread0(第一个thread)的结果输出。
     在host段,我们还要做一次相加操作,把不同workgroup得到的uint4,拆分成uint,并相加求得最终的结果。
//在cpu reduction各个workgroup的结果以及uint4分量 reduction
output = 0;
for(int i = 0; i < numBlocks * VECTOR_SIZE; ++i)
    output += outMapPtr
;
printf(&quot;gpu reduction result:%d\n&quot;, output);
if(refOutput==output) printf(&quot;passed\n&quot;);
程序执行后结果如下:
完整的代码请参考:
工程文件gclTutorial11
代码下载:
稍后提供
 
回复
使用道具
举报
提升卡
置顶卡
沉默卡
喧嚣卡
变色卡
千斤顶
显身卡
返回列表
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
|
立即注册
本版积分规则
发表回复
回帖后跳转到最后一页
Copyright © 2008-2020
六狼论坛
(http://it.6wolf.com) 版权所有 All Rights Reserved.
Powered by
Discuz!
X3.4
京ICP备14020293号-2
本网站内容均收集于互联网,如有问题请联系
QQ:389897944
予以删除
快速回复
返回顶部
返回列表