OpenCL 学习step by step (9) 灰度图Histogram计算(3)

简介: 在OpenCL编程中,特别是基于GPU的opencl的编程,提高程序性能最主要的方法就是想法提高memory的利用率,它主要包括两方面的优化:一方面是提高global memory的合并读写效率,另一方面就是减少local memory的bank conflict。

     在OpenCL编程中,特别是基于GPU的opencl的编程,提高程序性能最主要的方法就是想法提高memory的利用率,它主要包括两方面的优化:一方面是提高global memory的合并读写效率,另一方面就是减少local memory的bank conflict。下面我们分析一下教程7中的代码,看看它的memory利用率如何?

    首先我们用amd的opencl profiler分析一下程序性能[最新的app sdk改用CodeXL进行性能分析]。

     下面我们来分析我们的kernel代码中memory操作:

     首先是shared memory的的初始化,我们知道shared memory是local memory,被一个workgroup中的所有thread,或者说work item共享。在amd硬件系统中,local memory是LDS,它通常是为32k或更高,分为32个bank,dword字节地址,每个bank 512个item,我们可以通过函数得到自己系统中的local memory数量:

cl_ulong DeviceLocalMemSize;
clGetDeviceInfo(device,
    CL_DEVICE_LOCAL_MEM_SIZE,
    sizeof(cl_ulong),
    &DeviceLocalMemSize,
    NULL);

LDS的示意图如下,对于每个bank,同时只能有一个读写请求,如果两个thread都读写bank1,那个必须串行访问,这就称作bank conflict。

image

kernel初始化local memory的代码如下:

//初始化共享内存
for(int i = 0; i < BIN_SIZE; ++i)
    sharedArray[localId * BIN_SIZE + i] = 0;

     在同一时间,thread0访问地址0(bank1),thread1,访问地址256,也在bank1,…,这样就有很多bank conflit,降低程序的性能。从profiler里面可以看到,lds bank conflit为13.98,很高的比例,所以此时同时运行的thread就比较少,只有总wave(每个wave 64个thread)的12%(我曾经默认lds内存分配是0,这样我们就省去了这些代码,但是实际上分配内存是一些随机的值…)。

image

image

第二段memory操作的代码为:

    //计算thread直方图
    for(int i = 0; i < BIN_SIZE; ++i)
    {
        uint value = (uint)data[groupId * groupSize * BIN_SIZE + i * groupSize + localId];
        sharedArray[localId * BIN_SIZE + value]++;
    }

其中有lds的操作,也有global memory的操作,对于全局memory的访问,在同一时刻,thread0访问i=0的memory

,thread1访问相邻的memory单元…,这是对于global memory的访问会采用合并读写的方式(coalencing),就是一个memory请求返回16个dword,也就是一个请求满足16个thread,提高memory利用率。此时对lds的写是随机的,根据value的值决定,不能控制…

image

 

最后一段memory读写的代码:

//合并workgroup中所有线程的直方图,产生workgroup直方图
for(int i = 0; i < BIN_SIZE / groupSize; ++i)
{
     uint binCount = 0;
     for(int j = 0; j < groupSize; ++j)
         binCount += sharedArray[j * BIN_SIZE + i * groupSize + localId];
        
     binResult[groupId * BIN_SIZE + i * groupSize + localId] = binCount;
}

其中lds的读写如下图,此时每个线程访问不同的bank,因为amd lds访问就是以32为单位,所以实际上,这段代码不会有bank conflit。

image

相关文章
|
缓存 开发工具 数据库
Docker 及 Docker Compose 安装指南
Docker 是一个开源的容器化平台,可以帮助我们快速构建、打包和运行应用程序。而 Docker Compose 则是用于管理多个容器应用的工具,可以轻松定义和管理多个容器之间的关系。现在,让我们开始安装过程吧!
1535 0
|
机器学习/深度学习 存储 缓存
输入输出大全(普通输入输出和快读快写)C/C++
输入输出大全(普通输入输出和快读快写)C/C++
678 0
|
JSON API 开发者
小红书商品详情API接口(小红书API系列)
小红书商品详情API接口帮助开发者获取平台上特定商品的详细信息,包括标题、价格、图片、描述、评价数量等。支持HTTP GET/POST请求,返回JSON格式数据。通过传递商品ID及其他可选参数,开发者可以将小红书的商品信息整合到自己的应用中,提供更丰富的购物体验。Python示例代码展示了如何使用requests库发送GET请求并处理响应数据。实际使用需替换为真实接口地址和商品ID,并遵循平台认证要求。
|
数据库 开发工具
国产化之 .NET Core 操作达梦数据库DM8的两种方式1
国产化之 .NET Core 操作达梦数据库DM8的两种方式1
983 0
|
机器学习/深度学习 存储 人工智能
人工智能的三大主义
人工智能的三大主义之一——符号主义,通过数学和逻辑符号构建表达式以模拟人类思维。其代表性成果包括1956年的“逻辑理论家”程序和上世纪80年代的专家系统。1997年,“深蓝”计算机击败国际象棋冠军卡斯帕罗夫,是符号主义在博弈领域的巅峰之作。然而,由于人类智能的复杂性和广泛性,符号主义难以完全模拟人类感知和潜智能,逐渐走向衰落。
|
运维 Linux
在Linux中,如何诊断和解决系统启动问题?
在Linux中,如何诊断和解决系统启动问题?
|
存储 JSON Go
一文搞懂 Golang 高性能日志库 Zerolog
一文搞懂 Golang 高性能日志库 Zerolog
1648 0
|
前端开发 PHP 对象存储
如何用Postman测试文件或图片上传
本文介绍了在某些小项目中,如何使用传统方式将文件上传到与应用程序同一服务器上的方法,而不是使用大平台的对象存储。
2433 3
麒麟镜像下载
【8月更文挑战第23天】这是麒麟软件官方提供的产品试用下载链接,适用于银河麒麟、中标麒麟、开放麒麟及星光麒麟等国产操作系统。访问官网选择适合您的操作系统版本进行下载。使用迅雷等工具完成下载后即可体验自主可控的麒麟操作系统。
5427 1
|
存储 编解码 Java
轻松获取图片和视频文件的Exif信息-Java篇
本文简单介绍了Metadata 元数据以及Exif可交换图像文件信息的基本知识,介绍了metadata-extractor的具体用法,展示了png图像元数据读取、GPS坐标识别和定位以及视频的元数据信息提取,而metadata-extractor提供了大量能使我们快速便捷地获取元数据的方法。
6811 0