cuda编程学习——原子函数(十)

news2024/11/27 9:48:11

前言

参考资料:

高升博客
《CUDA C编程权威指南》
以及 CUDA官方文档
CUDA编程:基础与实践 樊哲勇

文章所有代码可在我的GitHub获得,后续会慢慢更新

文章、讲解视频同步更新公众《AI知识物语》,B站:出门吃三碗饭

1:原子函数

原子操作(atomic operation)的函数,简称为原子函数。

在CUDA中,一个线程的原子操作可以在不受其他线程的 任何操作的影响下完成对某个(全局内存或共享内存中的)数据的一套“读-改-写”操作。
该套操作也可以说是不可分的。

2:原子函数与归约计算

归约计算参考上一章节(第9)的介绍。

前面几个章节的归约计算,核函数并没有做全部的计算,即没有全部在GPU执行,而只是将一个长 一些的数组 d_x 变成了一个短一些的数组 d_y,后者中的每个元素为前者中若干元素的和。在调用核函数之后,将短一些的数组复制到主机,然后在主机中完成了余下的求和

有两种方法能够在GPU中 得到最终结果,
一是用另一个核函数将较短的数组进一步归约,得到最终的结果(一个数 值);
二是在先前的核函数的末尾利用原子函数进行归约,直接得到最终结果。

本文讨论第2种方法

//第9章归约核 函数的最后几行
//if 语句块的作用是将每一个线程块中归约的结果从共享内存 s_y[0] 复制到全
//局内 存d_y[bid]。为了将不同线程块的部分和s_y[0]累加起来,存放到一个全局
//内存地址
if (tid == 0)
{
d_y[bid] = s_y[0];
}

//使用原子函数

if (tid == 0) 
{
//第一个参数是待累加变量的地址address,第二个 参数是累加的值val
//该函数的作用是将地址address中的旧值old读出,计算old + val, 然后将计算的值存入地址address。
//这些操作在一次原子事务(atomic transaction)中完成,不会被别的线程中的原子操作所干扰。
atomicAdd(&d_y[0], s_y[0]);
}

原子函数对它的第一个参数指向的数据进行一次**“读-改-写”的原子操作**。第一个参数可以指向全局内存,也可以指向共享内存。对所有参与的 线程来说,该“读-改-写”的原子操作是一个线程一个线程轮流做的,但没有明确的次序。另外,原子函数没有同步功能。

原子函数的原型
1. 加法:T atomicAdd(T *address, T val); 功能:new = old + val。
2. 减法:T atomicSub(T *address, T val); 功能:new = old - val。
3. 交换:T atomicExch(T *address, T val); 功能:new = val。
4. 最小值:T atomicMin(T *address, T val); 功能:new = (old < val) ? old : val。
5. 最大值:T atomicMax(T *address, T val);
功能:new = (old > val) ? old : val。
6. 自增:T atomicInc(T *address, T val); 功能:new = (old >= val) ? 0 : (old + 1)7. 自减:T atomicDec(T *address, T val); 功能:new = ((old == 0) || (old > val)) ? val : (old - 1)8. 比较-交换(Compare And Swap):T atomicCAS(T *address, T compare, T val); 功能:new = (old == compare) ? val : old。
9. 按位与:T atomicAnd(T *address, T val); 功能:new = old & val。
10. 按位或:T atomicOr(T *address, T val); 功能:new = old | val。
11. 按位异或:T atomicXor(T *address, T val);
功能:new = old ^ val。

在这里插入图片描述

原子函数–归约计算

#include<stdint.h>
#include<cuda.h>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <math.h>
#include <stdio.h>

#define CHECK(call)                                   \
do                                                    \
{                                                     \
    const cudaError_t error_code = call;              \
    if (error_code != cudaSuccess)                    \
    {                                                 \
        printf("CUDA Error:\n");                      \
        printf("    File:       %s\n", __FILE__);     \
        printf("    Line:       %d\n", __LINE__);     \
        printf("    Error code: %d\n", error_code);   \
        printf("    Error text: %s\n",                \
            cudaGetErrorString(error_code));          \
        exit(1);                                      \
    }                                                 \
} while (0)

#ifdef USE_DP
typedef double real;
#else
typedef float real;
#endif

const int NUM_REPEATS = 100;
const int N = 100000000;
const int M = sizeof(real) * N;
const int BLOCK_SIZE = 128;

void timing(const real* d_x);

int main(void)
{
    real* h_x = (real*)malloc(M);
    for (int n = 0; n < N; ++n)
    {
        h_x[n] = 1.23;
    }
    real* d_x;
    CHECK(cudaMalloc(&d_x, M));
    CHECK(cudaMemcpy(d_x, h_x, M, cudaMemcpyHostToDevice));

    printf("\nusing atomicAdd:\n");
    timing(d_x);

    free(h_x);
    CHECK(cudaFree(d_x));
    return 0;
}

