【CUDA代码实践02】矩阵加法运算程序

文章目录

      • main.cu
        • 代码工作流程
      • matrixSum.cuh
      • matrixSum.cu
        • 代码结构说明
        • 总体工作流程

近年来,人工智能(AI)技术,尤其是大模型的快速发展,打开了全新的时代大门。对于想要在这个时代迅速成长并提升自身能力的个人而言,学会利用AI辅助学习已经成为一种趋势。不论是国内的文心一言、豆包,还是国外的ChatGPT、Claude,它们都能成为我们编程学习的有力助手。利用AI进行编程学习将大大提升自己的编程学习效率,这里给大家推荐一个我自己在用的集成ChatGPT和Claude的网站(国内可用,站点稳定):传送门

本章节代码详细注释了矩阵加法如何在GPU中运行,分为三个文件,main.cumatrixSum.cuhmatrixSum.cu

在这里插入图片描述

先放上CUDA程序程序基本框架

__global__ void func(args...){核函数内容
}
int main(void)
{设置GPU设备;分配主机和设备内存;数据从主机复制到设备;调用核函数在设备中进行计算;将就计算得到的数据从设备传给主机;释放主机与设备内存;
}

main.cu

代码工作流程
  1. 设置 GPU:使用 setGPU() 函数选择并设置合适的 GPU 设备。如果系统中没有可用的 CUDA 兼容 GPU,则会打印错误并退出程序。

  2. 分配内存

    • 在主机端(CPU)为三个向量 A, B, C 分配内存,并将内存初始化为 0。
    • 在设备端(GPU)为向量 A, B, C 分配内存,并初始化为 0。
  3. 初始化数据:在主机上初始化 AB 两个向量的值(通过 initiaData 随机生成数据)。

  4. 数据传输:将主机端的 AB 向量复制到 GPU 的设备内存中,C 向量也被传输到设备中,以存储计算结果。

  5. 并行计算

    • 通过配置 dim3 的线程块大小和网格大小,决定有多少线程执行并行计算。
    • 使用 addFromGPU 内核函数在设备上进行向量加法。
    • cudaDeviceSynchronize() 确保所有 GPU 线程完成计算后,程序继续执行。
  6. 结果传输:将计算结果 C 从设备端复制回主机端,以便在主机上进行打印。

  7. 结果输出:打印向量 A, BC 的前 10 个元素,验证结果是否正确。

  8. 清理内存:程序结束时,释放主机和设备的内存,重置 GPU 设备,确保资源得到正确释放。

