[菜鳥每天來段CUDA_C]多GPU的使用
單個GPU具有強大的平行計算的能力,當把多個GPU同時用來執行同一個任務的時候,計算的效能將會得到更大的提升。本文在兩塊GPU上實現大資料量的向量點積運算。主要步驟為:
1. 獲得裝置數量;
2. 任務分配;
3. 為每個任務建立一個執行緒;
4. 啟動每個執行緒進行運算;
5. 合併每個GPU得到的結果。
程式程式碼:
主程式:main.cpp
#include "main.h" #include <stdio.h> extern "C" void runDotProduct(float *dev_a, float *dev_b, float *dev_partial_c, int size); void* worker(void *pvoidData) { GPUPlan *plan = (GPUPlan*) pvoidData; HANDLE_ERROR(cudaSetDevice(plan->deviceID)); int size = plan->size; float *a, *b, c, *partial_c; float *dev_a, *dev_b, *dev_partial_c; a = plan->a; b = plan->b; partial_c = (float*)malloc(blockPerGrid*sizeof(float)); HANDLE_ERROR(cudaMalloc((void**)&dev_a, size*sizeof(float))); HANDLE_ERROR(cudaMalloc((void**)&dev_b, size*sizeof(float))); HANDLE_ERROR(cudaMalloc((void**)&dev_partial_c, blockPerGrid*sizeof(float))); HANDLE_ERROR(cudaMemcpy(dev_a, a, size*sizeof(float), cudaMemcpyHostToDevice)); HANDLE_ERROR(cudaMemcpy(dev_b, b, size*sizeof(float), cudaMemcpyHostToDevice)); runDotProduct(dev_a, dev_b, dev_partial_c, size); HANDLE_ERROR(cudaMemcpy(partial_c, dev_partial_c, blockPerGrid*sizeof(float), cudaMemcpyDeviceToHost)); c = 0; for (int i=0; i<blockPerGrid; i++) { c += partial_c[i]; } HANDLE_ERROR(cudaFree(dev_a)); HANDLE_ERROR(cudaFree(dev_b)); HANDLE_ERROR(cudaFree(dev_partial_c)); free(partial_c); plan->returnValue = c; return 0; } int main() { //on two GPUs int i; int deviceCount; HANDLE_ERROR(cudaGetDeviceCount(&deviceCount)); if (deviceCount < 2) { printf("No more than 2 device with compute 1.0 or greater." "only %d devices found", deviceCount); return 0; } float *a = (float*)malloc(sizeof(float)*N); HANDLE_NULL(a); float *b = (float*)malloc(sizeof(float)*N); HANDLE_NULL(b); for (i=0; i<N; i++) { a[i] = i; b[i] = i * 2; } GPUPlan plan[2]; plan[0].deviceID = 0; plan[0].size = N/2; plan[0].a = a; plan[0].b = b; plan[1].deviceID = 1; plan[1].size = N/2; plan[1].a = a + N/2; plan[1].b = b + N/2; cudaEvent_t start, stop; HANDLE_ERROR(cudaEventCreate(&start)); HANDLE_ERROR(cudaEventCreate(&stop)); float elapsedTime; HANDLE_ERROR(cudaEventRecord(start)); CUTThread mythread1 = start_thread((CUT_THREADROUTINE)worker, &plan[0]); CUTThread mythread2 = start_thread((CUT_THREADROUTINE)worker, &plan[1]); //worker(&plan[1]); end_thread(mythread1); end_thread(mythread2); HANDLE_ERROR(cudaEventRecord(stop)); HANDLE_ERROR(cudaEventSynchronize(stop)); HANDLE_ERROR(cudaEventElapsedTime(&elapsedTime, start, stop)); printf("Computing by 2 GPUs finished in %3.1f <ms>\n", elapsedTime); printf("value calculated: %f\n", plan[0].returnValue + plan[1].returnValue); HANDLE_ERROR(cudaEventDestroy(start)); HANDLE_ERROR(cudaEventDestroy(stop)); free(a); free(b); // on one GPU float *host_a; float *host_b; float *partial_c; host_a = (float*)malloc(N*sizeof(float)); host_b = (float*)malloc(N*sizeof(float)); partial_c = (float*)malloc(blockPerGrid*sizeof(float)); for (int i=0; i<N; i++) { host_a[i] = i; host_b[i] = 2 * i; } float *dev_a, *dev_b, *dev_partial_c; HANDLE_ERROR(cudaMalloc((void**)&dev_a, N*sizeof(float))); HANDLE_ERROR(cudaMalloc((void**)&dev_b, N*sizeof(float))); HANDLE_ERROR(cudaMalloc((void**)&dev_partial_c, blockPerGrid*sizeof(float))); HANDLE_ERROR(cudaMemcpy(dev_a, host_a, N*sizeof(float), cudaMemcpyHostToDevice)); HANDLE_ERROR(cudaMemcpy(dev_b, host_b, N*sizeof(float), cudaMemcpyHostToDevice)); cudaEvent_t start1, stop1; HANDLE_ERROR(cudaEventCreate(&start1)); HANDLE_ERROR(cudaEventCreate(&stop1)); HANDLE_ERROR(cudaEventRecord(start1)); runDotProduct(dev_a, dev_b, dev_partial_c, N); HANDLE_ERROR(cudaEventRecord(stop1)); HANDLE_ERROR(cudaEventSynchronize(stop1)); HANDLE_ERROR(cudaEventElapsedTime(&elapsedTime, start1, stop1)); printf("Computing by one GPU finished in %3.1f <ms>\n", elapsedTime); HANDLE_ERROR(cudaMemcpy(partial_c, dev_partial_c, blockPerGrid*sizeof(float), cudaMemcpyDeviceToHost)); float res = 0; for (int i=0; i<blockPerGrid; i++) { res += partial_c[i]; } printf("value calculated: %f\n", res); HANDLE_ERROR(cudaEventDestroy(start1)); HANDLE_ERROR(cudaEventDestroy(stop1)); HANDLE_ERROR(cudaFree(dev_a)); HANDLE_ERROR(cudaFree(dev_b)); HANDLE_ERROR(cudaFree(dev_partial_c)); free(host_a); free(host_b); free(partial_c); return 0; }
核函式:kernel.cu
#define imin(a,b) (a<b?a:b) extern const int N = 33 * 1024 * 1024; extern const int threadsPerBlock = 256; extern const int blockPerGrid = imin(32, (N+threadsPerBlock-1)/threadsPerBlock); __global__ void dotProduct(float *a, float *b, float *c, int N) { __shared__ float cache[threadsPerBlock]; int tid = blockDim.x * blockIdx.x + threadIdx.x; int cacheIdx = threadIdx.x; float temp = 0; while (tid < N) { temp += a[tid] * b[tid]; tid += blockDim.x * gridDim.x; } cache[cacheIdx] = temp; __syncthreads(); int i = blockDim.x /2; while (i != 0) { if (cacheIdx < i) { cache[cacheIdx] += cache[cacheIdx+i]; } __syncthreads(); i /= 2; } if (cacheIdx == 0) { c[blockIdx.x] = cache[0]; } } extern "C" void runDotProduct(float *dev_a, float *dev_b, float *dev_partial_c, int size) { dotProduct<<<blockPerGrid, threadsPerBlock>>>(dev_a, dev_b, dev_partial_c, size); }
本文試圖將同樣的資料在單個GPU上計算,比較計算時間來突出多GPU在計算效能上的提升。但實際情況是多GPU的計算時間卻比單GPU更長。初步考慮是覺得核函式太簡單,使得GPU執行的效能提升不足以彌補裝置分配以及執行緒排程等帶來的開銷。所以多GPU也許更適合在大量複雜計算的場景下使用~
相關推薦
[菜鳥每天來段CUDA_C]多GPU的使用
單個GPU具有強大的平行計算的能力,當把多個GPU同時用來執行同一個任務的時候,計算的效能將會得到更大的提升。本文在兩塊GPU上實現大資料量的向量點積運算。主要步驟為: 1. 獲得裝置數量; 2. 任務分配; 3. 為每個任務建立一個執行緒;
菜鳥每天來段CUDA_C]多GPU的使用
單個GPU具有強大的平行計算的能力,當把多個GPU同時用來執行同一個任務的時候,計算的效能將會得到更大的提升。本文在兩塊GPU上實現大資料量的向量點積運算。主要步驟為:1. 獲得裝置數量;2. 任務分配;3. 為每個任
[菜鳥每天來段CUDA_C]GPU實現水波動畫效果
本文利用GPU強大的計算能力生成不同時刻的水波圖片,並使用OpenGL繪製,實現水波動畫效果。其中幾個時刻的截圖如下: 生成一幀動畫的程式碼為: void generateFrame(DataBlock *d, int ticks) { dim3 blocks(DIM
[菜鳥每天來段CUDA_C] 利用頁鎖定記憶體提高運算效率
本文通過使用malloc分配記憶體和cudaHostAlloc分配頁鎖定記憶體,說明使用頁鎖定記憶體可提高運算效率,並指出哪些場合適合使用頁鎖定記憶體。 malloc分配的是標準的可分頁的(pagable)的主機記憶體,作業系統在對記憶體進行排程的時候可能會將這種記憶體分頁
菜鳥學Python之Python多版本共存安裝
Python的安裝 進入Python官方網站:www.python.org下載系統對應的Python版本 按照提示步奏安裝,安裝路徑選擇自定義,方便查詢 安裝完成後,按win+R鍵,輸入cmd進入cmd程式,輸入Python,如果能夠進入互動環境,則表示安裝完成 Python多版本共存
菜鳥先飛之JAVA_多執行緒
多執行緒的概述 執行緒是程式執行的一條路徑, 一個程序中可以包含多條執行緒,多執行緒併發執行可以提高程式的效率, 可以同時完成多項工作。 併發和並行的區別,並行就是兩個任務同時執行,就是甲任務進行的同時,乙任務也在進行。(需要多核CPU);併發是指兩個任務都
菜鳥攻略——C語言多檔案程式設計初探(一)
發現有很多童鞋學了一年半載的C語言還不會多檔案程式設計。很多人到現在一個程式都只有一個原始檔(main.cpp或mian.c)。甚至連我的室友大飛哥(我們都大二下學期了)昨天也問我怎麼做。
Python菜鳥晉級12----多線程
span not 可選 正在 元素 等待 run gin cti Python 多線程 多線程類似於同一時候執行多個不同程序,多線程執行有例如以下長處: 使用線程能夠把占領長時間的程序中的任務放到後臺去處理。用戶界面能夠更加吸引人。這樣比方用戶點擊了一個butto
(多圖慎入)圖解菜鳥到大拿實現財務自由走向人生巔峰之路
情況下 項目管理 備註 互聯 職業 mark jpg min 產品經理 整體發展線路 生命就是一場永不停止的修煉過程 也是一場折騰的過程 生命不息 折騰不止 愛折騰是技術人員必備的“功夫”,沒有之一 職業發展線路圖 職業發展對運維人員的要求特別嚴苛,因為運維人員針對不同的問
牛客網暑期ACM多校訓練營(第二場)菜鳥補題QAQ
warn 分享圖片 ini lin int 技術分享 ace main bre G transform 題目大意: 數軸上有n個集裝箱,第i個集裝箱位於坐標x[i],有a[i]件貨物。現在要把集裝箱進行一些移動,求在所有貨物移動總距離不超過T的情況下,最多能把多少
菜鳥程式設計師想趁頭髮還在找個女友!原因:陪機器人比陪女生時間多
近日,一位程式設計師相親圖引起了網友們的圍觀。這位"天然呆"的程式設計師表示自己現在年紀不小了,想趁頭髮還沒掉光時找個女朋友。 而關於擇偶標準,他表示是女孩就行,不是產品經理的話條件還能再放寬。這位天然呆的程式設計師小哥哥是負責快遞倉的倉儲自動化方面的,小哥哥表示,工作就是通過系統排程完成
如何簡單高效地部署和監控分散式爬蟲專案?菜鳥來教你!
初級使用者: 只有一臺開發主機 能夠通過 Scrapyd-client 打包和部署 Scrapy 爬蟲專案,以及通過 Scrapyd JSON API 來控制爬蟲,感覺 命令列操作太麻煩 ,希望能夠通過瀏覽器直接部署和執行專案 專業使用者: 有
面試被當成菜鳥,程式設計師:當場摘帽子,面試官:明天來上班!
很多求職者,都有過面試的經歷,這個過程很讓人煎熬,因為面試前需要做很多準備,比如修改簡歷、準備面試內容,甚至還要思考面試時要怎麼穿著才得體。 雖然說光看外表並不能客觀的反映一個人的真實能力,但是面試官也會通過求職者的外形和裝扮來判斷他們的經驗和閱歷。 學習web前端找工作這裡推
Java多執行緒菜鳥入門&執行緒安全
什麼是程序 電腦中時會有很多單獨執行的程式,每個程式有一個獨立的程序,而程序之間是相互獨立存在的。比如下圖中的QQ、酷狗播放器、電腦管家等等。 什麼是執行緒 程序想要執行任務就需要依賴執行緒。換句話說,就是程序中的最小執行單位就是執行緒,並且一個程序中至少有一個
菜鳥學python第二十四天(面向物件三大特性之多型)
面向物件三大特性之多型 什麼是多型 不同物件響應同一種方法的表現出不同的行為,產生不同的結果 用基類建立一套統一的規則,強制子類去遵循(使用抽象類實現),這樣便可以 在不用考慮物件具體型別的前提下而直接使用物件下的方法 為什麼要有多型 增加了程式的靈活性 以不變應萬變,不論
Java程式設計師從笨鳥到菜鳥之(三)面向物件之封裝,繼承,多型(下)
五:再談繼承 繼承是一種聯結類的層次模型,並且允許和鼓勵類的重用,它提供了一種明確表述共性的方法。物件的一個新類可以從現有的類中派生,這個過程稱為類繼承。新類繼承了原始類的特性,新類稱為原始類的派生類(子類),而原始類稱為新類的基類(父類)。派生類可以從它的基類那裡繼承方法和例項變數,並且類可以修改或增加
Java程式設計師從笨鳥到菜鳥之(五十四)細談Hibernate(五)Hibernate一對多關係對映
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興! 前幾篇系列部落格: 在前幾篇部落格,我們初步對Hibernate有了一定的基礎性的認知了,也能夠簡單的用hibernate進行
# Mybatis(四)表間關係分析,高階對映(一對一,一對多,多對多) 菜鳥日記--day05(下_02)
Mybatis(四)表間關係分析,高階對映(一對一,一對多,多對多) 菜鳥日記–day05(下_02) 花了很多時間,去看sql複雜查詢,更新慢了 電腦斷電寫的太急,綠色補更 一、表間關係分析 1.分析資料庫表的方法 思路: 需要分模組的對多張表進行邏輯分析 表記錄
菜鳥們注意了,來看看大神們推薦的運維資料和書籍
對於有志成為運維工程師的在校學生,有哪些好的運維方面的好書或者資料推薦? 韓海剛,運維 苦練基本功 1. 熟悉windows、linux作業系統;作業系統原理是精髓。 2. sed、awk、grep等指令碼用法熟悉;正則表示式熟悉。 3. 常見系統在windows,linux下部署要熟悉。比如dns
菜鳥的C#學習之旅——多型的實現途徑
目錄 一、定義 二、虛方法: 三、抽象類與抽象方法: 四、介面實現: 五、總結: 一、定義 多型:在面嚮物件語言中,介面的多種不同實現方式即為多型 多型性就是指在程式執行時,執行的雖然是一個呼叫方法的語句,卻可以根據派生類物件的型別的不同完成方法不同的具體實現