cuda編程筆記(13)--使用CUB庫實現基本功能

CUB 是 NVIDIA 提供的 高性能 CUDA 基礎庫,包含常用的并行原語(Reduction、Scan、Histogram 等),可以極大簡化代碼,并且比手寫版本更優化。

CUB無需鏈接,只用包含<cub/cub.cuh>頭文件即可

需要先臨時獲取空間

CUB 內部需要額外的緩沖區來做并行歸約、掃描等操作,而這個緩沖區的大小依賴于 輸入數據量、算法、GPU 結構,編譯期無法確定。

通用函數接口-Device-level(設備級)

運行在整個設備(grid)范圍,需要全局內存臨時空間。

cub::DeviceReduce::Reduce

template <typename InputIteratorT,typename OutputIteratorT,typename ReductionOp,typename T>
static cudaError_t Reduce(void *d_temp_storage,        // 臨時存儲區指針size_t &temp_storage_bytes,  // 存儲區大小InputIteratorT d_in,         // 輸入迭代器(GPU 內存)OutputIteratorT d_out,       // 輸出迭代器(GPU 內存)int num_items,               // 輸入元素個數ReductionOp reduction_op,    // 歸約操作符(如加法、最大值)T init,                      // 歸約初始值cudaStream_t stream = 0);    // CUDA 流
  • d_temp_storagetemp_storage_bytes:兩階段調用機制(先獲取大小再分配)

  • d_in / d_out:輸入和輸出數組指針(在 GPU 上)

  • num_items:元素數量

  • reduction_op:歸約操作(例如 cub::Sum(), cub::Max(),或自定義 Lambda)

  • init:歸約起始值

  • stream:運行在哪個 CUDA stream 上

求和

#ifndef __CUDACC__
#define __CUDACC__
#endif
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <cublas_v2.h>
#include <cufft.h>
#include<cub/cub.cuh>
#include <iostream>
#include<cstdio>
#include <vector>void error_handling(cudaError_t res) {if (res !=cudaSuccess) {std::cout << "error!" << std::endl;}
}
int main() {const int N = 8;float h_in[N] = { 1, 2, 3, 4, 5, 6, 7, 8 };float* d_in, * d_out;cudaMalloc(&d_in, N * sizeof(float));cudaMalloc(&d_out,  sizeof(float));cudaMemcpy(d_in, h_in, N * sizeof(float), cudaMemcpyHostToDevice);void* d_temp_storage = nullptr;size_t temp_storage_bytes = 0;cub::DeviceReduce::Reduce(d_temp_storage,temp_storage_bytes,d_in,d_out,N,cub::Sum(),0.0f);// 分配臨時空間cudaMalloc(&d_temp_storage, temp_storage_bytes);// 第二次調用:執行歸約cub::DeviceReduce::Reduce(d_temp_storage, temp_storage_bytes,d_in, d_out, N,cub::Sum(), 0.0f);float h_out;cudaMemcpy(&h_out, d_out, sizeof(float), cudaMemcpyDeviceToHost);std::cout << "Sum = " << h_out << std::endl;cudaFree(d_in);cudaFree(d_out);cudaFree(d_temp_storage);return 0;
}

當然,Reduce是通用版本,也有Sum的特化版本

  template <typename InputIteratorT, typename OutputIteratorT, typename NumItemsT>cudaError_tstatic Sum(void* d_temp_storage,size_t& temp_storage_bytes,InputIteratorT d_in,OutputIteratorT d_out,NumItemsT num_items,cudaStream_t stream = 0);
