使用 NVProf 檢測 CUDA kernel 的 bank conflict

使用 NVProf 檢測 CUDA kernel 的 bank conflict

NVProf 指令

使用 NVProf 可以對 bank conflict 進行檢測:

nvprof --events shared_ld_bank_conflict,shared_st_bank_conflict <app> [args...]

其中:

  • --events 選項指定的 shared_ld_bank_conflict,shared_st_bank_conflict分別代指從 shared memory 加載(讀取)時產生的 bank conflict, 以及向 shared memory 存儲(寫入)時產生的 bank conflict.
  • <app> [args...] 即要檢測的 CUDA 二進制程序及其參數.

額外說明

值得一提的是, 如果沒有從 shared memory 讀取的指令, 且沒有使用 -G 編譯, 則兩種 bank conflict 事件都無法檢測出來, 即使存在向 shared memory 寫入產生的 bank conflict.
(沒有讀取的 bank conflict 很好理解, 因為都沒有從 shared memory 讀取數據; 而至于寫入的 bank conflict, 應該是編譯器做了一定的優化, 即 shared memory 雖被寫入但數據沒有被讀取, 則寫入是沒有意義的, 這部分代碼實際并不執行, 所有寫入的 bank conflict 就不會檢測到了.)

這個主要作用是, 當我們對自己寫的 kernel 的 bank conflict 進行檢測的時候, 要確保保留對 shared memory 讀取的相關代碼或設置 -G 編譯選項, 否則可能會影響 bank conflict 的檢測.

舉例

以下代碼是一個很簡單的 CUDA kernel 示例, 考慮到 bank conflict 是 warp 層面的問題, 所有 kernel 中我定義了 warp_id, land_id 等變量便于后續 bank conflict 的說明.

#include <iostream>
#include <cstdio>
#include <vector>
#include <cuda.h>using namespace std;constexpr int SIZE_A = 64;
constexpr int SIZE_C = 64;__global__ void kernel(const int* a, int* c) {auto tid = (blockIdx.x * blockDim.x + threadIdx.x);auto lane_id = threadIdx.x & 0x1F;auto warp_id = tid >> 5;auto warp_in_block = threadIdx.x >> 5;__shared__ int shm[SIZE_A];if (tid < SIZE_A) {shm[warp_id * 32 + lane_id] = a[warp_id * 32 + lane_id];}if (tid < SIZE_C) {c[warp_id * 32 + lane_id] = shm[warp_id * 32 + lane_id];}
}int main() {vector<int> a(SIZE_A);for (int i = 0; i < SIZE_A; ++i) {a[i] = i;}int* d_a;cudaMalloc(&d_a, sizeof(int) * SIZE_A);cudaMemcpy(d_a, a.data(), sizeof(int) * SIZE_A, cudaMemcpyHostToDevice);int* d_c;cudaMalloc(&d_c, sizeof(int) * SIZE_C);cudaMemset(d_c, 0, sizeof(int) * SIZE_C);kernel<<<1, 128>>>(d_a, d_c);vector<int> c(SIZE_C);cudaMemcpy(c.data(), d_c, sizeof(int) * SIZE_C, cudaMemcpyDeviceToHost);for (auto x : c) {cout << x << " ";}cout << endl;cudaFree(d_c);cudaFree(d_a);return 0;
}

kernel() 函數完成的功能很簡單, 就是想數組 a 中的一部分數據先寫至 shared memory shm, 再寫入到 c 中. 在沒有額外說明時, 不使用 -G 選項編譯代碼.
很明顯的是, 由于 shm 的讀寫時, 每個 warp 的 32 個線程分片讀取不同的 4 字節數據, 因此代碼沒有 bank conflict.
在這里插入圖片描述
使用上述 NVProf 指令檢測, 結果也印證了上述推斷.

現在將 Kernel 修改如下:

__global__ void kernel(const int* a, int* c) {auto tid = (blockIdx.x * blockDim.x + threadIdx.x);auto lane_id = threadIdx.x & 0x1F;auto warp_id = tid >> 5;auto warp_in_block = threadIdx.x >> 5;__shared__ int shm[SIZE_A];// if (tid < SIZE_A) {//     shm[warp_id * 32 + lane_id] = a[warp_id * 32 + lane_id];// }for (auto i = threadIdx.x; i < SIZE_A; i += blockDim.x) {shm[(i % 2) * SIZE_A / 2 + i / 2] = a[i];}if (tid < SIZE_C) {c[warp_id * 32 + lane_id] = shm[warp_id * 32 + lane_id];;}
}

我們在讀取 a 數組到 shared memory 的時候, 進行了一點修改. 可以看到, 對應相鄰的兩個線程, tt+1 (假設 t % 2 ==0), 則一個寫入到 shm[t/2], 一個寫入到 shm[SIZE_A/2+(t+1)/2]shm[32+t/2], 由于恰好差了 32 個元素, 因此會訪問到相同的 bank, 會觸發 bank conflict. 通過 NVProf 檢測也得到了證實:
在這里插入圖片描述
這里的 2 次, 原因筆者猜測為 SIZE_A 大小為 64, 對應 2 個 warp, 每個 warp 相鄰的奇數線程和偶數線程訪問同一 bank, 以 warp 為單位, 每個 warp 產生 1 個 bank conflict, 共 2 個.

