程序中的Reduce(CPU和GPU)

news2024/10/6 18:35:11

前提

最近在看Reduce(归约)的相关知识和代码,做个总结。这里默认大家已经明白了Reduce的基础概念。

Reduce

根据参考链接一,Recude常见的划分方法有两种:

  1. 相邻配对:元素和它们相邻的元素配对
    在这里插入图片描述

  2. 交错配对:元素与一定距离的元素配对
    在这里插入图片描述

相关代码

相邻匹配——CPU

相邻匹配的代码有两个值得注意的地方,一个是在这一次递归中我们要循环多少次,另一个是在循环中我们如何确定下标。下面这段代码已经经过验证,大家可以对照这个图方便理解。
在这里插入图片描述

int traversal(vector<int> data, int size, int stride)
{
    if(size == 1)
    {
        return data[0];
    }
    int loop = size / 2;
    if(size % 2 == 0)
    {
        for(int i=0; i<loop; i++) //在这一次递归中循环的次数
        {
            data[i*(stride)] += data[i*(stride)+stride/2];  // 使用stride来确定下标
        }
    }
    else{
        for(int i=0; i<loop; i++)
        {
            data[i*(stride)] += data[i*(stride)+stride/2];
        }
        data[0] = data[0] + data[(size-1)*stride/2];
    }
    return traversal(data, size / 2, stride * 2);
}


int main()
{
    vector<int>a{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17};
    int res = traversal(a, a.size(), 2);
}

交错配对——CPU

int recursiveReduce(int *data, int const size)
{
	// terminate check
	if (size == 1)
        return data[0];
	// renew the stride
	int const stride = size / 2;
	if (size % 2 == 1)
	{
		for (int i = 0; i < stride; i++)
		{
			data[i] += data[i + stride];
		}
		data[0] += data[size - 1];
	}
	else
	{
		for (int i = 0; i < stride; i++)
		{
			data[i] += data[i + stride];
		}
	}
	// call
	return recursiveReduce(data, stride);
}

相邻匹配——GPU

__global__ void reduceNeighbored(int * g_idata,int * g_odata, unsigned int n)
{
	//set thread ID
	unsigned int tid = threadIdx.x;
	//boundary check
	if (tid >= n) return;
	//convert global data pointer to the
	int *idata = g_idata + blockIdx.x*blockDim.x;
	//in-place reduction in global memory
	for (int stride = 1; stride < blockDim.x; stride *= 2)
	{
		if ((tid % (2 * stride)) == 0)
		{
			idata[tid] += idata[tid + stride];
		}
		//synchronize within block
		__syncthreads();
	}
	//write result for this block to global mem
	if (tid == 0)
		g_odata[blockIdx.x] = idata[0];
}
//int size = 1<<24;
//int blocksize = 1024;
//dim3 block(blocksize);
//dim3 grid((size + block.x - 1)/block.x);

要注意这里存在线程束的分化。也就是一个block内只有线程号为0,2,4…的线程在执行,因为属于一个warp,所以其余线程在等待。

优化版本:

__global__ void reduceNeighboredLess(int * g_idata,int *g_odata,unsigned int n)
{
	unsigned int tid = threadIdx.x;
	unsigned idx = blockIdx.x*blockDim.x + threadIdx.x;
	// convert global data pointer to the local point of this block
	int *idata = g_idata + blockIdx.x*blockDim.x;
	if (idx > n)
		return;
	//in-place reduction in global memory
	for (int stride = 1; stride < blockDim.x; stride *= 2)
	{
		//convert tid into local array index
		int index = 2 * stride *tid;
		if (index < blockDim.x)
		{
			idata[index] += idata[index + stride];
		}
		__syncthreads();
	}
	//write result for this block to global men
	if (tid == 0)
		g_odata[blockIdx.x] = idata[0];
}

这个思路是:让warp的前几个线程跑满,而后半部分线程基本是不用执行的。当一个线程束内存在分支,而分支都不需要执行的时候,硬件会停止他们调用别人,这样就节省了资源。

交错匹配——GPU

__global__ void reduceInterleaved(int * g_idata, int *g_odata, unsigned int n)
{
	unsigned int tid = threadIdx.x;
	unsigned idx = blockIdx.x*blockDim.x + threadIdx.x;
	// convert global data pointer to the local point of this block
	int *idata = g_idata + blockIdx.x*blockDim.x;
	if (idx >= n)
		return;
	//in-place reduction in global memory
	for (int stride = blockDim.x/2; stride >0; stride >>=1)
	{

		if (tid <stride)
		{
			idata[tid] += idata[tid + stride];
		}
		__syncthreads();
	}
	//write result for this block to global men
	if (tid == 0)
		g_odata[blockIdx.x] = idata[0];
}

