任意长度并行前缀和 扫描算法 《PMPP》笔记

news2024/9/25 9:27:15

下面的算法针对于任意长度输入

在这里插入图片描述

对于大数据集,首先将输入分为几段,每一段放进共享内存并用一个线程块处理,比如一个线程块使用1024个线程的话,每个块最多能处理2048个元素。

在前面代码中,一个块最后的执行结果保存到了Y数组中,Y 数组保存了每个段扫描的结果,可以称之为扫描块, 一个扫描块只保存了当前块中前面所有元素的累加值,需要把这些扫描块合并到一个最终的结果中。

在这里插入图片描述

上述栗子, 在16个输入的数组中,分为4个扫描块,kernel将4个扫描块看做独立的输入数据集处理,扫描kernel结束之后,每个Y元素保存了这个扫描块中扫描的结果。

每个扫描块最后一个元素时当前扫描块中输入元素的总和。

在第二步中,从每个扫描块中收集最后一个元素,放进一个数组S中,然后对此数组进行扫描,然后将扫描S数组后的值累加到对应的扫描块上。

可以使用3个kernel实现层级扫描,第一个kernel和之前的kernel没有太大差别(都是针对块内进行扫描), 需要添加一个中间变量S,其维度为 inputSize/SECTION_SIZE, 在kernel的最后,需要块的最后一个线程把当前扫描块中最后值写到S中blockIdx.x 位置上。

第二个kernel和之前的kernel也一样,只是使用S作为输入,修改S的内容并将之作为输出。

第三个kernel接受S和Y数组作为输入,然后将输出写回到Y, 将一个S的元素加到对应扫描块的Y元素上。

/*
处理任意长度输入的并行归约, 包括3个层级kernel
*/
__global__ void tier1_scan_kernel(
    float* dev_x, float *dev_y, float *dev_s, unsigned int inputSize){
    // 第一层级,实现每个块内的归约,并将归约后的最后一个元素写到S中
    __shared__ float XY[SECTION_SIZE];
    int idx = blockIdx.x * blockDim.x +threadIdx.x;
    if(idx < inputSize){
        XY[threadIdx.x] = dev_x[idx];
    }

    // 归约阶段
    for(unsigned int stride=1;stride<blockDim.x; stride*=2){
        __syncthreads();
        int index = (threadIdx.x+1)*2*stride - 1;
        if(index<blockDim.x){
            XY[index] += XY[index-stride];
        }
    }

    // 分发阶段
    for(int stride=SECTION_SIZE/4; stride>0; stride/=2){
        __syncthreads();
        int index = (threadIdx.x+1)*stride*2 - 1;
        if(index+stride< SECTION_SIZE){
            XY[index+stride] += XY[index];
        }
    }

    __syncthreads();
    dev_y[idx] = XY[threadIdx.x];
    if (threadIdx.x == 0){
        dev_s[blockIdx.x] = XY[SECTION_SIZE-1];
    }
}

__global__ void tier2_scan_kernel(float * dev_s, unsigned int inputSize){
    __shared__ float XY[SECTION_SIZE];
    int idx = blockIdx.x * blockDim.x +threadIdx.x;
    if(idx < inputSize){
        XY[threadIdx.x] = dev_s[idx];
    }

    // 归约阶段
    for(unsigned int stride=1;stride<blockDim.x; stride*=2){
        __syncthreads();
        int index = (threadIdx.x+1)*2*stride - 1;
        if(index<blockDim.x){
            XY[index] += XY[index-stride];
        }
    }

    // 分发阶段
    for(int stride=SECTION_SIZE/4; stride>0; stride/=2){
        __syncthreads();
        int index = (threadIdx.x+1)*stride*2 - 1;
        if(index+stride< SECTION_SIZE){
            XY[index+stride] += XY[index];
        }
    }

    __syncthreads();
    dev_s[idx] = XY[threadIdx.x];
}

__global__ void tier3_scan_kernel(float *dev_y, float *dev_s, unsigned int inputSize){
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    if (idx< inputSize){
        dev_y[idx] += dev_s[blockIdx.x];
    }
}

