C++开发基础之初探CUDA计算环境搭建

一、前言

项目中有使用到CUDA计算的相关内容。但是在早期CUDA计算环境搭建的过程中,并不是非常顺利,编写此篇文章记录下。对于刚刚开始研究的你可能会有一定的帮助。

二、环境搭建

搭建 CUDA 计算环境涉及到几个关键步骤,包括安装适当的 CUDA 驱动程序和工具包、设置开发环境和编译器,以及编写和运行 CUDA 程序。感谢Davis lee详细的介绍 CUDA安装及环境配置——最新详细版以下是一个基本的搭建过程:

步骤 1:检查硬件兼容性

首先,确保的计算机上的 GPU 支持 CUDA。可以在 NVIDIA 的官方网站上查找 GPU 的型号以确定其是否支持 CUDA。
在这里插入图片描述

步骤 2:安装 CUDA 驱动程序

访问 NVIDIA 的官方网站,下载并安装与你的 GPU 兼容的最新 CUDA 驱动程序。安装过程中,根据向导提示进行操作。
在这里插入图片描述

步骤 3:安装 CUDA 工具包

下载并安装与你的 CUDA 驱动程序版本相匹配的 CUDA 工具包。CUDA 工具包中包含了编译器、库和工具,用于开发和运行 CUDA 程序。

https://developer.nvidia.com/cuda-downloads

步骤 4:安装适当的开发环境

你可以使用多种开发环境来编写 CUDA 程序,如 NVIDIA 提供的 CUDA Toolkit 中自带的 nvcc 编译器,或者集成了 CUDA 开发支持的 IDE,如 Visual Studio(需要安装适当的 CUDA 插件)或 JetBrains 的 CLion 等。

步骤 5:设置环境变量

在你的操作系统中设置 CUDA 相关的环境变量,包括 PATHCUDA_PATH 等,以便系统可以找到 CUDA 工具和库。

步骤 6:编写和编译 CUDA 程序

使用你选择的开发环境编写 CUDA 程序,并使用 CUDA 编译器(如 nvcc)编译程序。确保您的程序正确地链接了 CUDA 库,并且编译选项正确设置。

步骤 7:运行 CUDA 程序

将编译生成的可执行文件部署到你的计算机上,并在 CUDA 支持的环境中运行程序。你可能需要在程序运行时指定相应的 GPU 设备。

总之就是,在搭建时适配自己的电脑配置要求。做到最新即可。

三、实践编码过程

新增一个空的解决方案,我们命名为VectorProject.sln。

3.1 使用CUDA编写动态库

1、新增动态链接库 ,命名为VectorLibrary;

2、配置CUDA编译环境:
生成依赖项–>生成自定义
在这里插入图片描述
选择CUDA 12.3(targets,props)
在这里插入图片描述
这里如果不配置CUDA编译环境,会报错,无法正常编译通过的。配置完成后,可以查看项目的属性页。能看到CUDA C/C++配置部分
在这里插入图片描述
3、编写接口代码

这里主要定义两个向量的加法运算。

#pragma once
#include "pch.h"
#include <Windows.h>#ifdef VECTOR_LIBRARY_EXPORTS
#define VECTOR_LIBRARY_API __declspec(dllexport)
#else
#define VECTOR_LIBRARY_API __declspec(dllimport)
#endifBOOL VECTOR_LIBRARY_API vectorAddCPU(const float* A, const float* B, float* C, int N);
BOOL VECTOR_LIBRARY_API vectorAddGPU(const float* A, const float* B, float* C, int N);

4、编写CPU方法实现过程

// 封装CUDA函数的C++代码
#include "pch.h"
#include "vectorAdd.h"// CPU上的向量加法函数BOOL vectorAddCPU(const float* A, const float* B, float* C, int N)
{for (int i = 0; i < N; ++i) {C[i] = A[i] + B[i];}return true;
}

5、编写GPU方法实现过程
新增一个核函数声明文件 kernelVectorAdd.cuh

#include <iostream>
void kernelVectorAdd(const float* A, const float* B, float* C, int N);

编写核函数实现