参考链接

  1. CUDA基础3.4 避免分支分化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1876393.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

动态人物抠图换背景 MediaPipe

pip下载 MediaPipe pip install mediapipe -i 手部特征点模型包包含一个手掌检测模型和一个手部特征点检测模型。手掌检测模型在输入图片中定位手部&#xff0c;手部特征点检测模型可识别手掌检测模型定义的被剪裁手掌图片上的特定手部特征点。 由于运行手掌检测模型非常耗时&…

[图解]建模相关的基础知识-19

1 00:00:00,640 --> 00:00:04,900 前面讲了关系的这些范式 2 00:00:06,370 --> 00:00:11,570 对于我们建模思路来说&#xff0c;有什么样的作用 3 00:00:12,660 --> 00:00:15,230 我们建模的话&#xff0c;可以有两个思路 4 00:00:16,790 --> 00:00:20,600 一个…

【QT】按钮类控件 显示类控件

目录 按钮类控件 Push Button 设置按钮图标 按钮设置快捷键 设置鼠标点击按钮重复触发 Radio Button 单选框分组 Check Box 显示类控件 Label 常用属性 设置文本格式 给Label设置图片 Label标签设置边框 设置文本对齐方式 设置文本自动换行 设置文本缩进 设置…

AI与音乐的结合

前言 毫无疑问,AI的发展已经在音乐领域带来了诸多变化和影响.但人类创作仍然具有不可替代的重要性。人类的灵感、创造力以及对音乐的深刻理解和情感表达是音乐产业的核心动力来源。AI 更倾向于被视为一种辅助工具&#xff0c;与人类创作者相互协作和融合&#xff0c;共同推动音…

Nuxt3 的生命周期和钩子函数(五)

title: Nuxt3 的生命周期和钩子函数&#xff08;五&#xff09; date: 2024/6/29 updated: 2024/6/29 author: cmdragon excerpt: 摘要&#xff1a;本文详细介绍了Nuxt3中的六个核心生命周期钩子及其用法&#xff0c;包括build:done、build:manifest、builder:generateApp、…

解锁亚马逊、Temu、速卖通成功密码:重视评论,做好测评自养号

在亚马逊平台上&#xff0c;产品评论至关重要&#xff0c;因其能帮助其他买家做出购买决策。然而&#xff0c;亚马逊上的买家留评率却很低。有趣的是&#xff0c;存在一些买家&#xff0c;他们并未实际购买产品&#xff0c;却能发表评论。这究竟是怎么回事呢&#xff1f;接下来…

探索音频创作的无限可能——Studio One 5 软件深度解析

Studio One 5 是一款功能强大且备受赞誉的音频制作软件&#xff0c;无论是专业音乐制作人还是业余爱好者&#xff0c;都能在其中找到满足自己需求的强大功能。 对于 Mac 和 Windows 用户来说&#xff0c;Studio One 5 提供了一个直观且友好的操作界面。其简洁明了的布局让用户…

App Inventor 2 列表排序,函数式编程轻松实现高级排序算法

本文主要介绍 列表 的高级用法&#xff0c;即函数式编程&#xff0c;可以按照指定的逻辑进行列表的排序&#xff0c;而无需我们自己写代码实现排序功能。 指定的逻辑也包括很复杂的逻辑&#xff0c;也就是说如果你的排序逻辑很复杂&#xff0c;函数式编程就是最好的使用场景。…

FreeSWITCH 1.10.10 简单图形化界面22-JsSIP的demo测试并记录坑

FreeSWITCH 1.10.10 简单图形化界面22-JsSIP的demo测试 00 FreeSWITCH GUI界面预览01、安装FreeSWITCH GUI先看使用手册02. 使用手册在这里0、设置FreeSWITCH账号1、jssip的demo网站2、设置jssip账号并登录3、整理坑3.1 掉线问题3.11 解决3.2 呼叫问题13.21 解决13.3 呼叫问题2…

基于Spring Boot与Vue的智能房产匹配平台+文档

博主介绍&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐&#xff1a;最热的500个选题…

苏东坡传-读书笔记四

