CUDA從入門到精通(六):塊並行
同一版本的代碼用了這麼多次,有點過意不去,於是這次我要做較大的改動,大家要擦亮眼睛,拭目以待。
塊並行相當於操作係統中多進程的情況,上節說到,CUDA有線程組(線程塊)的概念,將一組線程組織到一起,共同分配一部分資源,然後內部調度執行。線程塊與線程塊之間,毫無瓜葛。這有利於做更粗粒度的並行。我們將上一節的代碼改為塊並行版本如下:
#include "cuda_runtime.h" #include "device_launch_parameters.h" #include <stdio.h> cudaError_t addWithCuda(int *c, const int *a, const int *b, size_t size); __global__ void addKernel(int *c, const int *a, const int *b) { int i = blockIdx.x; c[i] = a[i] + b[i]; } int main() { const int arraySize = 5; const int a[arraySize] = { 1, 2, 3, 4, 5 }; const int b[arraySize] = { 10, 20, 30, 40, 50 }; int c[arraySize] = { 0 }; // Add vectors in parallel. cudaError_t cudaStatus; int num = 0; cudaDeviceProp prop; cudaStatus = cudaGetDeviceCount(&num); for(int i = 0;i<num;i++) { cudaGetDeviceProperties(&prop,i); } cudaStatus = addWithCuda(c, a, b, arraySize); if (cudaStatus != cudaSuccess) { fprintf(stderr, "addWithCuda failed!"); return 1; } printf("{1,2,3,4,5} + {10,20,30,40,50} = {%d,%d,%d,%d,%d}\n",c[0],c[1],c[2],c[3],c[4]); // cudaThreadExit must be called before exiting in order for profiling and // tracing tools such as Nsight and Visual Profiler to show complete traces. cudaStatus = cudaThreadExit(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaThreadExit failed!"); return 1; } return 0; } // Helper function for using CUDA to add vectors in parallel. cudaError_t addWithCuda(int *c, const int *a, const int *b, size_t size) { int *dev_a = 0; int *dev_b = 0; int *dev_c = 0; cudaError_t cudaStatus; // Choose which GPU to run on, change this on a multi-GPU system. cudaStatus = cudaSetDevice(0); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?"); goto Error; } // Allocate GPU buffers for three vectors (two input, one output) . cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(int)); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMalloc failed!"); goto Error; } // Copy input vectors from host memory to GPU buffers. cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(int), cudaMemcpyHostToDevice); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } // Launch a kernel on the GPU with one thread for each element. addKernel<<<size,1 >>>(dev_c, dev_a, dev_b); // cudaThreadSynchronize waits for the kernel to finish, and returns // any errors encountered during the launch. cudaStatus = cudaThreadSynchronize(); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaThreadSynchronize returned error code %d after launching addKernel!\n", cudaStatus); goto Error; } // Copy output vector from GPU buffer to host memory. cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(int), cudaMemcpyDeviceToHost); if (cudaStatus != cudaSuccess) { fprintf(stderr, "cudaMemcpy failed!"); goto Error; } Error: cudaFree(dev_c); cudaFree(dev_a); cudaFree(dev_b); return cudaStatus; }
和上一節相比,隻有這兩行有改變,<<<>>>裏第一個參數改成了size,第二個改成了1,表示我們分配size個線程塊,每個線程塊僅包含1個線程,總共還是有5個線程。這5個線程相互獨立,執行核函數得到相應的結果,與上一節不同的是,每個線程獲取id的方式變為int i = blockIdx.x;這是線程塊ID。
於是有童鞋提問了,線程並行和塊並行的區別在哪裏?
線程並行是細粒度並行,調度效率高;塊並行是粗粒度並行,每次調度都要重新分配資源,有時資源隻有一份,那麼所有線程塊都隻能排成一隊,串行執行。
那是不是我們所有時候都應該用線程並行,盡可能不用塊並行?
當然不是,我們的任務有時可以采用分治法,將一個大問題分解為幾個小規模問題,將這些小規模問題分別用一個線程塊實現,線程塊內可以采用細粒度的線程並行,而塊之間為粗粒度並行,這樣可以充分利用硬件資源,降低線程並行的計算複雜度。適當分解,降低規模,在一些矩陣乘法、向量內積計算應用中可以得到充分的展示。
實際應用中,常常是二者的結合。線程塊、線程組織圖如下所示。
多個線程塊組織成了一個Grid,稱為線程格(經曆了從一位線程,二維線程塊到三維線程格的過程,立體感很強啊)。
好了,下一節我們介紹流並行,是更高層次的並行。
最後更新:2017-04-03 16:48:42
上一篇:
hdu 4607 Park Visit dfs
下一篇:
CUDA從入門到精通(五):線程並行
Pelican+Github搭建博客
MaxCompute UDF係列之判斷字符串中是否包含漢字
PostgreSQL 聚合表達式 FILTER , order , within group 用法
看過WWDC2017的閑談
java 在線編輯模版 代碼編輯器 兼容手機平板PC freemaker 靜態引擎 網站源碼
讓BASH,VIM美美的Powerline
《Node.js區塊鏈開發》——3.5 億書對DPoS機製的改進
HTML5學習資料推薦
如何查看Memcache 運行狀態 stats(Status) —— Memcache Telnet 接口
java中自定義annotation