#include <cuda_runtime.h>
#include <iostream>
#include <vector>
#include <device_launch_parameters.h>
#include "kernelVectorAdd.cuh"// CUDA核函数:在GPU上执行的向量加法
__global__ void kernelVectorAddImp(const float* A, const float* B, float* C, int N) {int i = blockDim.x * blockIdx.x + threadIdx.x;if (i < N) {C[i] = A[i] + B[i];}
}void kernelVectorAdd(const float* A, const float* B, float* C, int N) {float* d_A, * d_B, * d_C;size_t size = N * sizeof(float);// 分配设备内存cudaMalloc(&d_A, size);cudaMalloc(&d_B, size);cudaMalloc(&d_C, size);// 将数据从主机内存复制到设备内存cudaMemcpy(d_A, A, size, cudaMemcpyHostToDevice);cudaMemcpy(d_B, B, size, cudaMemcpyHostToDevice);// 执行CUDA核函数int threadsPerBlock = 256;int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock;kernelVectorAddImp <<<blocksPerGrid, threadsPerBlock >>> (d_A, d_B, d_C, N);// 等待所有CUDA核函数执行完毕cudaDeviceSynchronize();// 将结果从设备内存复制回主机内存cudaMemcpy(C, d_C, size, cudaMemcpyDeviceToHost);// 释放设备内存cudaFree(d_A);cudaFree(d_B);cudaFree(d_C);
}

在编写核函数调用的C++代码

// 封装CUDA函数的C++代码
#include "pch.h"
#include "kernelVectorAdd.cuh"
#include "vectorAdd.h"BOOL vectorAddGPU(const float* A, const float* B, float* C, int N) {kernelVectorAdd(A, B, C, N);return true;
}

这里需要把核函数进行封装,否则会报错,相关解决办法可见 关于CUDA C 项目中“ error C2059: 语法错误:“<” ”问题的解决方法.

6、现在我们编译下项目
在这里插入图片描述

3.2 编写C++控制台程序

1、新增C++控制台程序,VectorCpp
在这里插入图片描述
2、配置VectorLibrary.dll的引用
打开属性页,找到C/C++目录,附加包含目录添加配置

$(SolutionDir)VectorLibrary;

在这里插入图片描述
链接器–>常规–>附加库目录

$(TargetDir);%(AdditionalLibraryDirectories)

在这里插入图片描述
链接器–>输入–>附加依赖项

VectorLibrary.lib;%(AdditionalDependencies)

在这里插入图片描述
配置完成这些,就可以对VectorLibrary.dll正常引用了。

2、编写调用代码

// CudaWrapper.cpp
#include "pch.h"
#include <iostream>
#include <random>
#include <chrono>
#include "vectorAdd.h"// 生成随机数并填充到数组
void generateRandomNumbers(float* array, int N) {unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();std::default_random_engine generator(seed);std::uniform_real_distribution<float> distribution(0.0, 1.0); // 范围从0到1之间for (int i = 0; i < N; ++i) {array[i] = distribution(generator);}
}int main()
{int N = 1000000;float* pA = new float[N];float* pB = new float[N];float* pC_GPU = new float[N];float* pC_CPU = new float[N];// 为pA和pB生成随机数generateRandomNumbers(pA, N);generateRandomNumbers(pB, N);// 测量 CPU 端向量加法函数的执行时间auto start_cpu = std::chrono::high_resolution_clock::now();vectorAddCPU(pA, pB, pC_CPU, N);auto end_cpu = std::chrono::high_resolution_clock::now();std::chrono::duration<double> elapsed_cpu = end_cpu - start_cpu;std::cout << "CPU 端向量加法函数的执行时间: " << elapsed_cpu.count() << " 秒" << std::endl;// 测量 GPU 端向量加法函数的执行时间auto start_gpu = std::chrono::high_resolution_clock::now();vectorAddGPU(pA, pB, pC_GPU, N);auto end_gpu = std::chrono::high_resolution_clock::now();std::chrono::duration<double> elapsed_gpu = end_gpu - start_gpu;std::cout << "GPU 端向量加法函数的执行时间: " << elapsed_gpu.count() << " 秒" << std::endl;// 验证结果for (int i = 0; i < N; ++i){if ((pC_CPU[i] - pC_GPU[i]) > 1e-5){std::cout << "结果不匹配" << std::endl;break;}}std::cout << "结果匹配" << std::endl;// 记得释放内存delete[] pA;delete[] pB;delete[] pC_CPU;delete[] pC_GPU;return 0;
}

