CUDA By Example笔记--线程协作

news2025/7/25 6:46:50

1--使用线程实现GPU上的矢量求和

        完整代码:

# include <iostream>
# define N (33 * 1024)

__global__ void add(int* a, int* b, int* c){
    int tid = threadIdx.x + blockIdx.x * blockDim.x;
    while (tid < N){
        c[tid] = a[tid] + b[tid];
        tid += blockDim.x * gridDim.x;
    }
}

int main(void){
    int a[N], b[N], c[N];
    int *dev_a, *dev_b, *dev_c;

    // 在 GPU 分配内存
    cudaMalloc( (void**)&dev_a, N * sizeof(int));
    cudaMalloc( (void**)&dev_b, N * sizeof(int));
    cudaMalloc( (void**)&dev_c, N * sizeof(int));

    // 在 cpu 上赋值
    for(int i = 0; i < N; i++){
        a[i] = i;
        b[i] = i * i;
    }

    // 将数据复制到GPU
    cudaMemcpy(dev_a, a, N*sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(dev_b, b, N*sizeof(int), cudaMemcpyHostToDevice);

    add<<<128, 128>>>(dev_a, dev_b, dev_c);
    cudaMemcpy(c, dev_c, N*sizeof(int), cudaMemcpyDeviceToHost);

    // 验证是否正确执行
    bool success = true;
    for(int i = 0; i < N; i++){
        if((a[i] + b[i]) != c[i]){
            printf("Error: %d + %d != %d\n", a[i], b[i], c[i]);
            success = false;
        }
    }

    if(success) printf("We did it! \n");
    
    // 释放内存
    cudaFree(dev_a);
    cudaFree(dev_b);
    cudaFree(dev_c);

    return 0;
}

        核心代码分析:

add<<<128, 128>>>(dev_a, dev_b, dev_c);

        第一个参数 128 表示创建 128 个线程块,第二个参数 128 表示每个线程块包含 128 个线程,即创建了 128 × 128 个并行线程;

int tid = threadIdx.x + blockIdx.x * blockDim.x;

        计算每一个线程在所有线程中对应的索引值,threadIdx.x表示线程的索引,blockIdx.x表示线程块的索引,blockDim.x表示一个线程块的x长度;

while (tid < N){
    c[tid] = a[tid] + b[tid];
    tid += blockDim.x * gridDim.x;
}

        由于设置的线程块数目为 128,每个线程块线程的数目也是 128,共有 128 × 128 个并行线程,因此一次只能处理 128 × 128 个数据;

        每次处理完 128 × 128 个数据后,索引值需要增加 128 × 128,即 tid += blockDim.x * gridDim.x;

2--使用线程实现波纹效果

        完整代码:

#include "cuda.h"
#include "./common/book.h"
#include "./common/cpu_anim.h"

#define DIM 1024
#define PI 3.1415926535897932f

__global__ void kernel( unsigned char *ptr, int ticks ) {
    // map from threadIdx/BlockIdx to pixel position
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;

    // now calculate the value at that position
    float fx = x - DIM/2;
    float fy = y - DIM/2;
    float d = sqrtf( fx * fx + fy * fy );
    unsigned char grey = (unsigned char)(128.0f + 127.0f *
                                         cos(d/10.0f - ticks/7.0f) /
                                         (d/10.0f + 1.0f));    
    ptr[offset*4 + 0] = grey;
    ptr[offset*4 + 1] = grey;
    ptr[offset*4 + 2] = grey;
    ptr[offset*4 + 3] = 255;
}

struct DataBlock {
    unsigned char   *dev_bitmap;
    CPUAnimBitmap  *bitmap;
};

void generate_frame( DataBlock *d, int ticks ) {
    dim3    blocks(DIM/16, DIM/16);
    dim3    threads(16, 16);
    kernel<<<blocks, threads>>>( d->dev_bitmap, ticks );

    HANDLE_ERROR( cudaMemcpy( d->bitmap->get_ptr(),
                              d->dev_bitmap,
                              d->bitmap->image_size(),
                              cudaMemcpyDeviceToHost ) );
}

void cleanup( DataBlock *d ) {
    HANDLE_ERROR( cudaFree( d->dev_bitmap ) ); 
}

int main( void ) {
    DataBlock   data;
    CPUAnimBitmap  bitmap( DIM, DIM, &data );
    data.bitmap = &bitmap;

    HANDLE_ERROR( cudaMalloc( (void**)&data.dev_bitmap,
                              bitmap.image_size() ) );

    bitmap.anim_and_exit( (void (*)(void*,int))generate_frame,
                            (void (*)(void*))cleanup );
}

        CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)

project(Test1 LANGUAGES CUDA) # 添加支持CUDA语言
add_executable(main Test0307_2.cu)
target_link_libraries(main -lglut -lGLU -lGL)

        核心代码分析:

dim3    blocks(DIM/16, DIM/16);
dim3    threads(16, 16);
kernel<<<blocks, threads>>>( d->dev_bitmap, ticks );

        创建二维索引值的线程块和创建二维索引值的线程;

        每一个线程有唯一的索引 (x, y);

        在上述代码中,一副图像共有 DIM × DIM个像素,创建了 DIM/16 × DIM/16 个线程块,每一个线程块包含 16 × 16 个线程,一共有DIM × DIM个并行线程;因此每一个线程对应一个像素,每一个线程处理一个像素;

__global__ void kernel( unsigned char *ptr, int ticks ) {
    // map from threadIdx/BlockIdx to pixel position
    int x = threadIdx.x + blockIdx.x * blockDim.x;
    int y = threadIdx.y + blockIdx.y * blockDim.y;
    int offset = x + y * blockDim.x * gridDim.x;

    // 生成波纹的代码
    float fx = x - DIM/2;
    float fy = y - DIM/2;
    float d = sqrtf( fx * fx + fy * fy );
    unsigned char grey = (unsigned char)(128.0f + 127.0f *
                                         cos(d/10.0f - ticks/7.0f) /
                                         (d/10.0f + 1.0f));    
    ptr[offset*4 + 0] = grey;
    ptr[offset*4 + 1] = grey;
    ptr[offset*4 + 2] = grey;
    ptr[offset*4 + 3] = 255;
}

每一个线程的索引 (x, y) 通过以下代码进行计算:

        int x = threadIdx.x + blockIdx.x * blockDim.x;
        int y = threadIdx.y + blockIdx.y * blockDim.y;

其偏移量通过以下代码进行计算:

        int offset = x + y * blockDim.x * gridDim.x;

未完待续!

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

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

相关文章

pyqt 小项目

此项目是别人用Q开发的&#xff0c;我模仿用Pyqt编写。仿写过程种发下c 和python在调用时还是有些不一样。遇到行不通时就要多尝试别的方法。不如在C里可以直接在cpp文件里传入QBrush和QPen对象&#xff0c;而在python里就不行&#xff0c;估计使用信号与槽可以&#xff08;本人…

IfcRepresentationContext 与 IfcRepresentation

IfcRepresentationContext 与 IfcRepresentation 1. IfcRepresentationContext IfcRepresentationContext 定义了成果&#xff08;Product&#xff09;的IfcRepresentation相关上下文。 The IfcRepresentationContext defines the context to which the IfcRepresentation of…

通过堆栈分析深拷贝、浅拷贝、赋值的差异

前言数据类型分为&#xff1a;基本数据类型String、Number、Boolean、Null、Undefined、Symbol对象数据类型Object、Array基本数据类型的特点&#xff1a;直接存储在栈(stack)中的数据引用数据类型的特点&#xff1a;存储的是该对象在栈中引用&#xff0c;真实的数据存放在堆内…

云原生时代顶流消息中间件Apache Pulsar部署实操之轻量级计算框架

文章目录Pulsar Functions(轻量级计算框架)基础定义工作流程函数运行时处理保证和订阅类型窗口函数定义窗口类型滚动窗口滑动窗口函数配置函数示例有状态函数示例窗口函数示例自定义函数开发定义原生语言接口示例Pulsar函数SDK示例Pulsar Functions(轻量级计算框架) 基础定义 …

实验一:递归

1.铺砖 题目描述&#xff1a; 对于一个2行N列的走道。现在用12或22的砖去铺满。问有多少种不同的方式&#xff08;请用递推方式求解&#xff09;。如果N很大&#xff0c;需要高精度计算。下图是一个2行17列的走道的某种铺法&#xff1a; 输入要求&#xff1a; 一个整数N&a…

GitHub Copilot 全新升级,工作效率提升 55%

2021年 6 月&#xff0c;GitHub 和 OpenAI 推出了 GitHub Copilot 预览版&#xff0c;可根据命名或者正在编辑的代码上下文为开发者提供代码建议&#xff0c;被称为“你的 AI 结对程序员”。 近日&#xff0c;GitHub 宣布&#xff0c;经过去年 12 月以来的短暂测试后&#xff…

Spring基本概念与使用

文章目录一、Spring概念1.容器2.IoC3.DI4.Ioc与DI的关系二、Spring创建与使用1.Maven2.添加Spring框架支持注&#xff1a;国内的Maven源配置3.简单实例&#xff08;1&#xff09;创建一个Bean对象。&#xff08;2&#xff09;将Bean对象存储到Spring当中&#xff08;3&#xff…

JavaWeb基础

Servlet 是在服务器上运行的小程序。这个词是在 Java applet的环境中创造的&#xff0c;Java applet 是一种当作单独文件跟网页一起发送的小程序&#xff0c;它通常用于在客户端运行&#xff0c;结果得到为用户进行运算或者根据用户互作用定位图形等服务。服务器上需要一些程序…

Jenkins最新版安装调试