#include "cuda_runtime.h"  // 包含 CUDA 的运行时库头文件
#include <stdio.h>         // 标准输入输出库,用于 printf
#include "./matrixSum.cuh" // 包含自定义的 CUDA 函数声明int main()
{// 设置 GPU 设备setGPU();  // 检测并设置可用的 GPU 设备,确保 GPU 准备好执行计算// 分配主机内存和设备内存,并初始化int iElemCount = 512;  // 设置元素数量,这里假设每个向量有 512 个元素size_t stBytesCount = iElemCount * sizeof(float);  // 计算总共需要的字节数(512 个 float)// (1) 分配主机内存,并初始化float *fpHost_A, *fpHost_B, *fpHost_C;fpHost_A = (float *)malloc(stBytesCount);  // 为向量 A 分配主机内存fpHost_B = (float *)malloc(stBytesCount);  // 为向量 B 分配主机内存fpHost_C = (float *)malloc(stBytesCount);  // 为结果向量 C 分配主机内存if (fpHost_A != NULL && fpHost_B != NULL && fpHost_C != NULL) {memset(fpHost_A, 0, stBytesCount); // 将 A 的内存初始化为 0memset(fpHost_B, 0, stBytesCount); // 将 B 的内存初始化为 0memset(fpHost_C, 0, stBytesCount); // 将 C 的内存初始化为 0}else {printf("fail to malloc memory.\n");  // 如果内存分配失败,输出错误并退出程序exit(-1);}// 分配设备内存,并初始化float *fpDevice_A, *fpDevice_B, *fpDevice_C;cudaMalloc((float **)&fpDevice_A, stBytesCount);  // 为向量 A 分配设备内存cudaMalloc((float **)&fpDevice_B, stBytesCount);  // 为向量 B 分配设备内存cudaMalloc((float **)&fpDevice_C, stBytesCount);  // 为结果向量 C 分配设备内存if (fpDevice_A != NULL && fpDevice_B != NULL && fpDevice_C != NULL) {cudaMemset(fpDevice_A, 0, stBytesCount);  // 将设备内存 A 初始化为 0cudaMemset(fpDevice_B, 0, stBytesCount);  // 将设备内存 B 初始化为 0cudaMemset(fpDevice_C, 0, stBytesCount);  // 将设备内存 C 初始化为 0}else {printf("fail to malloc memory.\n");  // 如果设备内存分配失败,输出错误并退出程序free(fpHost_A);free(fpHost_B);free(fpHost_C);exit(-1);}// 初始化主机数据srand(666);  // 设置随机种子,保证每次生成相同的随机数initiaData(fpHost_A, iElemCount);  // 初始化主机向量 A 的数据initiaData(fpHost_B, iElemCount);  // 初始化主机向量 B 的数据// 将主机数据复制到设备cudaMemcpy(fpDevice_A, fpHost_A, stBytesCount, cudaMemcpyHostToDevice);  // 将 A 复制到设备cudaMemcpy(fpDevice_B, fpHost_B, stBytesCount, cudaMemcpyHostToDevice);  // 将 B 复制到设备cudaMemcpy(fpDevice_C, fpHost_C, stBytesCount, cudaMemcpyHostToDevice);  // 将 C 复制到设备// 调用核函数在设备中进行计算dim3 block(32);  // 定义每个线程块有 32 个线程dim3 grid(iElemCount / block.x);  // 计算需要多少个线程块来处理 512 个元素// 调用 GPU 核函数,执行向量加法addFromGPU<<<grid, block>>>(fpDevice_A, fpDevice_B, fpDevice_C, iElemCount);cudaDeviceSynchronize();  // 同步 CPU 和 GPU,确保 GPU 的计算完成// 将结果从设备复制回主机cudaMemcpy(fpHost_C, fpDevice_C, stBytesCount, cudaMemcpyDeviceToHost);// 打印计算结果中的前 10 个元素for (int i = 0; i <10; i++) {printf("idx=%2d\tmatrix_A:%.2f\tmatrix_B:%.2f\tresult=%.2f\n", i+1, fpHost_A[i], fpHost_B[i], fpHost_C[i]);}// 释放主机与设备内存free(fpHost_A);  // 释放主机内存free(fpHost_B);free(fpHost_C);cudaFree(fpDevice_A);  // 释放设备内存cudaFree(fpDevice_B);cudaFree(fpDevice_C);cudaDeviceReset();  // 重置设备,清理所有资源return 0;  // 程序成功结束
}

matrixSum.cuh

#pragma once
#include <stdlib.h>
#include <stdio.h>extern void setGPU(); // 声明函数,但不定义
extern void addFromCPU(float *A, float *B, float *C, const int N);
extern void initiaData(float *addr, int elemCount);
extern __global__ void addFromGPU(float *A, float *B, float *C, const int N);

matrixSum.cu