void __global__ reduce(const real* d_x, real* d_y, const int N)
{
    const int tid = threadIdx.x;
    const int bid = blockIdx.x;
    const int n = bid * blockDim.x + tid;
    extern __shared__ real s_y[];
    s_y[tid] = (n < N) ? d_x[n] : 0.0;
    __syncthreads();

    for (int offset = blockDim.x >> 1; offset > 0; offset >>= 1)
    {
        if (tid < offset)
        {
            s_y[tid] += s_y[tid + offset];
        }
        __syncthreads();
    }

    if (tid == 0)
    {
        atomicAdd(d_y, s_y[0]);
    }
}

real reduce(const real* d_x)
{
    const int grid_size = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;
    const int smem = sizeof(real) * BLOCK_SIZE;

    real h_y[1] = { 0 };
    real* d_y;
    CHECK(cudaMalloc(&d_y, sizeof(real)));
    CHECK(cudaMemcpy(d_y, h_y, sizeof(real), cudaMemcpyHostToDevice));

    reduce << <grid_size, BLOCK_SIZE, smem >> > (d_x, d_y, N);

    CHECK(cudaMemcpy(h_y, d_y, sizeof(real), cudaMemcpyDeviceToHost));
    CHECK(cudaFree(d_y));

    return h_y[0];
}

void timing(const real* d_x)
{
    real sum = 0;

    for (int repeat = 0; repeat < NUM_REPEATS; ++repeat)
    {
        cudaEvent_t start, stop;
        CHECK(cudaEventCreate(&start));
        CHECK(cudaEventCreate(&stop));
        CHECK(cudaEventRecord(start));
        cudaEventQuery(start);

        sum = reduce(d_x);

        CHECK(cudaEventRecord(stop));
        CHECK(cudaEventSynchronize(stop));
        float elapsed_time;
        CHECK(cudaEventElapsedTime(&elapsed_time, start, stop));
        printf("Time = %g ms.\n", elapsed_time);

        CHECK(cudaEventDestroy(start));
        CHECK(cudaEventDestroy(stop));
    }

    printf("sum = %f.\n", sum);
}



在这里插入图片描述

相比于第9篇文章使用共享内存29ms,有了稍微的性能提升

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

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

相关文章

文心一言 VS 讯飞星火 VS chatgpt (28)-- 算法导论5.1 3题

三、假设你希望以1/2的概率输出0与 1。你可以自由使用一个输出0或1的过程 BIASED-RANDOM。它以某概率 p 输出1&#xff0c;概率 1-p 输出0&#xff0c;其中 0<p<1 &#xff0c;但是 p 的值未知。请给出一个利用 BIASED-RANDOM 作为子程序的算法&#xff0c;返回一个无偏的…

pwm led

PWM Dimming (脉冲宽度调制) 调光——是一种利用简单的数字脉冲&#xff0c;反复开关灯光LED驱动器的调光技术。通过程序控制输出宽、窄不同的数字式脉冲&#xff0c;即可简单地实现改变输出电流&#xff08;电压&#xff09;&#xff0c;从而调节LED灯的亮度。 当PWM不是满占空…

真无线蓝牙耳机哪个牌子好用?六款真无线蓝牙耳机品牌推荐

无论我们是看视频还是在路上听音乐&#xff0c;真无线蓝牙耳机可以丰富我们的一天。然而&#xff0c;问题是有太多的选择&#xff0c;许多人不知道哪一款的性价比高音质好&#xff0c;下面小编特意整理了一期性价比高音质好的蓝牙耳机。 第一款&#xff1a;南卡小音舱lite2 蓝…

运维小白必学篇之基础篇第一集:Linux相关命令实验

Linux相关命令实验 实验者&#xff1a;胡 阳 命令提示符 【rootlocalhost ~】# 【当前登录系统的用户主机名 当前工作目录】提示符 &#xff08;# 表示 管理员&#xff09; &#xff08;&#xff04; 表示 普通用户&#xff09; 基本格式&#xff1a;命令 【选项】 【…

一文带你学习前端 - 自动化测试

theme: devui-blue 前端自动化测试 1. 自动化测试基本概念介绍 前言 一般我们实现功能&#xff0c;基本都是两部分写代码&#xff0c;调试/测试。写代码和测试的时间&#xff0c;基本都是55分。如果是测试逻辑&#xff0c;可能要打一下log&#xff0c;或者打断点去调试。测…

行业报告 | 工业机器视觉深度报告——兼具高成长和成熟技术的AI应用赛道

原创 | 文 BFT机器人 01 核心要点 核心观点: 工业机器视觉是高技术壁垒、商业模式成熟、国产替代迅速、行业快速发展的优秀赛道。行业端&#xff1a;3C电子是最主要的行业&#xff0c;新能源行业增速最快&#xff0c;受益于质量管控政策和行业高增速。技术端&#xff1a;大模型…