void func_scan_gpu3(float* x, unsigned int length){
    float *y = new float[length];

    float *dev_x, *dev_y, *dev_s;
    cudaMalloc((void**)&dev_x, length*sizeof(float));
    cudaMalloc((void**)&dev_y, length*sizeof(float));
    unsigned int blocks = (length + SECTION_SIZE -1)/ SECTION_SIZE;

    cudaMemcpy(dev_x, x, length*sizeof(float), cudaMemcpyHostToDevice);
    cudaMalloc((void**)&dev_s, blocks*sizeof(float));
    tier1_scan_kernel<<<blocks, SECTION_SIZE>>>(dev_x, dev_y, dev_s, length);
    tier2_scan_kernel<<<1, blocks>>>(dev_s, blocks);
    tier3_scan_kernel<<<blocks, SECTION_SIZE>>>(dev_y,dev_s, length);

    cudaMemcpy(y, dev_y,length*sizeof(float), cudaMemcpyDeviceToHost);
    print1DArr(y, SECTION_SIZE);

    cudaFree(dev_x);
    cudaFree(dev_y);
    cudaFree(dev_s);
    delete[] y;
}

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

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

相关文章

桥接模式和NET模式的区别

桥接模式和NET模式的区别 NAT模式&#xff1a; NAT&#xff1a;网络地址转换&#xff08;模式&#xff09;&#xff1a;借助宿主机来上网&#xff0c;没桥接那么麻烦&#xff0c;只用配置DNS即可。 缺点&#xff1a;扎根于宿主机&#xff0c;不能和局域网内其它真实的主机进行…

用Python实现运筹学——Day 2: 线性规划的基本概念

一、学习内容 线性规划的定义&#xff1a; 线性规划&#xff08;Linear Programming, LP&#xff09;是一种用于求解约束条件下线性目标函数最优解的方法。线性规划问题通常涉及最大化或最小化一个线性目标函数&#xff0c;目标函数的变量受一组线性不等式或等式的约束。 目标…

C语言 | Leetcode C语言题解之第435题无重叠区间

题目&#xff1a; 题解&#xff1a; int cmp(int** a, int** b) {return (*a)[1] - (*b)[1]; }int eraseOverlapIntervals(int** intervals, int intervalsSize, int* intervalsColSize) {if (intervalsSize 0) {return 0;}qsort(intervals, intervalsSize, sizeof(int*), cm…

【React】Ant Design 5.x版本drawer抽屉黑边问题

环境 antd: ^5.14.1react: ^18 问题情况 <Drawer open{open} closable{false} mask{false} width{680}getContainer{props.getContainer || undefined}><p>Some contents...</p><p>Some contents...</p><p>Some contents...</p> …

[网络] 网络层--IP协议

目录 一、IP协议 1.1 基本概念 1.2 IP协议报头 1.3 如何将报头和有效载荷分离和分用 1.4 分片与组装 1.5 如何减少分片&#xff1f; 1.6 分片和封装的具体过程 二、网段划分 2.1 再次理解IP地址 2.2 了解DHCP 2.3 网络划分方案 2.4 为什么要进行网络划分 2.5 特殊的…

Java基础——字节流和字符流

字节流和字符流的用法几乎完全一样&#xff0c;区别在于字节流和字符流所操作的数据单元不同&#xff0c;字节流操作的单元是数据单元是8位的字节&#xff0c;字符流操作的是数据单元为16位的字符。 为什么要有字符流&#xff1f; Java中字符是采用Unicode标准&#xff0c;Un…

【Go语言】Go语言结构体全面解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

基于 Canvas 的可缩放拖动网格示例(Vue3以及TypeScript )

文章目录 1. 基本知识2. Vue33. TypeScript 1. 基本知识 基本知识讲解&#xff1a; Canvas API&#xff1a; 一种用于在网页上绘制图形的 HTML 元素&#xff0c;使用 JavaScript 的 Canvas API 来进行绘制 使用 getContext(2d) 方法获取 2D 绘图上下文&#xff0c;允许开发者绘…

