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
繁體地址,請注明出處:http://hk.pswp.cn/diannao/84851.shtml
英文地址,請注明出處:http://en.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推出了強枚舉來代替舊版的枚舉&…