cuda编程笔记(2)--传递参数、设备属性

以下是最简单的带参数的核函数使用过程:

#include<iostream>
#include<cstdio>
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
__global__ void add(int a,int b,int *c) {*c = a + b;
}
int main() {int c;int* dev_c;cudaMalloc((void **)&dev_c,sizeof(int));add << <1, 1 >> > (2, 7, dev_c);cudaMemcpy(&c, dev_c, sizeof(int), cudaMemcpyDeviceToHost);//这里会隐式同步,等待核函数执行完printf("2+7=%d\n", c);cudaFree(dev_c);cudaError_t err = cudaDeviceSynchronize();if (err != cudaSuccess) {std::cerr << "CUDA Error: " << cudaGetErrorString(err) << std::endl;}return 0;
}

add的参数:

  • int a, int b:两个通过值传递的整型参数。

  • int *c:一个指针,指向 GPU 设备内存,用于返回结果。

cudaMalloc 的作用

cudaError_t cudaMalloc(void **devPtr, size_t size);
  • 作用:在 GPU 设备内存上分配一块大小为 size 字节的内存空间。

  • 参数说明

    • void **devPtr:一个指向设备指针的指针,cudaMalloc 会将申请到的设备内存地址写入这个指针。

    • size:需要分配的内存字节数。

  • 返回值:返回 cudaSuccess(表示成功),或者其他错误码。

为什么要用 cudaMalloc

因为 GPU 上运行的核函数(__global__)不能访问 CPU 的内存(host memory),所以:

  • 要传递结果回 CPU,必须在 GPU 内存中有一块空间存放结果

  • 你不能直接传一个 CPU 指针(如 int* c)给核函数,否则会产生非法内存访问;

  • 所以你要用 cudaMalloc 分配一块 GPU 内存(例如 int* dev_c),传给核函数用于写入结果。

 示意图:

+----------------+        cudaMemcpy        +----------------+
|    Host (CPU)  | <----------------------> |  Device (GPU)   |
|  int c;        |                          |  int* dev_c     |
+----------------+        cudaMalloc        +----------------+↑dev_c = GPU上的内存地址

在主机代码中,不能对 dev_c 解引用,只能通过 cudaMemcpy 把它里面的数据拷回来后使用。

区域地址空间是否可以解引用该地址?
主机内存(Host)主机地址只能在 CPU 代码中解引用
设备内存(Device)显存地址只能在 GPU 核函数中解引用

 但是在主机上可以对它进行参数传递等不涉及访问内存的操作。

cudaMemcpy

cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind);
参数名说明
dst目标地址(可以是主机或设备内存)
src源地址(可以是主机或设备内存)
count拷贝的字节数
kind拷贝类型,说明从哪拷到哪(见下表)
类型含义
cudaMemcpyHostToDevice从主机(Host)拷贝到设备(Device)
cudaMemcpyDeviceToHost从设备(Device)拷贝到主机(Host)
cudaMemcpyDeviceToDevice设备内存之间拷贝(GPU → GPU)
cudaMemcpyHostToHost主机内存之间拷贝(等价于 memcpy

cudaMemcpy同步操作,它会阻塞主机线程直到拷贝完成。这保证了数据安全,但也意味着它会造成 CPU 等待。

⚠️ 如果你希望异步传输,需要使用 cudaMemcpyAsync 并配合 CUDA 流(streams)。

释放显存的函数 —— cudaFree

cudaError_t cudaFree(void* devPtr);

 在 GPU 上释放之前通过 cudaMalloc 分配的内存。

  • devPtr:需要释放的设备指针(即之前通过 cudaMalloc 得到的 GPU 地址)。

  • 返回值:返回一个 cudaError_t 类型的错误码(cudaSuccess 表示成功)。

就像在 CPU 上使用 malloc 后要调用 free,在 GPU 上使用 cudaMalloc 分配内存后也必须调用 cudaFree 来释放显存:

  • 否则会造成 显存泄漏

  • 长时间运行或循环分配会 耗尽 GPU 显存

  • 导致 CUDA 程序崩溃或性能严重下降。

核函数的参数规则

一、核函数参数的基本要求

参数必须是可以被复制(copiable)的数据类型

  • 标量类型(如 int, float, double, char

  • 指针类型(如 int*, float*

  • 结构体或类(必须是 trivially copyable)

不支持的:

  • 引用类型(如 int&

  • 虚函数、继承的类等复杂对象

二、参数传递方式:值传递(by value)

CUDA 核函数的参数都是 按值传递,即参数会从主机拷贝一份副本传递给设备。

  • 标量变量:直接复制一份到 GPU。

  • 指针变量:复制的是主机这边的指针值(指向 GPU 内存的地址)。

三、指针指向的内存必须是设备内存

你传给内核的指针必须指向显存(设备内存),否则会导致错误或非法访问:

反例:

int c;
add<<<1, 1>>>(2, 3, &c);  // ❌ 错误!主机地址传入设备代码,非法访问

四、核函数参数个数限制

CUDA 对核函数的参数总字节数有限制(包括传入的所有变量)。

  • 通常限制为 最多 256 字节(不同架构可能有差异);

  • 如果你传入很多参数(如结构体),建议:

    • 封装为一个结构体;

    • 或使用显存中数据结构代替参数(通过指针传入)。

  • 不能使用可变参数

五、结构体作为参数的限制

你可以将结构体作为核函数参数传入,但有几点要注意:

  • 结构体必须是简单结构体(POD 类型,不能有构造函数、虚函数、继承);

  • 会被按值拷贝到设备上;

  • 如果结构体内部有指针,那些指针必须指向设备内存。

六、核函数参数必须可在 host 代码中准备好

由于核函数只能从 host 调用,所有参数必须能在 host 端构造并传入(不能传 GPU 上运行时才能生成的数据结构,比如 GPU 上的临时指针等)。

查询设备

cudaGetDeviceCount

cudaError_t cudaGetDeviceCount(int* count);

获取当前系统中 可用的 CUDA 设备数量(即 GPU 的个数)。

参数:

  • count: 一个指针,用来存放返回的设备数量。

返回值:

  • cudaSuccess 表示成功;

  • 否则返回错误码(如没有安装驱动、无 GPU 等)。

cudaGetDeviceProperties

cudaError_t cudaGetDeviceProperties(cudaDeviceProp* prop, int device);

功能:

获取指定编号 GPU 的详细属性(例如显存大小、线程数量、SM 架构等)。

参数:

  • prop: 指向 cudaDeviceProp 结构体的指针,用于接收设备信息;

  • device: 设备编号,范围是 [0, count - 1]

struct cudaDeviceProp

struct cudaDeviceProp {char name[256];                         // GPU 名称字符串size_t totalGlobalMem;                 // 全局显存总大小(单位:字节)size_t sharedMemPerBlock;             // 每个线程块可用的共享内存大小int regsPerBlock;                     // 每个线程块可用的寄存器数量int warpSize;                         // 一个 warp 中的线程数量(通常为32)size_t memPitch;                      // 最大内存复制宽度(以字节为单位)int maxThreadsPerBlock;              // 每个线程块支持的最大线程数量int maxThreadsDim[3];                // 每个线程块在 x, y, z 三维的最大线程数int maxGridSize[3];                  // 每个网格在 x, y, z 三维的最大块数int clockRate;                       // 时钟频率(kHz)size_t totalConstMem;                // 常量内存总大小(字节)int major;                           // 计算能力主版本号int minor;                           // 计算能力次版本号size_t textureAlignment;            // 纹理对齐要求(字节)size_t texturePitchAlignment;       // 对二维纹理中行对齐的要求(字节)int deviceOverlap;                  // 是否支持设备与主机的重叠执行(1 是,0 否)int multiProcessorCount;            // SM(流式多处理器)数量int kernelExecTimeoutEnabled;       // 是否启用了内核执行超时(1 是,0 否)int integrated;                     // 是否为集成 GPU(1 是,0 否)int canMapHostMemory;              // 是否支持映射主机内存到设备地址空间int computeMode;                    // 计算模式(0: 默认,1: 仅主机访问,2: 禁止访问)int maxTexture1D;                   // 最大 1D 纹理尺寸int maxTexture1DMipmap;            // 最大 1D Mipmap 纹理尺寸int maxTexture1DLinear;            // 最大 1D 线性纹理尺寸(仅支持一维纹理)int maxTexture2D[2];               // 最大 2D 纹理尺寸(width, height)int maxTexture2DMipmap[2];         // 最大 2D Mipmap 尺寸int maxTexture2DLinear[3];         // 最大 2D 线性纹理尺寸(width, height, pitch)int maxTexture2DGather[2];         // 最大 2D Gather 纹理尺寸int maxTexture3D[3];               // 最大 3D 纹理尺寸(width, height, depth)int maxTexture3DAlt[3];            // 替代的最大 3D 纹理尺寸int maxTextureCubemap;             // 最大立方体纹理尺寸int maxTexture1DLayered[2];        // 最大 1D 分层纹理尺寸(width, layers)int maxTexture2DLayered[3];        // 最大 2D 分层纹理尺寸(width, height, layers)int maxTextureCubemapLayered[2];   // 最大立方体分层纹理尺寸(width, layers)int maxSurface1D;                  // 最大 1D surface 尺寸int maxSurface2D[2];               // 最大 2D surface 尺寸int maxSurface3D[3];               // 最大 3D surface 尺寸int maxSurface1DLayered[2];        // 最大 1D 分层 surface 尺寸int maxSurface2DLayered[3];        // 最大 2D 分层 surface 尺寸int maxSurfaceCubemap;             // 最大立方体 surface 尺寸int maxSurfaceCubemapLayered[2];   // 最大立方体分层 surface 尺寸size_t surfaceAlignment;           // surface 对齐要求(字节)int concurrentKernels;             // 是否支持多个 kernel 并发执行int ECCEnabled;                    // 是否启用 ECC(错误检查与纠正)int pciBusID;                      // PCI 总线 IDint pciDeviceID;                   // PCI 设备 IDint pciDomainID;                   // PCI 域 IDint tccDriver;                     // 是否为 TCC 驱动(用于专业显卡如 Tesla)int asyncEngineCount;              // 同时支持异步传输与执行的引擎数量int unifiedAddressing;            // 是否支持统一虚拟地址空间(UVA)int memoryClockRate;              // 显存时钟频率(kHz)int memoryBusWidth;               // 显存总线宽度(位)int l2CacheSize;                  // L2 缓存大小(字节)int maxThreadsPerMultiProcessor;  // 每个 SM 支持的最大线程数int streamPrioritiesSupported;    // 是否支持流优先级int globalL1CacheSupported;       // 是否支持全局 L1 缓存int localL1CacheSupported;        // 是否支持本地 L1 缓存size_t sharedMemPerMultiprocessor; // 每个 SM 可用的共享内存大小(字节)int regsPerMultiprocessor;         // 每个 SM 可用的寄存器数量int managedMemory;                 // 是否支持托管内存int isMultiGpuBoard;              // 是否为多 GPU 板卡的一部分int multiGpuBoardGroupID;         // 多 GPU 板卡上的组 ID
};


配合使用,获取设备属性

#include <iostream>
#include <cuda_runtime.h>int main() {int deviceCount = 0;cudaError_t err = cudaGetDeviceCount(&deviceCount);if (err != cudaSuccess) {std::cerr << "cudaGetDeviceCount failed: " << cudaGetErrorString(err) << std::endl;return -1;}std::cout << "Found " << deviceCount << " CUDA device(s).\n";for (int i = 0; i < deviceCount; ++i) {cudaDeviceProp prop;cudaGetDeviceProperties(&prop, i);std::cout << "\nDevice " << i << ": " << prop.name << "\n";std::cout << "  Total Global Memory: " << (prop.totalGlobalMem >> 20) << " MB\n";std::cout << "  Compute Capability: " << prop.major << "." << prop.minor << "\n";std::cout << "  Multiprocessors: " << prop.multiProcessorCount << "\n";std::cout << "  Max Threads Per Block: " << prop.maxThreadsPerBlock << "\n";std::cout << "  Max Threads Dim: ("<< prop.maxThreadsDim[0] << ", "<< prop.maxThreadsDim[1] << ", "<< prop.maxThreadsDim[2] << ")\n";std::cout << "  Max Grid Size: ("<< prop.maxGridSize[0] << ", "<< prop.maxGridSize[1] << ", "<< prop.maxGridSize[2] << ")\n";}return 0;
}

cudaGetDevice

cudaGetDevice 是 CUDA 运行时 API 中的一个函数,用来获取当前线程所使用的 CUDA 设备编号(Device ID)。它的常见用途是:

  • 查询当前使用的是哪一个 GPU。

  • cudaSetDevice(int device) 搭配使用,切换或记录设备上下文。

cudaError_t cudaGetDevice(int* device);

参数说明:

  • int* device:一个指向整数的指针,函数会把当前设备的 ID(从 0 开始)写入这里。

配合使用:cudaSetDevice

cudaSetDevice(1);       // 绑定设备1
cudaGetDevice(&id);     // 确认当前设备 id 是 1

cudaChooseDevice

cudaChooseDevice 是 CUDA Runtime API 中的一个函数,它的作用是:根据你指定的一些性能偏好,选择最适合的 CUDA 设备(GPU)并返回设备编号(ID)

cudaError_t cudaChooseDevice(int* device, const cudaDeviceProp* prop);

参数说明:

  • int* device:返回选择的设备编号。

  • const cudaDeviceProp* prop:你的“理想设备”配置(可以只设置关键字段)。

使用方式:

    cudaDeviceProp desiredProp = {};desiredProp.major = 7;  // 至少计算能力为 7.x(如 Volta, Turing, Ampere)desiredProp.totalGlobalMem = 4L * 1024 * 1024 * 1024;  // 至少 4GB 显存int chosenDevice = -1;cudaError_t err = cudaChooseDevice(&chosenDevice, &desiredProp);

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

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

相关文章

C# WinForm应用程序多语言实现全面指南

目录 引言 一、多语言实现基础概念 1.1 多语言实现的核心原理 1.2 .NET本地化支持机制 二、基于XML的多语言实现方案 2.1 方案概述 2.2 XML文件结构示例 2.3 实现步骤 2.4 优缺点分析 三、基于.resx资源文件的多语言实现 3.1 方案概述 3.2 实现步骤 3.3 资源文件结…

Python爬虫实战:研究Playwright框架相关技术

1 引言 1.1 研究背景与意义 网络爬虫作为一种自动获取互联网信息的技术,在数据采集、信息监测、竞争情报等领域具有广泛应用。随着 Web 技术的发展,越来越多的网站采用 JavaScript 动态渲染技术,传统爬虫工具难以有效获取完整的页面内容。Playwright 作为新一代自动化测试…

中企出海大会|打造全球化云计算一张网,云网络助力中企出海和AI创新

全球化是阿里云的长期战略&#xff0c;未来阿里云将持续加大云和 AI 基础设施建设投入。首先是加速打造全球化的云计算网络&#xff0c;一张具备 AI技术服务能力和全球竞争力的云计算网络是阿里云的长期目标。 —— 阿里巴巴集团 CEO、阿里云智能集团董事长兼 CEO 吴泳铭 5 月 …

唯创WT2606B TFT显示灵动方案,重构电子锁人机互动界面,赋能智能门锁全场景交互!

在智能家居的浪潮中&#xff0c;门锁搭载显示屏已成为行业创新的焦点。据行业数据显示&#xff0c;2023年全球智能门锁出货量中&#xff0c;搭载显示屏的型号占比已突破40%&#xff0c;且年复合增长率达25%。而2024年国内智能门锁销量突破2200万套&#xff0c;预计2025年市场规…

轻量化开源方案——浅析PdfPatcher实际应用

PDF处理在实际工作中十分重要&#xff0c;今天浅析PdfPatcher在PDF处理中的实际应用。 核心功能实测 批量处理能力 支持修改文档属性/页码编号/页面链接 一键清除复制/打印限制&#xff08;实测WPS加密文档可解锁&#xff09; 自动清理隐藏冗余数据&#xff08;经测试可平均…

Docker 环境搭建与三大数据库(MySQL/Redis/MongoDB)部署教程

Docker 环境搭建与三大数据库(MySQL/Redis/MongoDB)部署教程 一、简介二、安装wsl三、wsl磁盘迁移四、wsl磁盘压缩五、Docker下载六、win11配置docker虚拟环境命令工具七、Docker部署mysql八、Docker部署redis九、Docker部署mongo一、简介 Docker 是一个开源的容器化平台,它…

CPO-BP+MOPSO,冠豪猪优化BP神经网络+多目标粒子群算法!(Matlab源码)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.CPO-BPNSGA&#xff0c;冠豪猪优化BP神经网络粒子群算法&#xff01;&#xff08;Matlab完整源码和数据&#xff09;&#xff0c;冠豪猪算法优化BP神经网络的权值和阈值&#xff0c;运行环境Matlab2020b及以上。 多…

Vision Pro发布!开发者如何快速上手空间UI设计?

Vision Pro发布&#xff01;开发者如何快速上手空间UI设计&#xff1f; 【内容摘要】 苹果最新发布的Vision Pro&#xff0c;不仅重新定义了我们对虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;的认知&#xff0c;也为开发者们带来了前所未有的机…

Bootstrap法进行随机模拟

一、问题背景 # 26名神经功能受损儿童接受了两组&#xff08;A组与B组&#xff09;空间知觉测试&#xff0c;得分如下A组和B组数据。 # A组数据 x_A <- c(48, 36, 20, 29, 42, 42, 20, 42, 22, 41, 45, 14, 6, 0, 33, 28, 34, 4, 32, 24, 47, 41, 24, 26, 30, 41)# B组数据…

Spring AI 多模型智能协作工作流实现指南

Spring AI 多模型智能协作工作流实现指南 说明 本文档旨在指导开发者基于 Spring AI 框架&#xff0c;在 Spring Boot 2 环境下集成多种主流大语言模型&#xff08;如 OpenAI ChatGPT、Deepseek、阿里云通义千问等&#xff09;&#xff0c;并提供从环境配置、模型调用、流式输…

C语言中清空缓存区到底写到哪里比较好

文章目录 问题背景%d和%c读取缓冲区的差别清空缓存区 问题背景 在写C语言的命令行程序时&#xff0c;我们经常会用到用户输入和标准输出&#xff0c;特别的&#xff0c;当用户输入后&#xff0c;我们发现程序运行不是我们要的样子&#xff0c;这个时候&#xff0c;很可能就是输…

计算机视觉与深度学习 | 基于 YOLOv8 + BeautyGAN + CodeFormer + Face Parsing 实现简单的人脸美颜

人脸美颜 **一、算法流程图****二、完整代码实现**1. 环境准备2. 完整代码(face_beautify.py)**三、核心算法公式**1. YOLOv8检测损失函数2. BeautyGAN损失函数3. CodeFormer图像重建公式**四、关键实现细节**1. 多尺度人脸处理2. 颜色校正策略**五、模型下载清单****六、性能…

如何在WordPress中选择最佳Elementor主题:专家指南

当你在WordPress建站过程中逐步积累了经验&#xff0c;你可能会发觉&#xff0c;基础和进阶主题已难以完全满足你的需求。如果你需要更复杂的功能、更灵活的布局设计&#xff0c;甚至高级定制效果&#xff0c;那么就需要选择更加专业的主题。在这篇文章中&#xff0c;我将为你推…

FPGA高速接口 mipi lvds cameralink hdml 千兆网 sdi

mipi: https://blog.csdn.net/SDJ_success/article/details/146541776 cameralink CameraLink协议 CameraLink协议是一种专门针对机器视觉应用领域的串行通信协议&#xff0c;它使用低压差分信号(LVDS)进行数据的传输和通信。CameraLink标准是在ChannelLink标准的基础上多加了…

手机收不到WiFi,手动输入WiFi名称进行连接不不行,可能是WiFi频道设置不对

以下是电脑上分享WiFi后&#xff0c;部分手机可以看到并且能连接&#xff0c;部分手机不行&#xff0c;原因是&#xff1a;频道设置为5GHz&#xff0c;修改成&#xff0c;任何可用频率&#xff0c;则可

12.Java 对象冷冻术:从用户登录到游戏存档的序列化实战

目录 一、引言 二、用户登录存档&#xff1a;让账号信息「冻龄」不变 1. 给对象贴「冷冻标签」&#xff1a;实现 Serializable 2. 冷冻与解冻实战&#xff1a;把用户存进文件 3. 演示场景 三、游戏存档复活&#xff1a;让角色进度「穿越时空」 1. 复杂对象冷冻&#xff…

conda 环境中opencv 报错以及其他报错

如题&#xff0c;通过 conda install opencv 然后遇到 ImportError: DLL load failed while importing cv2: 找不到指定的模块。 参考网络相关答案 通过conda 卸载 然后通过 pip3 安装opencv-pyhton https://stackoverflow.com/questions/75387197/anaconda-importerror-dll-…

(已开源-CVPR2024) RadarDistill---NuScenes数据集Radar检测第一名

本文介绍一篇Radar 3D目标检测模型&#xff1a;RadarDistill。雷达数据固有的噪声和稀疏性给3D目标检测带来了巨大挑战。在本文中&#xff0c;作者提出了一种新的知识蒸馏(KD)方法RadarDistill&#xff0c;它可以通过利用激光雷达数据来提高雷达数据的表征。RadarDistill利用三…

创建型设计模式之Singleton(单例)设计模式

创建型设计模式之Singleton&#xff08;单例&#xff09;设计模式 摘要&#xff1a; Singleton&#xff08;单例&#xff09;设计模式确保一个类仅有一个实例&#xff0c;并提供全局访问点。其结构包含一个静态方法getInstance()用于获取唯一实例&#xff0c;构造方法私有化防…

C++11:系统类型增强

C11&#xff1a;系统类型增强 强枚举类型作用域限定隐式类型转换指定类型前置声明 类型别名 using模板别名复杂指针别名 auto限制性 auto注意事项 nullptrdecltype 强枚举类型 在C98的枚举设计中&#xff0c;存在很多缺陷&#xff0c;为此C11推出了强枚举来代替旧版的枚举&…