#ifndef __CUDACC__
#define __CUDACC__
#endif
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <cublas_v2.h>
#include <cufft.h>
#include<cub/cub.cuh>
#include <iostream>
#include<cstdio>
#include <vector>void error_handling(cudaError_t res) {if (res !=cudaSuccess) {std::cout << "error!" << std::endl;}
}
int main() {const int N = 8;float h_in[N] = { 1, 2, 3, 4, 5, 6, 7, 8 };float* d_in, * d_out;cudaMalloc(&d_in, N * sizeof(float));cudaMalloc(&d_out,  sizeof(float));cudaMemcpy(d_in, h_in, N * sizeof(float), cudaMemcpyHostToDevice);void* d_temp_storage = nullptr;size_t temp_storage_bytes = 0;// 先獲取臨時空間大小cub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, d_in, d_out, N);cudaMalloc(&d_temp_storage, temp_storage_bytes);// 執行 Reducecub::DeviceReduce::Sum(d_temp_storage, temp_storage_bytes, d_in, d_out, N);float h_out;cudaMemcpy(&h_out, d_out, sizeof(float), cudaMemcpyDeviceToHost);std::cout << "Sum = " << h_out << std::endl;cudaFree(d_in);cudaFree(d_out);cudaFree(d_temp_storage);return 0;
}

自定義乘積

可以求數組所有元素的乘積;乘積Reduce沒有提供接口,可以自己寫一個可執行對象(仿函數類,lambda表達式等都可以)

這里使用lambda表達式

#ifndef __CUDACC__
#define __CUDACC__
#endif
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <cublas_v2.h>
#include <cufft.h>
#include<cub/cub.cuh>
#include <iostream>
#include<cstdio>
#include <vector>void error_handling(cudaError_t res) {if (res !=cudaSuccess) {std::cout << "error!" << std::endl;}
}
int main() {const int N = 8;float h_in[N] = { 1, 2, 3, 4, 5, 6, 7, 8 };float* d_in, * d_out;cudaMalloc(&d_in, N * sizeof(float));cudaMalloc(&d_out, sizeof(float));cudaMemcpy(d_in, h_in, N * sizeof(float), cudaMemcpyHostToDevice);void* d_temp_storage = nullptr;size_t temp_storage_bytes = 0;cub::DeviceReduce::Reduce(d_temp_storage, temp_storage_bytes, d_in, d_out, N, []__device__(float a, float b) ->float{ return a * b; }, 1.0f);// 分配臨時空間cudaMalloc(&d_temp_storage, temp_storage_bytes);// 第二次調用:執行乘積cub::DeviceReduce::Reduce(d_temp_storage, temp_storage_bytes, d_in, d_out, N, []__device__(float a, float b) ->float{ return a * b; }, 1.0f);float h_out;cudaMemcpy(&h_out, d_out, sizeof(float), cudaMemcpyDeviceToHost);std::cout << "mul = " << h_out << std::endl;cudaFree(d_in);cudaFree(d_out);cudaFree(d_temp_storage);return 0;
}

如果想要使用在設備使用lambda表達式,需要編譯時加上:

nvcc main.cu -o main --extended-lambda

如果用VS,打開項目屬性,在這里加:

(用仿函數類就不用開啟這個,如此即可)

struct MultiplyOp {__device__ float operator()(float a, float b) const {return a * b;}
};// 調用
cub::DeviceReduce::Reduce(d_temp_storage, temp_storage_bytes,d_in, d_out, N,MultiplyOp(), 1.0f);

前綴和