清理旧的jenkins&#xff1a; find / -name jenkins* 一项一项的清理&#xff1a;rm -rf /var/log/jenkins* 下载最新版jenkins镜像&#xff1a;jenkins-redhat-stable安装包下载_开源镜像站-阿里云 上传到服务器&#xff1a; 安装命令&#xff1a; yum install -y jenkins…

Excel不愧是宝藏游戏机

你玩过95版Excel自带的游戏彩蛋吗&#xff1f; 众所周知&#xff0c;微软有做彩蛋的传统&#xff0c;这个传统最早是在1979年由比尔盖茨写下的basic复活节彩蛋开始的&#xff0c;当时你只需要输入“WAIT6502,1″,就可以跳出“MICROSOFT!”字符串。到后来&#xff0c;全体微软开…

Redis学习(六):主从复制,发布订阅和实际可能遇到缓存失效的情况

Redis发布订阅 Redis发布订阅&#xff08;Public/Subscribe&#xff09;是一种消息通信模式&#xff1a;发送者发送消息&#xff0c;订阅者接收消息。 Redis客户端可以订阅任意数量的频道。 这张图里有三个角色&#xff1a; 消息发送者频道&#xff08;消息队列&#xff09;…

AIGC时代,大模型微调如何发挥最大作用?

人工智能的快速发展推动了大模型的广泛应用&#xff0c;它们在语言、视觉、语音等领域的应用效果已经越来越好。但是&#xff0c;训练一个大模型需要巨大的计算资源和时间&#xff0c;为了减少这种资源的浪费&#xff0c;微调已经成为一种流行的技术。微调是指在预训练模型的基…

2023年3月全国DAMA-CDGA/CDGP数据管理认证火热报名中...

弘博创新是DAMA中国授权的数据治理人才培养基地&#xff0c;贴合市场需求定制教学体系&#xff0c;采用行业资深名师授课&#xff0c;理论与实践案例相结合&#xff0c;快速全面提升个人/企业数据治理专业知识与实践经验&#xff0c;通过考试还能获得数据专业领域证书。 DAMA认…

【iOS】—— 浅看block源码

block 文章目录block如何通过终端clang生成源码cpp文件block实质截获自动变量全局变量和静态变量的截获__block说明符iOS开发“强弱共舞”——weak和strong配套使用解决block循环引用问题如何通过终端clang生成源码cpp文件 之前在学习block中学习的比较浅&#xff0c;只看了oc…

sentinel源码入门

sentinel是一个流量治理组件&#xff0c;主要用来做降级、熔断和限流&#xff0c;以及监控等&#xff0c;sentinel的使用相对来说比较简单&#xff0c;这篇博客主要介绍sentinel的源码 入口 在使用sentinel的时候&#xff0c;我们需要引入sentinel的相关jar包&#xff0c;然后…

如何使用码匠连接 ClickHouse

目录 在码匠中集成 ClickHouse 在码匠中使用 ClickHouse 关于码匠 ClickHouse 数据源是一种列式数据库管理系统&#xff0c;由俄罗斯 Yandex 公司开发和维护。它专注于高性能、高并发、高可扩展性和低延迟的数据处理&#xff0c;特别是在海量数据的 OLAP&#xff08;联机分析…

性能分析利器:火焰图

什么是火焰图 火焰图&#xff08;FlameGraph&#xff09;是是由 Linux 性能优化大师 Brendan Gregg 发明的。通过 perf 等工具分析得到结果&#xff0c;看起来就像是火焰&#xff0c;这也是它的名字的由来。火焰图以一个全局的视野来看待时间分布&#xff0c;它从底部往顶部&am…

Dockerfile部署SpringBoot项目

Dockerfile部署SpringBoot项目 文章目录 利用Dockerfile部署SpringBoot项目 1、创建一个SpringBooot项目并且打成jar包2、在Linux中创建一个文件夹&#xff0c;来做docker测试3、将jar包上传到Linux中4、编写Dockerfile文件5、制作镜像6、启动容器7、查看容器启动日志8、访问接…

高效能自动化港口数字化码头智慧港航,中国人工智能企业CIMCAI世界港航人工智能领军者,成熟港口码头人工智能产品中国人工智能企业

打造高效能自动化港口数字化码头智慧港航&#xff0c;中国人工智能企业CIMCAI中集飞瞳世界港航人工智能领军者&#xff0c;成熟港口码头人工智能产品全球顶尖AI科技CIMCAI成熟AI产品全球前三船公司及港口落地&#xff0c;包括全球港口/堆场智能闸口验箱&#xff0c;全球港口岸边…

Vulnhub系列:Raven 1

该篇为Vulnhub系列靶机渗透&#xff0c;本次靶机存在4个flag。下面开始我们今天的渗透之旅。Raven靶机有很多种思路&#xff0c;我将对其进行一一整理。首先进行信息收集&#xff0c;利用arp-scan和nmap&#xff0c;进行靶机的ip及端口扫描发现了22、80、111端口。下面访问80端…