长江三峡&#xff0c;无人不知其风光壮丽&#xff0c;但对旅客而言&#xff0c;则是险象环生。此段江流全长二百二十余里&#xff0c;急流旋涡在悬崖峭壁之间滚转出入&#xff0c;水下暗石隐伏&#xff0c;无由得见&#xff0c;船夫要极其敏捷熟练&#xff0c;才可通行。三峡之…

Linux平台下RTSP|RTMP播放器如何跟python交互投递RGB数据供视觉算法分析

技术背景 我们在对接Linux平台RTSP播放模块的时候&#xff0c;遇到这样的技术需求&#xff0c;开发者需要把Linux RTSP播放器拉取的数据&#xff0c;除了实时播放外&#xff0c;还要投递给python&#xff0c;用于视觉算法分析。 技术实现 Linux平台RTSP、RTMP直接播放不再赘…

夏季如何科学防暑?约克VRF中央空调为您奉上清凉降暑秘籍

热热热&#xff0c;一到夏天“滚滚热浪”来袭&#xff0c;仿佛像个炙热的“烤炉”一般&#xff0c;燥热难耐、流汗不停&#xff0c;长时间呆在高温环境下还容易引发中暑、热射病等问题&#xff0c;威胁身体健康。      有人可能会说&#xff0c;高温天气&#xff0c;我躲在…

Ubuntu系统,实现FastDDS的源码编译

目录 一、Ubuntu系统介绍二、FastDDS是什么三、FastDDS的源码编译四、FastDDS的简单测试 一、Ubuntu系统介绍 Ubuntu是一个基于Linux的开源操作系统&#xff0c;由Canonical公司开发和维护。它以其易用性、稳定性和安全性而受到广泛赞誉。Ubuntu系统提供了一个图形化的桌面环境…

【MTK平台】连接蓝牙耳机播放音乐>插入有线耳机>再拔掉有线耳机,声音会从设备中播放一秒,再切到蓝牙耳机

一般这类情况优先考虑Audio的问题 修改如下这个BTA2DP_MUTE_CHECK_DELAY_MS 参数值既可&#xff0c;比如增加delay 把BTA2DP_MUTE_CHECK_DELAY_MS * 4改成 BTA2DP_MUTE_CHECK_DELAY_MS *8 frameworks/base/services/core/java/com/android/server/audio/AudioDeviceBroker.j…

微信小程序开发_准备工作

1 注册小程序 注册地址 https://mp.weixin.qq.com/wxopen/waregister?actionstep1&sourcempregister&token&langzh_CN 2 完善小程序信息 进入微信公众平台https://mp.weixin.qq.com/,登录账号 登录后,在首页完善小程序信息和小程序类目 完成后在左侧找到开发…

【ACM出版-EI稳检索】第三届金融创新、金融科技与信息技术国际学术会议(FFIT 2024,7月26-28)

第三届金融创新、科技与信息技术国际学术会议&#xff08;FFIT 2024&#xff09;将于2024年07月26-28日于重庆举行。 FFIT2024 将围绕“金融创新”、"金融科技”与“信息技术”等相关最新研究领域&#xff0c;为来自国内外高等院校、科学研究所、企事业单位的专家、教授、…

SerDes介绍以及原语使用介绍(3)ISERDESE2原语介绍

文章目录 前言一、ISERDESE21.1、ISERDESE2端口信号1.1、ISERDESE2参数 二、BITSLIP-位滑动2.1、BITSLIP作用2.2、BITSLIP使用2.3、BITSLIP示例 前言 上文对OSERDESE进行了详细介绍并且进行了仿真分析&#xff0c;本文开始对ISERDES进行介绍&#xff0c; 一、ISERDESE2 不难…

Python生成和识别二维码教程

引言 二维码&#xff08;QR Code&#xff09;在日常生活中非常常见&#xff0c;广泛应用于支付、登录验证、信息分享等场景。本文将介绍如何使用Python生成和识别二维码&#xff0c;适合初学者快速上手。我们将使用qrcode和pyzbar库来实现这一功能。 环境准备 在开始之前&am…

Python+Pytest+Allure+Yaml+Jenkins+GitLab接口自动化测试框架详解

PythonPytestAllureYaml接口自动化测试框架详解 编撰人&#xff1a;CesareCheung 更新时间&#xff1a;2024.06.20 一、技术栈 PythonPytestAllureYamlJenkinsGitLab 版本要求&#xff1a;Python3.7.0,Pytest7.4.4,Allure2.18.1,PyYaml6.0 二、环境配置 安装python3.7&…