前綴和有專門的函數

  template <typename InputIteratorT, typename OutputIteratorT>static cudaError_t ExclusiveSum(void* d_temp_storage,// 臨時存儲指針size_t& temp_storage_bytes,// 臨時存儲大小InputIteratorT d_in,// 輸入迭代器(指針)OutputIteratorT d_out,// 輸出迭代器(指針)int num_items,// 元素數量cudaStream_t stream = 0)// CUDA 流(可選)
;

使用起來沒有任何差別

#ifndef __CUDACC__
#define __CUDACC__
#endif
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <cublas_v2.h>
#include <cufft.h>
#include<cub/cub.cuh>
#include <iostream>
#include<cstdio>
#include <vector>void error_handling(cudaError_t res) {if (res !=cudaSuccess) {std::cout << "error!" << std::endl;}
}
int main() {const int N = 8;float h_in[N] = { 1, 2, 3, 4, 5, 6, 7, 8 };float* d_in, * d_out;cudaMalloc(&d_in, N * sizeof(float));cudaMalloc(&d_out, N*sizeof(float));cudaMemcpy(d_in, h_in, N * sizeof(float), cudaMemcpyHostToDevice);void* d_temp_storage = nullptr;size_t temp_storage_bytes = 0;// 獲取臨時空間大小cub::DeviceScan::ExclusiveSum(d_temp_storage, temp_storage_bytes, d_in, d_out, N);cudaMalloc(&d_temp_storage, temp_storage_bytes);// 執行 Exclusive Scancub::DeviceScan::ExclusiveSum(d_temp_storage, temp_storage_bytes, d_in, d_out, N);float h_out[N];cudaMemcpy(h_out, d_out, N * sizeof(float), cudaMemcpyDeviceToHost);std::cout << "Exclusive Scan: ";for (int i = 0; i < N; i++) std::cout << h_out[i] << " ";std::cout << std::endl;cudaFree(d_in);cudaFree(d_out);cudaFree(d_temp_storage);return 0;
}

ExclusiveScan 是前綴和,不包括當前元素:

輸入:   [1, 2, 3, 4, 5, 6, 7, 8]
輸出:   [0, 1, 3, 6,10,15,21,28]

Block-level (線程塊級)

作用

  • 用于一個 Block 內的線程協作,通常替代手寫的 __shared__ + 手寫 reduce/scan。

  • 比 Warp-level 更大范圍(整個 block),但不涉及 grid 級同步。

  • 用途:塊內歸約、塊內前綴和、塊內排序。

