cuda編程筆記(10)--memory access 優化

全局內存訪問優化(Coalesced Access)

什么是 Coalesced Access?

定義:一個 warp(32 個線程)在同一指令中訪問全局內存時,如果這些訪問請求可以合并成盡可能少的內存事務(通常是 32、64 或 128 字節對齊的塊),就叫 coalesced

條件:一個 warp 的線程訪問 連續且對齊 的地址。

int tid = threadIdx.x + blockIdx.x * blockDim.x;
float val = d_array[tid];  // ? 連續訪問 → Coalesced

優化技巧

以結構體對齊內存:使用 __align__(16)float4

為什么需要對齊?

  • GPU 內存總線要求訪問按 32/64/128 字節對齊,這樣才能合并成一次事務。

  • 如果內存對齊不好,warp 訪問會拆分成多個事務,帶寬利用率降低。

技巧

  • 使用 float4(4 個 float 一起)保證 16 字節對齊。

  • 或者使用 CUDA 對齊修飾符:

float4 vs float

float

  • 單個 4 字節(32 bit)的浮點數。

  • 每個線程訪問 1 個 float 時,如果 warp 中 32 個線程訪問地址連續(0,1,2,3...),CUDA 會把它們合并成1~2 個內存事務,性能好。

float4

  • CUDA 提供的 矢量類型,表示 4 個連續的 float(總共 16 字節)。

  • 優點:

    • 天然 16 字節對齊(滿足 GPU 內存事務對齊要求)。

    • 每個線程一次加載 4 個浮點數,減少指令數,提高帶寬利用率。

//設置float4
float4 f;
f.x = 1.1, f.y = 2.2, f.z = 3.3, f.w = 4.4;
float4 v = data[idx];  // 讀取 4 個 float
result = v.x + v.y + v.z + v.w;

如果要讀取大數組,使用 float4 可以讓 每個線程批量讀取,提高 coalesced 訪問效率。

對比:

  • 32 個線程一次訪問 float → 128 字節(32*4)

  • 32 個線程一次訪問 float4 → 512 字節(32*16),如果對齊良好,GPU 可以用更少的事務完成。

__align__(n) 關鍵字

作用

  • 強制結構體或變量的起始地址對齊到 n 字節邊界

  • 為什么?因為 GPU(和 CPU)要求數據按一定字節對齊訪問,否則:

    • 拆分訪問 → 多次內存事務 → 性能差

    • 未對齊訪問 → 有的設備直接報錯

struct __align__(16) MyStruct {float x, y, z, w;
}; // 占 16 字節,起始地址必須是 16 的倍數
  • 如果不加 __align__(16),可能被編譯器按 4 字節對齊排布,不符合 GPU 要求。

為什么 CUDA 推薦使用 float4 + 對齊?

  • 全局內存的訪問規則:按 32/64/128 字節事務合并。

  • 如果 warp 32 線程訪問 float(每個 4 字節),正好 128 字節,可以合并。

  • 如果 warp 32 線程訪問 float4(每個 16 字節),正好 512 字節,GPU 需要 4 個事務,但每個事務更大,吞吐率更高。

  • 重要:必須保證起始地址按 float4 對齊,否則性能下降。

行優先存儲,避免跨行訪問

  • CUDA 全局內存是按一維線性存儲的,如果訪問跨行,會破壞 coalesced。

  • 例如,二維矩陣 A[M][N],默認按行優先(row-major)存儲:

內存布局: A[0][0], A[0][1], ..., A[0][N-1], A[1][0], ...

錯誤訪問模式(列遍歷):

val = A[col][row]; // 每個線程跨 stride 訪問

每個線程 stride 大,warp 訪問不連續,性能差。

優化

  • 保證 threadIdx.x 對應 最快變化維度(行訪問),這樣 warp 線程連續訪問。