让工作效率提升10倍:十大AIGC工具评测

AI技术的普及已经在近年来不断增长。这种技术已经改变了我们与电脑的互动方式&#xff0c;让我们能够更高效、更自然地完成任务。本文将展示10个基于ChatGPT和GPT-3 AI模型构建的最强大的资源&#xff0c;使您更容易充分利用它们的潜力。因此&#xff0c;如果您想利用AI技术改进…

DiscoTOC - 自动内容表格

示例 桌面 移动终端 特性 toc table of contents&#xff08;内容列表&#xff09; 通过菜单上面的设置按钮&#xff0c;根据当前内容的状况一键生成 toc 列表Toc 将会一直在页面中尽显显示 —— 滚动内容与 topic 的链接是同步的当你滚动过当前页面中中的主题的时候&#…

Python numpy - 数组的创建与访问

目录 一 数组array的创建途径 1 列表list 2 函数array 3 函数arange 4 函数zeros 5 函数eyes 6 随机函数randn/ randint 二 数组array的访问 1 访问形状/元素个数/数据类型 2 访问一维数组的位置/范围 3 访问二维数组的位置/范围 4 用&#xff1a;访问二维数组的…

美国餐饮连锁集团【CAVA Group】申请纽交所IPO上市

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;来自美国的餐饮连锁集团【CAVA Group】近期已向美国证券交易委员会&#xff08;SEC&#xff09;提交招股书&#xff0c;申请在纽交所IPO上市&#xff0c;股票代码为(CAVA) &#xff0c;CAVA Group…

基于SSM的疫情物资管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

公民开发者学习无代码编程,从CRUD开始

目录 1 创建数据表2 创建新增页面3 新增功能开发4 预览总结 自从Forrester2014年提出低代码的概念后&#xff0c;对于编程人员重新进行了划分。使用传统开发工具&#xff0c;使用代码进行编程的叫专业开发人员。使用低代码或者无代码开发工具&#xff0c;作为企业内部的人员&am…

基于深度学习的高精度老鼠检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度老鼠检测识别系统可用于日常生活中检测与定位老鼠目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的老鼠目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型训练数据…

如何确定bug是前端还是后端的错误?

前言&#xff1a;学会分析一个bug属于前端还是后端的错误&#xff0c;可方便开发快速定位问题&#xff0c;缩短与开发的沟通成本&#xff0c;也是测试人员的必备技能&#xff0c;笔者面试时就曾经被问到过&#xff0c;那就一起分析一波吧。 一、定义bug类型&#xff1a; 1、…

app渗透-抓包

app渗透-1 前言1.模拟器2.抓包工具-Fiddler2.1抓app包2.1.1设置模拟器2.1.2设置fiddler2.1.3使用 2.2抓小程序2.2.1抓包2.2.2解决抓不到https2.2.3解决抓不到包-12.2.4解决抓不到包-22.2.5解决抓不到包-3 前言 不要把app和小程序想的多困难&#xff0c;其实就是一个小的网站塞…

2023-06-01:讲一讲Redis常见数据结构以及使用场景。

2023-06-01&#xff1a;讲一讲Redis常见数据结构以及使用场景。 答案2023-06-01&#xff1a; 字符串&#xff08;String&#xff09; 适合场景 缓存功能 Redis 作为缓存层&#xff0c;MySQL 作为存储层&#xff0c;在大部分请求中&#xff0c;数据的读取通常是从 Redis 中…

Python笔记(更新ing)

目录 第一章 Python初识1、什么是编程语言2、第一个Python程序 第二章 基本语法1、 字面量2、 注释3、 变量4、 数据类型5、 数据类型转换6、 标识符7、 运算符8、 字符串扩展9、 字符串拼接10、 字符串格式化11、 字符串格式化的精度控制12、 字符串格式化的方式二13、 对表达…

deepin安装docker和pytorch

title: deepin安装docker和pytorch date: 2023-06-01 17:28:58 tags: [linux, torch,docker] deepin安装docker和pytorch 总体的流程图大致如下&#xff0c;首先是安装linux&#xff0c;这个直接跳过&#xff0c;接下来就是安装docker&#xff0c;之后&#xff0c;安装docker之…

推动科技教育普惠|2023 开放原子全球开源峰会校源行分论坛即将启幕

科技创新&#xff0c;人才先行&#xff0c;高校作为开源人才培养的主阵地&#xff0c;在开源的发展中扮演着关键角色。 6 月 13 日&#xff0c;2023 开放原子全球开源峰会校源行分论坛将在北京经开区亦创国际会展中心盛大举行。论坛以“聚缘于校、开源共行”为主题&#xff0c;…

上海亚商投顾:沪指冲高回落微涨 AI应用端再度爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日冲高回落&#xff0c;创业板指相对偏强。AI应用端再度爆发&#xff0c;传媒、影视、游戏等方向领涨&a…