MySQL数据库备份详解

文章目录 引言● 数据库备份的重要性 MySQL数据库备份的基础知识● 备份类型1、完全备份2、增量备份3、差异备份 ● 备份工具与方法1、逻辑备份工具——mysqldump2、物理备份工具——Xtrabackup3、第三方解决方案 MySQL数据库备份的实施步骤1、环境准备2、选择合适的备份工具与…

【Linux基础IO】深入解析Linux基础IO缓冲区机制:提升文件操作效率的关键

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;Linux “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;暂无 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀Linux基础IO &#x1f4d2;1. 什么是缓…

14.第二阶段x86游戏实战2-C++语言开发环境搭建-VisualStudio2017

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

基于jsonpath_ng的JSON数据查改增删

jsonpath_ng支持JSON数据的读写操作。 安装 pip install jsonpath-ng测试数据 from jsonpath_ng import parse import jsonjson_data { "store": {"book": [ { "category": "reference","author": "Nigel Rees&qu…

数据集-目标检测系列-鲨鱼检测数据集 shark >> DataBall

数据集-目标检测系列-鲨鱼检测数据集 shark >> DataBall 数据集-目标检测系列-鲨鱼检测数据集 shark 数据量&#xff1a;6k 想要进一步了解&#xff0c;请联系。 DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;百种数据集&#xff0c;持续增加中。 示例&…

【自动驾驶】基于车辆几何模型的横向控制算法 | Stanley 算法详解与编程实现

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

【Python】探索 Elpy:Emacs 中的 Python 开发环境

可以短时间不开心&#xff0c;但别长时间不清醒。 对于使用 Emacs 编辑器的 Python 开发者来说&#xff0c;Elpy 是一个强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它通过整合多个 Emacs Lisp 和 Python 包&#xff0c;提供了一套完整的 Python 编程支持。本文…

丹摩智算平台体验:AI开发从未如此简单

目录 初次接触丹摩智算GPU算力资源表格 轻松创建GPU实例镜像选择 实验过程体验实验中的一些细节 使用后的感受一点小建议总结 最近我一直在学习一些与深度学习相关的知识&#xff0c;准备自己动手做一些模型训练的实验。平时在自己电脑上跑模型总感觉有点吃力&#xff0c;特别是…

复制他人 CSDN 文章到自己的博客

文章目录 0.前言步骤 0.前言 在复制别人文章发布时&#xff0c;记得表明转载哦 步骤 在需要复制的csdn 文章页面&#xff0c;打开浏览器开发者工具&#xff08;F12&#xff09;Ctrl F 查找"article_content"标签头 右键“Copy”->“Copy element”新建一个 tx…

[大语言模型-论文精读] ACL2024-长尾知识在检索增强型大型语言模型中的作用

ACL2024-长尾知识在检索增强型大型语言模型中的作用 On the Role of Long-tail Knowledge in Retrieval Augmented Large Language Models Authors: Dongyang Li, Junbing Yan, Taolin Zhang, Chengyu Wang, Xiaofeng He, Longtao Huang, Hui Xue, Jun Huang 1.概览 问题解决&…

Windows驱动调试方法

单步调试驱动 驱动的调试不能直接在本机上进行&#xff0c;而是要放在虚拟机&#xff08;或其它设备&#xff09;中。这是因为在内核模式下&#xff0c;一个断点的触发将会停下整个系统而不只是单个进程。 在前面的文章里&#xff0c;使用了DbgPrint函数来进行日志的输出&…

学习一下怎么用git

目录 初始化操作 设置名字&#xff1a; 设置邮箱: 查询状态 初始化本地仓库 清空git bush控制台 git的三个区域 文件提交 将会文件提交到暂存区 暂存指定文件 暂存所有改动文件 查看暂存区里面的文件 将文件提交到版本库 git文件状态查看 ​编辑 暂存区的相关指令…