但如果我們將后面將 shm 寫入 c 數組的代碼注釋掉, 即沒有從 shared memory 讀取的代碼, 則可以看到 NVProf 并不會檢測到剛剛的 shared_st_bank_conflict.

    if (tid < SIZE_C) {c[warp_id * 32 + lane_id] = shm[warp_id * 32 + lane_id];;}

在這里插入圖片描述

但如果我們在編譯的時候使用 -G 選項, 則可以看到剛剛的 shared_st_bank_conflict 有可以被檢測到了:
在這里插入圖片描述

因此, 可以推斷出, 在默認情況下, 編譯器對于不讀取的 shared memory 的寫入操作會進行優化, 實際上并不會執行 shared memory 的寫入操作, 而 debug 模式 (帶 -G 選項)時, 則不會進行該優化.

如下代碼展示了在從 shared memory shm 讀取到 c 數組時的 bank conflict.

constexpr int SIZE_A = 64;
constexpr int SIZE_C = 32;__global__ void kernel(const int* a, int* c) {auto tid = (blockIdx.x * blockDim.x + threadIdx.x);auto lane_id = threadIdx.x & 0x1F;auto warp_id = tid >> 5;auto warp_in_block = threadIdx.x >> 5;__shared__ int shm[SIZE_A];if (tid < SIZE_A) {shm[warp_id * 32 + lane_id] = a[warp_id * 32 + lane_id];}if (tid < SIZE_C) {// c[warp_id * 32 + lane_id] = shm[warp_id * 32 + lane_id];c[warp_id * 32 + lane_id] =shm[warp_in_block * 32 + lane_id / 8 + (lane_id % 2) * 32];}
}

可以看到, 相鄰的 8 個線程分奇偶訪問同一 bank 的兩個地址. NVProf 輸出如下:
在這里插入圖片描述

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

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

相關文章

python -opencv 中值濾波 ,均值濾波,高斯濾波實戰

python -opencv 中值濾波 &#xff0c;均值濾波&#xff0c;高斯濾波實戰 cv2.blur-均值濾波 cv2.medianBlur-中值濾波 cv2.GaussianBlur-高斯濾波 直接看代碼吧&#xff0c;代碼很簡單&#xff1a; import copy import math import matplotlib.pyplot as plt import matp…

c++的更嚴格的類型轉換要求

C有更嚴格的類型轉換要求 C中對類型轉換有嚴格的要求&#xff0c;需要的類型和給的類型不 一致時可能會編譯報錯 例如&#xff1a; C語言中 #include<stdio.h> #include<stdlib.h> //全局變量 //C語言中的函數的形參的類型可以不寫&#xff0c;沒有返回值可以返回&…

聯發科正在改寫全球高端手機芯片市場格局

全球高端手機芯片市場正在重塑。 11 月 21 日&#xff0c;聯發科發布了新一代卓越 5G 生成式 AI 移動芯片天璣 8300。 這款定位于中端機檔位的芯片&#xff0c;無論在技術架構還是在實際性能表現上&#xff0c;都實現了對前代旗艦芯片的趕超&#xff0c;徹底打破了業內長期存…

相機和濾鏡應用程序Nevercenter CameraBag Photo mac軟件特點說明

Nevercenter CameraBag Photo mac是一款相機和濾鏡應用程序&#xff0c;它提供了一系列先進的濾鏡、調整工具和預設&#xff0c;可以幫助用戶快速地優化和編輯照片。 Nevercenter CameraBag Photo mac軟件特點 1. 濾鏡&#xff1a;Nevercenter CameraBag Photo提供了超過200種…

復費率電表和預付費電表有哪些區別?

隨著科技的發展和能源管理的日益嚴格&#xff0c;電表技術也在不斷更新換代。復費率電表和預付費電表作為兩種主流的智能電表&#xff0c;各自具有獨特的優勢和應用場景。接下來&#xff0c;小編來為大家詳細解析這兩種電表的區別及其應用場景。 一、復費率電表 1.定義及工作原…

計算機精度導致各種誤差,大數吃小數

如果 p ? p^* p?是p的近似, ∣ p ? ? p ∣ |p^*-p| ∣p??p∣是絕對誤差, ∣ p ? ? p ∣ / ∣ p ∣ |p^*-p|/|p| ∣p??p∣/∣p∣是相對誤差 舍入誤差,就是數據表示精度不足帶來的誤差 a0.1234564≈0.123456fl(a) b0.1234546≈0.123455fl(b) 在上面發生了舍入誤差 f…

力扣labuladong一刷day15天K個一組翻轉鏈表與回文鏈表

力扣labuladong一刷day15天K個一組翻轉鏈表與回文鏈表 一、25. K 個一組翻轉鏈表 題目鏈接&#xff1a;https://leetcode.cn/problems/reverse-nodes-in-k-group/ 思路&#xff1a;k個一組翻轉鏈表&#xff0c;每k個翻轉抽取出一個單獨的方法reverse&#xff0c;翻轉a到b&…

力扣刷題第二十九天--二叉樹

前言 問問自己&#xff0c;刷題的效果真的達到了嗎&#xff1f; 內容 一、翻轉二叉樹 226.翻轉二叉樹 給你一棵二叉樹的根節點 root &#xff0c;翻轉這棵二叉樹&#xff0c;并返回其根節點。 遞歸 func invertTree(root *TreeNode) *TreeNode {if rootnil{return root}…

Vue中的$nextTick的作用

在 Vue 中&#xff0c;當某些數據發生變化時&#xff0c;DOM 并不會立即更新。相反&#xff0c;Vue 會在下一個事件循環周期&#xff08;microtask&#xff09;中異步執行更新&#xff0c;這樣可以避免頻繁的 DOM 操作。然而&#xff0c;有時候我們需要在 DOM 更新后執行一些操…

2024-NeuDS-數據庫題目集

一.判斷題 1.在數據庫中產生數據不一致的根本原因是冗余。T 解析&#xff1a;數據冗余是數據庫中產生數據不一致的根本原因&#xff0c;因為當同一數據存儲在多個位置時&#xff0c;如果其中一個位置的數據被修改&#xff0c;其他位置的數據就不一致了。因此&#xff0c;在數據…

11.docker的網絡-docker0的理解及bridge網橋模式的介紹與實例

1.docker0的基本理解 安裝完docker服務后&#xff0c;我們首先查看一下宿主機的網絡配置 ifconfig我們可以看到&#xff0c;docker服務會默認在宿主機上創建一個虛擬網橋docker0&#xff0c;該網橋網絡的名字稱為docker0。它在內核層連通了其他物理或者虛擬網卡&#xff0c;這…

ubuntu22.04系統下載程序和依賴,并拷貝到指定路徑下

腳本1 apt install aptitude apt-get -d install xxx #xxx是待下載的安裝包 mv /var/cache/apt/archives/* /home/tuners/1apt install aptitude apt-get -d install xxx mv /var/cache/apt/archives/*.deb /home/tuners/1 xxx 為程序包名稱 /home/tuners/1為保存程序包的…

從零開始的搭建指南:開發高效的抖音預約服務小程序

預約服務小程序提高了效率&#xff0c;節省了用戶時間。下文&#xff0c;小編將與大家一同探討如何從零開始打造預約服務小程序。 第一步&#xff1a;明確需求和目標 確定你的小程序主要服務領域是什么&#xff1f;是醫療預約、美容美發、餐廳預訂還是其他行業&#xff1f;明…

Python 如何開發出RESTful Web接口,DRF框架助力靈活實現!

Django Rest Framework&#xff08;DRF&#xff09;是構建強大且靈活的Web API的優秀工具。它基于Django&#xff0c;提供了一套用于構建Web API的組件和工具&#xff0c;簡化了API開發過程&#xff0c;同時保留了Django的優雅和強大。 一、Web應用模式 在開發Web應用時&…

Android組件化搭建學習

什么是組件化&#xff1f; 為什么要用組件化&#xff1f;在項目的開發過程中&#xff0c;隨著開發人員的增多及功能的增加&#xff0c;如果提前沒有使用合理的開發架構&#xff0c;那么代碼會越來臃腫&#xff0c;功能間代碼耦合也會越來越嚴重&#xff0c;這時候為了保證項目…

C# 忽略大小寫

在 C# 中&#xff0c;你可以通過以下幾種方式來忽略大小寫&#xff1a; 使用 ToLower 或 ToUpper 方法將字符串轉換為全小寫或全大寫&#xff0c;然后進行比較。使用 Compare 或 CompareOrdinal 方法&#xff0c;并傳入正確的 StringComparer 實例以指示比較應該忽略大小寫。使…

Android 開發Java調用Kotlin提示包不存在

在kotlin代碼所在module的build.gradle設置 plugins {id org.jetbrains.kotlin.android }

Unity中Shader的Standard材質解析(一)

文章目錄 前言一、在Unity中&#xff0c;按一下步驟準備1、在資源管理面板創建一個 Standard Surface Shader2、因為Standard Surface Shader有很多缺點&#xff0c;所以我們把他轉化為頂點片元著色器3、整理只保留主平行光的Shader效果4、精簡后的最終代碼 前言 在Unity中&am…

基于Springboot+Vue選課系統

選課系統要求 (1)數據庫表&#xff1a;教師信息表、學生信息表、課程表、選課表 其中&#xff0c;教師信息表、學生信息表和選課表的數據需要提前設置&#xff0c;本題主要操作課程表 (2) 技術架構&#xff1a; 后臺使用springboot 前端使用vue-admin-template (3) 考試時間&…

鴻蒙(HarmonyOS)應用開發——安裝DevEco Studio安裝

前言 HarmonyOS華為開發的操作系統&#xff0c;旨在為多種設備提供統一的體驗。它采用了分布式架構&#xff0c;可以在多個設備上同時運行&#xff0c;提供更加流暢的連接和互動。HarmonyOS的目標是提供更高的安全性、更高效、響應更快的用戶體驗&#xff0c;并通過跨設備功能…