調換索引順序,確保 threadIdx.x 是最快變化維度

  • 原則:warp 線程訪問地址必須連續

  • 如果你的算法天然是列操作,可以調整線程分布:

如果是行優先,那么變化最快的其實是列下標,threadIdx.x對應的也應該是列。如果算法要求列優先,可以對row和col進行調換

以下是行優先情況下col和row的寫法

int col = blockIdx.x * blockDim.x + threadIdx.x;  // x 對應列
int row = blockIdx.y * blockDim.y + threadIdx.y;  // y 對應行

使用 Shared Memory 緩存 tile

為什么?

  • 全局內存訪問延遲大(400~600 cycles),共享內存延遲低(≈100x 更快)。

  • 如果每個線程直接從全局內存多次訪問,會拖慢性能。

  • 解決:把要用的數據塊(tile)加載到共享內存,所有線程復用,減少全局訪問。

例子見上一篇文章:cuda編程筆記(9)--使用 Shared Memory 實現 tiled GEMM -CSDN博客

Bank Conflict

Bank Conflict(共享內存銀行沖突) 是 CUDA 編程中的一個性能問題,發生在多個線程同時訪問 共享內存(Shared Memory) 時。

共享內存的結構

  • CUDA 的 共享內存被劃分成多個 Bank,類似一個并行訪問的“多路存儲器”。

  • 每個 Bank 可以在一個時鐘周期內處理 1 個 32-bit 訪問請求

  • Warp(32 個線程)同時訪問共享內存時:

    • 如果 32 個線程訪問 32 個不同的 Bank無沖突(完美并行)

    • 如果 多個線程訪問同一個 Bank 的不同地址發生 Bank Conflict,訪問會被 串行化,性能大幅下降。

具體原理