線程塊級類的調用套路是一樣的

  1. 定義類型(typedef

  2. 申請共享內存(TempStorage

  3. 調用對象的方法

BlockReduce模板類

namespace cub {template <typename T,                // 數據類型,例如 float, intint BLOCK_DIM_X,           // 線程塊大小cub::BlockReduceAlgorithm ALGORITHM = cub::BLOCK_REDUCE_WARP_REDUCTIONS // 可選//還有一些其他模板參數,一般都可以忽略
>
class BlockReduce {
public:// 內部類型:臨時存儲struct TempStorage;// 構造函數:傳入共享內存__device__ __forceinline__ BlockReduce(TempStorage& temp_storage);// 常用方法:__device__ T Sum(T input); // 塊內所有線程求和template <typename ReductionOp>__device__ T Reduce(T input, ReductionOp reduction_op); // 自定義規約操作__device__ T Sum(T input, T identity); // 帶初始值的求和// 返回最大值和索引struct ArgMax { T value; int index; };__device__ ArgMax Reduce(T input, ReductionOp reduction_op, ArgMax identity);
};} // namespace cub

特點

  • 不需要手寫循環/__syncthreads(),CUB 自動優化 bank conflict。

  • 自定義操作用 .Reduce(val, binary_op)

塊內歸約


__global__ void block_reduce_sum(float* d_in, float* d_out) {// 定義 BlockReduce 類型:數據類型 float,block 大小 256typedef cub::BlockReduce<float, 256> BlockReduceT;// 共享內存(臨時存儲)__shared__ typename BlockReduceT::TempStorage temp_storage;int tid = threadIdx.x + blockIdx.x * blockDim.x;float val = d_in[tid];// 每個 block 歸約,返回該 block 的總和float block_sum = BlockReduceT(temp_storage).Sum(val);if (threadIdx.x == 0) {d_out[blockIdx.x] = block_sum;  // 每個 block 的結果}
}

BlockReduce::Sum(T input) 里的 input 參數當前線程貢獻的單個值,也就是參與規約的元素。

BlockReduce::Sum() 會在整個 線程塊(block)內,把所有線程的 input 值加起來,返回 塊內的總和

自定義規約

 __device__ T Reduce(T input, ReductionOp reduction_op); // 自定義規約操作

該成員函數可以讓我們實現自定義的規約操作

參數含義
input每個線程的本地值,類型為 T
binary_op一個二元操作函數對象,類型為 BinaryOp,定義了如何將兩個 T 類型的值合并。例如:加法、乘法、最大值等。

比如可以用cub庫提供的可調用對象類

float block_sum = BlockReduceT(temp_storage).Reduce(val, cub::Sum());//規約加法
float block_prod = BlockReduceT(temp_storage).Reduce(val, cub::Multiply());//規約乘法

也可以自己實現仿函數類或lambda表達式;具體操作與上文Device級別的自定義乘積類似;

BlockScan

namespace cub {template <typename T,            // 數據類型int BLOCK_DIM_X,       // 線程塊大小cub::BlockScanAlgorithm ALGORITHM = cub::BLOCK_SCAN_WARP_SCANS // 可選
>
class BlockScan {
public:struct TempStorage;__device__ __forceinline__ BlockScan(TempStorage& temp_storage);// 前綴和(不包含自己)template <typename ScanOp>__device__ void ExclusiveScan(T input, T &output, ScanOp scan_op, T identity);// 前綴和(包含自己)template <typename ScanOp>__device__ void InclusiveScan(T input, T &output, ScanOp scan_op);// 常用簡化版本__device__ void ExclusiveSum(T input, T &output, T identity = 0);__device__ void InclusiveSum(T input, T &output);
};} // namespace cub

使用

typedef cub::BlockScan<int, 256> BlockScanT;
__shared__ typename BlockScanT::TempStorage temp_storage;
int output;
BlockScanT(temp_storage).ExclusiveSum(input, output);

BlockRadixSort

namespace cub {template <typename KeyT,           // 鍵類型int BLOCK_DIM_X,         // 線程塊大小typename ValueT = void,  // 可選,值類型int ITEMS_PER_THREAD = 1 // 每線程處理的元素個數
>
class BlockRadixSort {
public:struct TempStorage;__device__ __forceinline__ BlockRadixSort(TempStorage& temp_storage);// 對鍵排序(升序),排序后把屬于該線程的key更新__device__ void Sort(KeyT &key);// 降序__device__ void SortDescending(KeyT &key);// 鍵值對排序__device__ void Sort(KeyT &key, ValueT &value);__device__ void SortDescending(KeyT &key, ValueT &value);
};} // namespace cub

使用模式

#include <cub/cub.cuh>__global__ void block_sort(int *d_keys) {typedef cub::BlockRadixSort<int, 256> BlockRadixSortT;__shared__ typename BlockRadixSortT::TempStorage temp_storage;int thread_id = threadIdx.x + blockIdx.x * blockDim.x;int key = d_keys[thread_id];// 在 block 內排序(升序)BlockRadixSortT(temp_storage).Sort(key);// 寫回排序后的值d_keys[thread_id] = key;
}

Warp-level

Warp-level 原語(線程束級)

  • 用于warp 內高效協作,替代手寫 __shfl_*

  • 適合 warp 內歸約(reduce)、前綴和(scan),比手寫更可讀。

具體用法與block級一模一樣,只是模板類名改為WarpReduce、WarpScan

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/94711.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/94711.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/94711.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LabVIEW濾波器測控系統

?基于LabVIEW 平臺的高頻濾波器測控系統&#xff0c;通過整合控制與測試功能&#xff0c;替代傳統分離式測控模式。系統以 LabVIEW 為核心&#xff0c;借助標準化接口實現對濾波器的自動化參數調節與性能測試&#xff0c;顯著提升測試效率與數據處理能力&#xff0c;適用于高頻…

美團運維面試題及參考答案(上)

輸入一個字符串,將其轉換成數字時,需要考慮哪些情況(如字符串是否合法、是否為空、int 的范圍、是否為 16 進制等)? 將字符串轉換成數字時,需全面考慮多種邊界情況和合法性問題,具體如下: 字符串基礎狀態:首先需判斷字符串是否為空(長度為0)或僅包含空白字符(如空…

Spring-AI 深度實戰:企業級 AI 應用開發指南與 Python 生態對比(高級篇)

為什么 Spring-AI 是企業級 AI 的“隱形冠軍”&#xff1f;&#xff08;而不僅是另一個封裝庫&#xff09;在 Python 主導的 AI 世界中&#xff0c;Spring-AI 的誕生常被誤解為“Java 的跟風之作”。但真正的企業級 AI 需求&#xff08;事務一致性、分布式追蹤、安全審計&#…

OpenAI 回歸開源領域突發兩大推理模型,六強AI企業競逐加劇軍備競賽態勢!

獲悉&#xff0c;OpenAI重回開源賽道&#xff0c;奧特曼深夜官宣兩個分別名為GPT-oss-120b和GPT-oss-20b的模型將在AI軟件托管平臺Hugging Face上線&#xff0c;在用戶輸入指令后將能生成文本。兩大推理模型上線GPT-oss-120b適用于需要高推理能力的生產級和通用型場景。在核心推…

嵌入式學習硬件(一)ARM體系架構

目錄 1.SOC 2.內核架構的分類 3.馮諾依曼架構和哈佛架構 4.kernel 5.指令集 6.ARM處理器產品分類 7.編譯的四個步驟?編輯 8.RAM和ROM?編輯 9.ARM處理器工作模式 10.異常處理 11.CPSR程序狀態寄存器 1.SOC system on chip 片上系統&#xff0c;可以運行操作系統的一種高端的功…

OpenAI推出開源GPT-oss-120b與GPT-oss-20b突破性大模型,支持商用與靈活部署!

模型介紹OpenAI再次推出開源模型&#xff0c;發布了兩款突破性的GPT-oss系列大模型&#xff0c;即GPT-oss-120b和GPT-oss-20b&#xff0c;為AI領域帶來了巨大的創新和發展潛力。這兩款模型不僅在性能上與現有的閉源模型媲美&#xff0c;而且在硬件適配性上具有明顯優勢&#xf…

【Unity Plugins】使用ULipSync插件實現人物唇形模擬

一、下載插件ULipSync&#xff1a; 1. 進入Github網址&#xff1a;https://github.com/hecomi/uLipSync/releases/tag/v3.1.4 2. 點擊下載下方的unitypackage 3. 安裝使用ULipSync的相關的插件 發行者也提到了&#xff0c;在使用的時候需要在Package Manager里安裝Unity.B…

基于 Transformer-BiGRU GlobalAttention-CrossAttention 的并行預測模型

1 背景與動機 在高頻、多尺度且非平穩的時序場景(如新能源產能預測、金融行情、用戶行為流分析)中,單一網絡分支 往往難以同時捕獲 長程依賴(Transformer 長距離建模優勢) 局部細粒信息(循環網絡對短期波動敏感) 將 Transformer 與 雙向 GRU(BiGRU) 以并行支路組合…

大模型與Spring AI的無縫對接:從原理到實踐

摘要&#xff1a;本文系統梳理了大模型知識&#xff0c;以及與Spring AI的集成方案&#xff0c;涵蓋本地部署、云服務、API調用三種模式的技術選型對比。通過DeepSeek官方API示例詳解Spring AI的四種開發范式&#xff08;純Prompt/Agent/RAG/微調&#xff09;&#xff0c;并提供…

linux下實現System V消息隊列實現任意結構體傳輸

以下是一個實現&#xff0c;可以發送和接收任意類型的結構體消息&#xff0c;而不僅限于特定的CustomMsg類型&#xff1a;#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/msg.h> #include <…

TCP的三次握手和四次揮手實現過程。以及為什么需要三次握手?四次揮手?

三次握手和四次揮手的實現原理&#xff0c;以及為什么要這樣設計&#xff1f;三次握手的實現三次握手的核心角色與參數三次握手的具體步驟第一步&#xff1a;客戶端 → 服務器&#xff08;發送 SYN 報文&#xff09;第二步&#xff1a;服務器 → 客戶端&#xff08;發送 SYNACK…

Java開發時出現的問題---架構與工程實踐缺陷

除語言和并發層面&#xff0c;代碼設計、工程規范的缺陷更易導致系統擴展性差、維護成本高&#xff0c;甚至引發線上故障。1. 面向對象設計的常見誤區過度繼承與脆弱基類&#xff1a;通過繼承復用代碼&#xff08;如class A extends B&#xff09;&#xff0c;會導致子類與父類…

項目評審管理系統(源碼+文檔+講解+演示)

引言 在當今快速發展的商業環境中&#xff0c;項目評審和管理是確保項目成功的關鍵環節。項目評審管理系統作為一種創新的數字化工具&#xff0c;通過數字化手段優化項目評審和管理的全流程&#xff0c;提高項目管理效率&#xff0c;降低風險&#xff0c;提升項目成功率。本文將…

ComfyUI 安裝WanVideoWrapper

目錄 方法2&#xff1a;通過 ComfyUI-Manager 安裝 方法3&#xff1a;手動下載并解壓 測試代碼&#xff1a; WanVideoWrapper 方法2&#xff1a;通過 ComfyUI-Manager 安裝 在 ComfyUI 界面頂部找到 Manager&#xff08;管理器&#xff09;選項。 進入 Install Custom Nod…

react合成事件大全,如onClick,onDrag

1. 鼠標事件onClick - 點擊事件onContextMenu - 右鍵菜單事件onDoubleClick - 雙擊事件onDrag - 拖拽事件onDragEnd - 拖拽結束事件onDragEnter - 拖拽進入目標區域事件onDragExit - 拖拽離開目標區域事件onDragLeave - 拖拽離開事件onDragOver - 拖拽懸停事件onDragStart - 拖…

從《中國開源年度報告》看中國開源力量的十年變遷中,Apache SeaTunnel 的躍遷

如果把開源世界比作一條奔涌的大河&#xff0c;過去十年里&#xff0c;中國開發者已經從“岸邊試水”變成了“中流擊水”。在最近落下帷幕的 Community Over Code Asia 2025&#xff0c;華東師范大學教授王偉老師基于《中國開源年度報告》進行的一場分享&#xff0c;用一組數字…

JAVA 程序員cursor 和idea 結合編程

cursor 是基于vscode改良而來的&#xff0c;外加上Claude大語言模型而產生的AI編輯器&#xff0c;市面上也有阿里的靈碼qianwen3-coder大語言模型。我個人電腦還是喜歡用idea集成靈碼插件開發。但是也稍微介紹下習慣idea的人只是使用cursor代碼生成的話&#xff0c;這有個小妙招…

查看部署在K8S服務的資源使用情況

要查看 Pod中 server 的資源使用情況&#xff08;CPU 和內存&#xff09;&#xff0c;你需要使用 Kubernetes 的監控工具。最常用的是 kubectl top 命令。? 方法一&#xff1a;使用 kubectl top&#xff08;推薦&#xff09; 1. 查看 Pod 的 CPU 和內存使用 kubectl top pod s…

uni-app vue3 小程序接入 aliyun-rtc-wx-sdk

安裝依賴&#xff1a; npm install aliyun-rtc-wx-sdk crypto-jsuni-app&#xff0c;新建一個頁面&#xff0c;粘貼以下代碼 在阿里云實時音視頻補充appId、appKey即可&#xff0c; <template><view class"container"><!-- 用戶輸入區域 --><vi…

Java技術棧/面試題合集(3)-Java并發篇

場景 Java入門、進階、強化、擴展、知識體系完善等知識點學習、性能優化、源碼分析專欄分享: Java入門、進階、強化、擴展、知識體系完善等知識點學習、性能優化、源碼分析專欄分享_java高級進階-CSDN博客 通過對面試題進行系統的復習可以對Java體系的知識點進行查漏補缺。…