3、运行程序
完整的项目结构
在这里插入图片描述
运行结果
在这里插入图片描述
在这个示例中,成功运行得出结果。这个时候,你会发现为什么CPU的计算结果远远高于GPU。那是因为:

  • 数据传输开销:在CUDA中,数据必须在主机(CPU)和设备(GPU)之间进行传输。在每次调用CUDA函数之前和之后,都需要将数据从主机内存复制到设备内存,然后将结果从设备内存复制回主机内存。这些数据传输的开销会降低CUDA的性能,特别是当数据量较大时。
  • Kernel调用开销:在CUDA中,每次调用核函数都需要一定的开销,包括启动核函数、将数据传递给核函数、核函数在GPU上执行等。如果向量大小较小,核函数的启动开销可能会占据相当大的比例,从而降低CUDA的性能。
  • 并行化效率不佳:在某些情况下,CUDA核函数可能无法充分利用GPU的并行计算能力。这可能是因为向量大小太小,无法充分填充GPU的计算单元,或者核函数的计算密度不够高,无法实现最大的并行化效率。
  • 内存访问模式:CUDA核函数的性能受到内存访问模式的影响。如果核函数中的内存访问模式不利于GPU的缓存和内存访问优化,性能可能会受到影响。

究其根本原因就是,这个算法太简单了,CPU就可以搞定,用不上GPU。

四、总结

在这个项目中,我们主要体会框架的用法,以及CUDA计算环境搭建的。通过编码实践,构建项目成功实验了CUDA计算环境搭建,为接下来的工作准备好环境。

五、参考文档

错误 MSB4062 未能从程序集加载任务

VS加载CUDA项目出错:未找到导入的项目

整理:warning LNK4098: 默认库“LIBCMT”与其他库的使用冲突;请使用 /NODEFAULTLIB:library

Win10下在VS2019中配置使用CUDA进行加速的C++项目 (配置.h文件,.dll以及.lib文件等)

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

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

相关文章

分析示例 | Simufact焊接工艺仿真变形精确预测汽车结构

导语 焊接是汽车制造过程中一个关键环节&#xff0c;白车身、发动机、底盘和变速箱等都离不开焊接工艺的应用&#xff0c;主要涉及气保焊、电阻点焊、激光焊、电子束焊等多种焊接工艺。由于汽车车型众多、成形结构复杂、汽车制造质量、效率、成本等方面的综合要求。如何高效、…

杰理AC632N提升edr的hid传输速率, 安卓绝对坐标触摸点被识别成鼠标的修改方法

第一个问题: 首先修改edr的hid传输速率.修改你的板级配置,里面的一个地方给注释掉了,请打开那个注释就能提升edr的hid传输效率了 第二个问题: 修改632n系别把触摸板的hid报告描述符识别成鼠标点,修改如下: 注释掉上面的pnp,改成下面的

element plus的容器组件

element-plus的容器组件主要有el-container,el-aside,el-header,el-main,el-footer,后面4个组件其父组件必须是el-container。 el-container采用flex布局&#xff0c;如果其子元素包含el-header或el-footer时会采用垂直布局&#xff0c;否则会采用水平布局&#xff0c;可设置其…

教程 | Navicat 17 管理连接新方法

Navicat 17 提供了比以往更多的连接数据库实例的方式。除了传统的连接字符串方式以外&#xff0c;Navicat 17 还支持 URI 连接&#xff0c;无论身在何处&#xff0c;都可以轻松地通过 URI 访问对象。另外&#xff0c;还有一个新的管理连接功能&#xff0c;即允许你通过一个以用…

大数据揭秘

起源 不管是国内&#xff0c;国外的招聘目前数据分析工程师&#xff0c;或者是大数据工程师我感觉都是处于启蒙阶段&#xff0c;对于数据分析或者大数据没有什么体系技术栈一说&#xff0c;相比于前后端&#xff0c;除了高端互联网企业其他的企业招数据分析工程师我认为目前都…

【全开源】房屋出租出售预约系统(FastAdmin+ThinkPHP+Uniapp)

房屋出租出售预约系统&#xff1a;一站式解决房产交易难题 一款基于FastAdminThinkPHPUniapp开发的房屋出租出售预约系统&#xff0c;支持小程序、H5、APP&#xff0c;包含房客、房东(高级授权)、经纪人(高级授权)三种身份。核心功能有&#xff1a;新盘销售、房屋租赁、地图找…

Python 技巧分享:NEF 文件的元数据提取

介绍 随着摄影技术的不断发展&#xff0c;NEF 文件作为尼康相机的 RAW 格式文件&#xff0c;因其包含丰富的图像数据和元数据&#xff0c;备受摄影爱好者和专业摄影师的青睐。提取 NEF 文件中的元数据对照片管理、分析及处理具有重要意义。本文将介绍如何使用 Python 技术&…

慎投!Hindawi这本SCI还在检,这里已被踢!新增14本Scopus期刊被剔除!