代码结构说明
  1. addFromGPU 内核函数

    • 功能:在 GPU 上并行执行向量加法。每个线程处理向量的一个元素。

    • 执行逻辑

      • 通过 blockIdx.xthreadIdx.x 计算每个线程在整个网格中的全局索引 id,确保每个线程都对应唯一的数组元素。
      • 使用 if (id < N) 进行边界检查,避免数组越界访问。
      • 使用 printf 打印当前线程的索引信息,用于调试。
      • 每个线程执行向量加法 C[id] = A[id] + B[id]
  2. initiaData 函数

    • 功能:初始化一个浮点数数组(向量),每个元素是一个随机生成的值,用于测试向量加法。

    • 执行逻辑

      • 使用 rand() 生成随机数,并将其转换为浮点数格式,填充数组 addr
  3. setGPU 函数

    • 功能:检测系统中可用的 GPU 数量,并设置使用指定的 GPU 设备(默认为设备 0)。

    • 执行逻辑

      • 调用 cudaGetDeviceCount 获取系统中可用的 GPU 数量。
      • 如果没有找到可用的 GPU,程序退出。
      • 调用 cudaSetDevice 设置当前使用的 GPU 设备(设备 0)。
      • 检查 cudaSetDevice 是否成功,如果失败则退出程序。
总体工作流程
  1. 通过 setGPU() 检测系统中可用的 GPU 并选择一个 GPU 设备。
  2. 调用 initiaData() 函数生成随机数据,初始化向量 A 和 B。
  3. 使用 addFromGPU 内核函数在 GPU 上并行执行向量加法,每个线程处理向量的一部分,最终计算出向量 C。
