CUDA
隨着顯卡的發展,GPU越來越強大,而且GPU爲顯示圖像做了優化。在計算上已經超越了通用的CPU。如此強大的芯片如果只是作爲顯卡就太浪費了,因此NVidia推出CUDA,讓顯卡可以用於圖像計算以外的目的。
host 指代CPU及其內存,
device指代GPU及其內存。
CUDA程序中既包含host程序,又包含device程序,它們分別在CPU和GPU上運行。同時,host與device之間可以進行通信,它們之間可以進行數據拷貝。
GPU並行化的工作流程:
CPU發送一種稱爲kernel的函數到GPU。
GPU同時運行該函數的多個版本,稱爲threads。thread可以組合成block,一個kernel裏的所有thread稱爲一個grid。
threads :thread的不同版本
block : 多個thread組成
grid:一個kernel裏的所有thread
修飾符
__host__
修飾符
__global__
修飾符
__device__
修飾符
__global__
__global__
是CUDA C/C++
的函數修飾符,表示該函數爲一個kernel函數,且
- 該函數會在
GPU(device)
上執行。 - 必須返回
void
。 - 由主機
(host)
代碼調用。 - 只能被CPU調用。
在調用kernel
函數時,函數名後的<<<b, t>>>
b
代表block的數目。t
代表每個block中thread的數目。
//kernel函數需要運行在4個block上,每個block有2個thread
__global__ void myKernel() {
// ...
}
void main()
{
int block,thread;
block=4;
thread=2;
myKernel<<<block,thread>>>();
}
__host__
- 運行在CPU上,每次調用運行一次。
- 只能被CPU調用。
- 所有未顯式標明函數前置修飾符的函數均爲host函數。
__device__
- 運行在GPU上,每次調用運行一次。
- 只能被GPU調用。
#include <stdio.h>
__device__ int dev1() {
}
__device__ int dev2() {
}
__global__ void run10Times() {
//your code here
dev1();
dev2();
//end of your code
}
int main() {
run10Times<<<2, 5>>>();
printf("Hello, World!\n");
return 0;
}
內存分配
cudaMalloc
分配設備上的內存
cudaMemcpy
將不同內存段的數據進行拷貝
cudaFree
釋放先前在設備上申請的內存空間
__host__ cudaError_t cudaMalloc (void **devPtr, size_t size)
/*該函數主要用來分配設備上的內存(即顯存中的內存)。該函數被聲明爲了__host__,即表示被host所調用,即在cpu中執行的代碼所調用。
返回值:爲cudaError_t類型,實質爲cudaError的枚舉類型,其中定義了一系列的錯誤代碼。如果函數調用成功,則返回cudaSuccess。
第一個參數,void ** 類型,devPtr:用於接受該函數所分配的內存地址。
第二個參數,size_t類型,size:指定分配內存的大小,單位爲字節。*/
__host__ cudaError_t cudaMemcpy (void *dst, const void *src, size_t count, enum cudaMemcpyKind kind)
/*
該函數主要用於將不同內存段的數據進行拷貝,內存可用是設備內存,也可用是主機內存
第一個參數,void*類型,dst:爲目的內存地址
第二個參數,const void *類型,src:源內存地址
第三個參數,size_t類型,count:將要進行拷貝的字節大小
第四個參數,enum cudaMemcpyKind類型,kind:拷貝的類型,決定拷貝的方向。
cudaMemcpyKind類型如下:cudaMemcpyHostToHost, cudaMemcpyHostToDevice, cudaMemcpyDeviceToHost, cudaMemcpyDeviceToDevice, cudaMemcpyDefault。*/
__host__ cudaError_t cudaFree (void* devPtr)
/*該函數用來釋放先前在設備上申請的內存空間(通過cudaMalloc、cudaMallocPitch等函數),注意,不能釋放通過標準庫函數malloc進行申請的內存。
返回值:爲錯誤代碼的類型值。
第一個參數,void**類型,devPtr:指向需要釋放的設備內存地址。*/
cudaMemcpyKind類型如下:
cudaMemcpyHostToHost,
cudaMemcpyHostToDevice,
cudaMemcpyDeviceToHost,
cudaMemcpyDeviceToDevice,
cudaMemcpyDefault。
#include <stdio.h>
#include <stdlib.h>
#include <cuda.h>
#include <cuda_runtime.h>
__global__ void colonel(int *a_d){
//your code here
*a_d = 2;
//end of your code
}
int main(){
int a = 0, *a_d;
cudaMalloc((void**) &a_d, sizeof(int));
cudaMemcpy(a_d, &a, sizeof(int), cudaMemcpyHostToDevice);
colonel<<<1, 1>>>(a_d);
cudaMemcpy(&a, a_d, sizeof(int), cudaMemcpyDeviceToHost);
printf("a = %d\n", a);
cudaFree(a_d);
}