假設:

  • 共享內存被分為 32 個 Bank

  • 每個 Bank 寬度 = 4 字節(一個 float

  • 地址映射公式:

bank_id = (address_in_bytes / 4) % 32

例子

__shared__ float s[32][32];
按行優先存儲(Row-major):

  • s[i][j] 的地址 = base + (i * 32 + j) * 4

情況 1:訪問同一列

如果每個線程訪問 s[threadIdx.x][k](同一列 k),

  • 地址 = base + (threadIdx.x * 32 + k) * 4

  • bank_id = (threadIdx.x * 32 + k) % 32 = k(因為 threadIdx.x * 32 是 32 的倍數)

  • 所有線程訪問同一 Bank(k) → 嚴重沖突

情況 2:訪問同一行

如果每個線程訪問 s[k][threadIdx.x](同一行 k),

  • 地址 = base + (k * 32 + threadIdx.x) * 4

  • bank_id = (k * 32 + threadIdx.x) % 32 = threadIdx.x

  • 每個線程訪問不同 Bank → 無沖突

避免 Bank Conflict 的方法

核心原則:讓 warp 內的 32 個線程訪問的地址盡量分布到不同的 bank。

  • 按行訪問而非按列

    • 推薦:s[threadIdx.y][threadIdx.x](X 對應列,變化最快)

  • 增加 padding(填充列)

    • 如果二維數組導致 bank 沖突,可以在第二維加一個“dummy 列”,讓 stride ≠ 32:

__shared__ float s[TILE_SIZE][TILE_SIZE + 1];

使用結構化數據(float4)或 align

  • 一次加載多個元素,減少 warp 的 bank 競爭。

?

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

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

相關文章

閑庭信步使用圖像驗證平臺加速FPGA的開發:第三十一課——車牌識別的FPGA實現(3)車牌字符分割預處理

(本系列只需要modelsim即可完成數字圖像的處理,每個工程都搭建了全自動化的仿真環境,只需要雙擊top_tb.bat文件就可以完成整個的仿真,大大降低了初學者的門檻!!!!如需要該系列的工程…

電子電氣架構 --- 汽車軟件全生命周期

我是穿拖鞋的漢子,魔都中堅持長期主義的汽車電子工程師。 老規矩,分享一段喜歡的文字,避免自己成為高知識低文化的工程師: 簡單,單純,喜歡獨處,獨來獨往,不易合同頻過著接地氣的生活,除了生存溫飽問題之外,沒有什么過多的欲望,表面看起來很高冷,內心熱情,如果你身…

力扣面試150(41/150)

7.25 56. 合并區間 以數組 intervals 表示若干個區間的集合,其中單個區間為 intervals[i] [starti, endi] 。請你合并所有重疊的區間,并返回 一個不重疊的區間數組,該數組需恰好覆蓋輸入中的所有區間 。 我的思路: 左端點升序…

【隧道篇 / IPsec】(7.6) ? 01. 利用向導快速建立IPsec安全隧道 (點對點) ? FortiGate 防火墻

【簡介】相信很多人已經習慣利用導向快速創建VPN了,而且已經有部分嘗鮮者已經用上了FortiOS 7.6,但是會發現FortiOS 7.6下的VPN向導改變了很多,一時無法下手,下面我們來看看最常見的點對點是如何配置的。環境介紹在配置IPsec VPN之…

PLLIP核

。1 號紅色框內的速度等級代表著設備的速度 等級,保存默認就好;2 號紅色框內設置輸入頻率;3 號紅色框選擇 PLL 的工作模式。我們 開發板用的晶振是 50MHz 的,故在 2 號紅色框內我們填寫 50MHz;我們在 3 號紅色框內選正…

1.1 Deep learning?pytorch ?深度學習訓練出來的模型通常有效但無法解釋合理性? 如何 解釋?

DL 是什么,你如何理解DL模型? DL 對于我而言,就是人類試圖想通過數學語言描述人類學習過程的一門技術,或者說學科。 因此 DL 模型 相當于 數學 的 一個 funciton ,有輸入,通過function處理,得…

java實現在工具類中注入其他對象方式

方案1: Slf4j Component public class ChatdocApiClient {Value("${chatdoc.app-id}")private String appId;Value("${chatdoc.secret}")private String secret;Value("${chatdoc.domain}")private String domain;private final Rest…

electron中IPC 渲染進程與主進程通信方法解析

electron中ipcRenderer.invoke、ipcRenderer.on、ipcRenderer.send、ipcRenderer.sendSync作用與區別 IPC 渲染進程與主進程通信方法解析 ipcRenderer 的這幾個方法作用不完全相同,它們適用于不同的通信場景,核心區別在于通信方向、是否需要響應以及同步…

epoll_event 事件類型詳解

epoll_event 事件類型詳解 epoll_event 是 Linux epoll I/O 多路復用機制的核心結構體&#xff0c;其中的事件類型決定了 epoll 監控的行為和觸發條件。以下是各種事件類型的詳細解析&#xff1a; epoll_event 結構體 #include <sys/epoll.h>typedef union epoll_data {v…

設計自己的小傳輸協議 導論與概念

設計自己的小傳輸協議 導論與概念 1&#xff1a;聊一聊協議頭設計 ? 早在《TCP/IP詳解》中的第一句話中&#xff0c;我們就知道協議的含義是這樣的&#xff1a;協議是通信雙方共同遵守的一套規則&#xff0c;提供格式定義、語義解釋等&#xff0c;使不同設備或軟件能夠正確交…

iOS —— 天氣預報仿寫總結

在iOS中&#xff0c;最常見的網絡請求方式是NSURLSession&#xff0c;它是蘋果推薦的現代API&#xff0c;簡單安全且易于拓展。一次完整的網絡請求流程&#xff1a;構造 NSURL 對象創建 NSURLSessionDataTask發起請求&#xff08;resume&#xff09;在回調中解析數據回到主線程…

MySQL 8.4 Windows 版安裝記錄與步驟參考

導語&#xff1a; MySQL 作為廣泛使用的開源數據庫管理系統&#xff0c;是許多開發者和學習者的必備工具。最近有朋友詢問安裝過程&#xff0c;正好整理了 MySQL 8.4 在 Windows 系統下的安裝步驟和一些注意事項&#xff0c;分享給有需要的朋友做個參考。關于 MySQL&#xff1a…

七、搭建springCloudAlibaba2021.1版本分布式微服務-skywalking9.0鏈路追蹤

前言鏈路追蹤介紹 對于一個大型的幾十個&#xff0c;幾百個微服務構成的微服務架構系統&#xff0c;通常會遇到下面的一系列問題。 如何串聯整個調用鏈路&#xff0c;快速定位問題&#xff1f;如何澄清各個微服務之間的依賴關系&#xff1f;如何進行各個微服務接口的性能分析&a…

深入理解大語言模型生成參數:temperature、top\_k、top\_p 等全解析

在使用大語言模型&#xff08;如 GPT-4、LLaMA、ChatGLM 等&#xff09;進行文本生成任務時&#xff0c;很多開發者會面對各種“生成參數”&#xff0c;如 temperature、top_k、top_p、repetition_penalty 等。這些參數雖然看起來抽象&#xff0c;但掌握它們的意義和配置技巧&a…

vulhub Web Machine(N7)靶場攻略

下載地址&#xff1a; https://download.vulnhub.com/webmachine/Web-Machine-N7.ova 使用方法&#xff1a; 靶場下載好以后不用解壓&#xff0c;需要使用Oracle VirtualBox虛擬機打開&#xff0c;用VMware會報錯。安裝Oracle VirtualBox虛擬機時安裝地址不能隨便選擇&#…

【機器學習深度學習】模型微調:多久才算微調完成?——如何判斷微調收斂,何時終止訓練

目錄 前言 一、微調過程的目標&#xff1a;優化模型表現 二、微調需要多久&#xff1f; 微調時間無法確定 三、如何判斷微調何時收斂&#xff1f; 3.1 觀察Loss的下降趨勢 3.2 損失值趨于平穩&#xff0c;意味著收斂 如何識別收斂&#xff1f; 3.3 驗證Loss的波動&…

紅隊視角:實戰滲透測試中漏洞利用的進階技巧與防御

紅隊作為滲透測試的 “攻擊方”&#xff0c;其核心價值不僅在于發現漏洞&#xff0c;更在于挖掘漏洞的深度利用方式 —— 通過繞過防護措施、組合低危漏洞形成攻擊鏈&#xff0c;暴露企業真實安全風險。從紅隊視角解析漏洞利用的進階技巧&#xff0c;既能幫助防御方理解攻擊思路…

OpenHarmony BUILD.gn中執行腳本

在OpenHarmony編譯構建中筆者經常遇到這樣的場景——需要執行sh腳本完成某些操作。筆者將OpenHarmony BUILD.gn中執行腳本的方法分享如下&#xff1a; 前置知識點 1.能夠把自定義的子系統加入OpenHarmony源碼的編譯構建&#xff0c;請參考&#xff1a;https://ost.51cto.com/…

QUIC協議如何在UDP基礎上解決網絡切換問題

一、UDP 四元組的本質局限UDP 本身無連接狀態&#xff0c;其數據包僅通過四元組尋址。但 QUIC 在 UDP 之上構建了完整的連接語義。二、QUIC 的連接遷移核心機制1. 連接標識符&#xff08;Connection ID&#xff09;關鍵設計&#xff1a;每個 QUIC 連接擁有全局唯一 64-bit Conn…

力扣131:分割回文串

力扣131:分割回文串題目思路代碼題目 給你一個字符串 s&#xff0c;請你將 s 分割成一些 子串&#xff0c;使每個子串都是 回文串 。返回 s 所有可能的分割方案。 思路 從題目中我們可以總結出這道題的三個需要解決的問題&#xff1a; 如何判斷回文串如何找到一種方案里的所…