本周投稿推荐 SSCI • 中科院2区&#xff0c;6.0-7.0&#xff08;录用友好&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09; CNKI • 3天内初审录用&#xff0c;随即出版&#xff08;急录友好&#xff09; SCI&EI • 4区生物医学类&#xff0c;0…

电商数据驱动的决策智慧:深度解析数据采集与应用||电商API接口接入与应用

引言 在数字化时代&#xff0c;数据已成为电商企业最宝贵的资产之一。通过有效的数据采集&#xff0c;企业能够洞察市场动态、理解消费者需求、优化运营策略&#xff0c;从而在激烈的市场竞争中脱颖而出。本文将深入探讨电商数据采集的重要性、常用方法以及应用实践。 一、电商…

C语言—内存函数

1. memcpy 使用和模拟实现 void* memcpy&#xff08;void* destination&#xff0c;const void* source&#xff0c;size_t num&#xff09;&#xff1b; 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。这个函数在遇到 ‘\0’ 的时候并不…

神经网络 torch.nn---Convolution Layers

torch.nn — PyTorch 2.3 documentation torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) torch.nn和torch.nn.functional的区别 torch.nn是对torch.nn.functional的一个封装&#xff0c;让使用torch.nn.functional里面的包的时候更加方便 torch.nn包含了torch.nn.…

Linux日志服务rsyslog深度解析(上)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、日志在Linux系统中的作用 2、rsyslog历史背景 …

保姆级讲解 FTP服务器的搭建、配置与管理

本来目录很长的 因为感觉不太美观 所以小标题都删掉了 本文介绍了 本地用户的FTP服务器搭建实例匿名用户的FTP服务器搭建实例虚拟用户的FTP服务器搭建实例企业常见类型搭建实验 配置与管理FTP服务器 配置与管理FTP服务器一、FTP相关知识二、项目设计与准备三、项目实施四、认识…

MyBatisPlus——入门到进阶

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。&#x1f34e;个人主页&#xff1a;Meteors.的博客&#x1f49e;当前专栏&#xff1a;知识分享、知识备份✨特色专栏&#xff1a; 知识分享…

【GIS教程】土地利用转移矩阵

随着科技社会的不断进步&#xff0c;人类活动对地理环境的影响与塑造日益明显&#xff0c;土地不断的侵蚀与改变也导致一系列的环境问题日益突出。土地利用/覆盖&#xff08;LUCC&#xff09;作为全球环境变化研究的重点问题为越来越多的国际研究机构所重视&#xff0c;研究它的…

Day25 首页待办事项及备忘录添加功能

​ 本章节,完成首页待办事项及备忘录添加功能 一.修改待办事项和备忘录逻辑处理类,即AddMemoViewModel和AddTodoViewModel 在 AddMemoViewModel逻辑处理类中,为了支持与其关联的View视图文件的数据绑定,需要定义一个与视图文件相匹配的实体类 Model。这个Model将包含 View中…

图像算法---自动对焦AF

一&#xff0c;CDAF反差对焦原理 CDAF&#xff0c;全称Contrast Detection Auto Focus&#xff0c;即反差式对焦或对比度检测自动对焦&#xff0c;是一种广泛应用于入门级数码相机和相机模块化智能手机上的自动对焦技术。以下是关于CDAF反差对焦的详细介绍&#xff1a; 工作原…

每日AI资讯-20240606

智普AI推出全新开源大模型GLM-4-9B 智谱AI日前推出全新开源模型GLM-4-9B&#xff0c;该尺寸模型首次具备多模态能力。据了解&#xff0c;GLM-4-9B&#xff0c;最高支持1M/约两百万字上下文输入&#xff0c;相当于2本《红楼梦》或125篇论文的长度。性能上&#xff0c;GLM-4-9B函…

《手把手教你》系列练习篇之13-python+ selenium自动化测试 -压轴篇(详细教程)

1. 简介 “压轴”原本是戏曲名词&#xff0c;指一场折子戏演出的倒数第二个剧目。在现代社会中有很多应用&#xff0c;比如“压轴戏”&#xff0c;但压轴也是人们知识的一个盲区。“压轴”本意是指倒数第二个节目&#xff0c;而不是人们常说的倒数第一个&#xff0c;倒数第一个…

苗情生态自动监测站

TH-MQ1在现代农业发展中&#xff0c;苗情生态自动监测站的应用已经变得日益重要。这种技术不仅为农业生产提供了实时的数据支持&#xff0c;还通过精准监测和科学决策&#xff0c;提高了农业生产的效率和质量。 首先&#xff0c;苗情生态自动监测站的优势在于其能够实现精准监…