#include "matrixSum.cuh" // 包含自定义头文件,通常用于声明函数和变量,这里可能包含 CUDA 函数的声明// 内核函数 (kernel function) addFromGPU,负责在 GPU 上进行向量加法
// 参数:
// - float* A: 输入向量 A 的设备指针
// - float* B: 输入向量 B 的设备指针
// - float* C: 输出向量 C 的设备指针
// - const int N: 向量中元素的数量
__global__ void addFromGPU(float *A, float *B, float *C, const int N)
{// blockIdx.x 表示当前线程块 (block) 的 x 维索引// threadIdx.x 表示当前线程 (thread) 在线程块中的 x 维索引const int bid = blockIdx.x;        // 当前线程所在的线程块的索引const int tid = threadIdx.x;       // 当前线程在线程块内的索引const int id = bid * blockDim.x + tid;  // 计算全局索引 (global index)// 计算线程在整个线程网格中的唯一ID,用于确定当前线程负责的元素// blockDim.x 表示每个线程块中的线程数,这里通过线程块索引 (bid) 和线程索引 (tid) 计算唯一的全局索引// 边界检查:确保 id 不会超出向量的大小,避免访问越界的内存if (id < N) {// 打印当前线程的 block ID、thread ID 和计算出的全局索引 idprintf("bid = %d\ttid = %d\tid = %d\n", bid, tid, id);// 执行向量加法,计算 C[id] = A[id] + B[id],每个线程负责一个元素的加法C[id] = A[id] + B[id];}
}// 初始化数据的函数,将随机生成的数据填充到向量中
// 参数:
// - float* addr: 指向需要初始化的向量的指针
// - int elemCount: 向量中的元素数量
void initiaData(float *addr, int elemCount)
{// 循环填充每个元素,生成随机数 (0-255) 的浮点表示,范围在 0 到 25.5 之间for (int i = 0; i < elemCount; i++){addr[i] = (float)(rand() & 0xFF) / 10.f;  // 取 0 到 255 之间的随机整数,并转换为浮点数}return;  // 函数结束,返回主程序
}// 设置 GPU 的函数,用于检测可用 GPU 并选择设备
void setGPU()
{int iDeviceCount = 0;  // 存储 GPU 的数量cudaError_t error = cudaGetDeviceCount(&iDeviceCount);  // 获取可用的 GPU 设备数量// 检查是否存在可用的 CUDA 兼容设备if (error != cudaSuccess || iDeviceCount == 0) {printf("No CUDA compatible GPU found\n");exit(-1);  // 如果没有找到 GPU,程序终止}else {printf("The count of GPUs is %d.\n", iDeviceCount);  // 打印检测到的 GPU 数量}// 选择设备 0(如果有多个 GPU,这里默认选择第一个 GPU)int iDevice = 0;error = cudaSetDevice(iDevice);  // 设置当前使用的 GPU 设备// 检查是否成功设置 GPUif (error != cudaSuccess) {printf("cudaSetDevice failed! \n");  // 如果设置失败,打印错误信息并退出exit(-1);}else {printf("cudaSetDevice success! \n");  // 成功设置 GPU}
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s可以部署私有云吗?私有云部署全攻略

k8s可以部署私有云吗&#xff1f;K8S可以部署私有云。Kubernetes是一个开源的容器编排引擎&#xff0c;能够自动化容器的部署、扩展和管理&#xff0c;使得应用可以在各种环境中高效运行。通过使用Kubernetes&#xff0c;企业可以在自己的数据中心或私有云环境中搭建和管理容器…

OpenSSH_8.7 无法使用密码登录问题解决

文章目录 前言SSH 版本 配置 SSH 密码登录其它总结个人简介 前言 最近使用 Crunchbits VPS&#xff08;virt.crunchbits.com&#xff09; 时&#xff0c;由于更换电脑导致认证的 ssh 秘钥丢失&#xff0c;尝试 SSH 密码登录时遇到如下错误提示&#xff1a;Permission denied (…

探索 Python 幽默之源:pyjokes 库全解析

&#x1f680; 探索 Python 幽默之源&#xff1a;pyjokes 库全解析 1. 背景介绍&#xff1a;为何选择 pyjokes&#xff1f; 在紧张的编程工作中&#xff0c;幽默是一种有效的缓解压力的方式。pyjokes 是一个专为程序员设计的 Python 库&#xff0c;它提供了丰富的单行笑话&am…

【Dv2Admin】Django配置线上ws反向代理

在 Web 应用程序的部署过程中,安全性、稳定性和实时通信是开发者们普遍关注的重点。Django 是一个非常流行的 Web 框架,常与 Nginx 配合使用,以便实现反向代理、负载均衡以及 SSL 加密等功能。除此之外,实时功能(如 WebSocket)也是现代应用中经常使用的技术。 在项目中实…

Fast Simulation of Mass-Spring Systems in Rust 论文阅读

参考资料&#xff1a; Fast Simulation of Mass-Spring Systems in Rust 论文阅读&#xff1a;Fast Simulation of Mass-Spring Systems 【论文精读】讲解刘天添2013年的fast simulation of mass spring system(Projective Dynamics最早的论文) Projective Dynamics笔记(一…

uniapp圆形波浪进度效果

uniapp圆形波浪进度效果 背景实现思路代码实现尾巴 背景 最近项目中有些统计的地方需要用到圆形的波浪进度效果&#xff0c;要求是根据百分比值然后在一个圆形内动态的展示一个波浪形的进度&#xff0c;看参考一下效果。 实现思路 这个效果看着挺复杂的&#xff0c;那么我们…

【Linux】磁盘文件系统(inode)、软硬链接

文章目录 1. 认识磁盘1.1 磁盘的物理结构1.2 磁盘的逻辑结构 2. 引入文件系统2.1 EXT系列文件系统的分区结构2.2 inode 3. 软硬链接3.1 软链接3.2 硬链接 在讲过了内存文件系统后&#xff0c;我们可以知道文件分为两种&#xff1a; 打开的文件&#xff08;内存中&#xff09;未…

如何提高英语口语表达能力?

提高英语口语表达能力是一个逐步积累和实践的过程。 1. 自我练习方法 录音与回听 录音&#xff1a;用手机或其他设备录下自己的口语练习&#xff0c;比如描述一天的活动、讲述一个故事或复述一篇文章。 回听&#xff1a;仔细听录音&#xff0c;找出发音、语法和流利度方面的问…

【设计模式-状态模式】

状态模式&#xff08;State Pattern&#xff09;是一种行为设计模式&#xff0c;它允许一个对象在内部状态改变时改变它的行为。换句话说&#xff0c;这种模式让对象在不同的状态下能够表现出不同的行为&#xff0c;而不需要修改对象的代码。状态模式通过将对象的行为与状态进行…

node集成redis (教学)

文章目录 前言一、安装redis二、可视化界面测试连接1.vscode安装插件 三、node代码编写1.先安装两个库&#xff08;redis和ioredis&#xff09;2.测试连接 &#xff08;前提是你的redis服务器要启动起来&#xff09; 总结 前言 在Node.js中集成ioredis是一个常见的做法&#x…

vscode配色主题与图标库推荐

vscode配色主题推荐:Andromedavsocde图标库&#xff1a; vscode-icons Andromeda Dark theme with a taste of the universe 仙女座&#xff1a;一套宇宙深空体验的哑暗色主题; 高对比度,色彩饱和; Easy Installation Open the extensions sidebar on Visual Studio CodeSear…

【LeetCode:263. 丑数 + 数学】

在这里插入代码片 &#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕…

apply call bind 简介

Function.prototype.call(thisArg [, arg1, arg2, …]) call() 简述 call() 方法 调用一个函数, 其具有一个指定的 this 值和分别地提供的参数(参数的列表)。当第一个参数为 null、undefined 的时候&#xff0c; 默认 this 上下文指向window。 call() 简单实例 const name …

【项目复现】——DDoS-SDN Detection Project

文章目录 概要整体架构流程1. 系统和网络配置2. SDN控制器配置3. 流量生成4. 数据采集5. DDoS检测机制6. 机器学习模型训练7. 实时检测部署 前期准备复现流程第一步&#xff1a;系统和网络配置1.1 安装和设置操作系统1.2 安装VirtualBox和Mininet1.3 创建SDN网络拓扑 第二步&am…

探索现代软件开发中的持续集成与持续交付(CI/CD)实践

探索现代软件开发中的持续集成与持续交付&#xff08;CI/CD&#xff09;实践 随着软件开发的飞速进步&#xff0c;现代开发团队已经从传统的开发模式向更加自动化和灵活的开发流程转变。持续集成&#xff08;CI&#xff09; 与 持续交付&#xff08;CD&#xff09; 成为当下主…

w~自动驾驶合集6

我自己的原文哦~ https://blog.51cto.com/whaosoft/12286744 #自动驾驶的技术发展路线 端到端自动驾驶 Recent Advancements in End-to-End Autonomous Driving using Deep Learning: A SurveyEnd-to-end Autonomous Driving: Challenges and Frontiers 在线高精地图 HDMa…

iOS AVAudioSession 详解【音乐播放器的配置】

前言 在 iOS 音频开发中&#xff0c;AVAudioSession 是至关重要的工具&#xff0c;它控制着应用的音频行为&#xff0c;包括播放、录音、后台支持和音频中断处理等。对于音乐播放器等音频需求强烈的应用&#xff0c;设计一个合理的 AVAudioSession 管理体系不仅能保证音频播放…

三周精通FastAPI:16 Handling Errors处理错误

官网文档&#xff1a;https://fastapi.tiangolo.com/zh/tutorial/handling-errors 处理错误 某些情况下&#xff0c;需要向客户端返回错误提示。 这里所谓的客户端包括前端浏览器、其他应用程序、物联网设备等。 需要向客户端返回错误提示的场景主要如下&#xff1a; 客户端…

FastAPI、langchain搭建chatbot,langgraph实现历史记录

环境&#xff1a;openEuler、python 3.11.6、Azure openAi、langchain 0.3.3、langgraph 0.2.38 背景&#xff1a;基于FastAPI、langchain实现一个QA系统&#xff0c;要求实现历史记录以及存储特征信息 时间&#xff1a;20241022 说明&#xff1a;在历史记录的存储中&…

R语言机器学习算法实战系列(十四): CatBoost分类算法+SHAP值 (categorical data gradient boosting)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍CatBoost的原理CatBoost的步骤教程下载数据加载R包导入数据数据预处理数据描述数据切割设置数据对象调节参数训练模型预测测试数据评估模型模型准确性混淆矩阵模型评估指标ROC Curv…