Mais conteúdo relacionado
Semelhante a 2015年度GPGPU実践基礎工学 第11回 GPUでの並列プログラミング(ベクトル和) (20)
2015年度GPGPU実践基礎工学 第11回 GPUでの並列プログラミング(ベクトル和)
- 8. #define N (1024*1024)
void init(float *a, float *b,
float *c){
int i;
for(i=0; i<N; i++){
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
}
void add(float *a, float *b,
float *c){
int i;
for(i=0; i<N; i++)
c[i] = a[i] + b[i];
}
int main(void){
float a[N],b[N],c[N];
init(a,b,c);
add(a,b,c);
return 0;
}
CPUプログラム(メモリの静的確保)
GPGPU実践基礎工学
vectoradd.c
8 2015/11/18
- 9. #include<stdlib.h>
#define N (1024*1024)
#define Nbytes (N*sizeof(float))
void init(float *a, float *b,
float *c){
int i;
for(i=0; i<N; i++){
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
}
void add(float *a, float *b,
float *c){
int i;
for(i=0; i<N; i++)
c[i] = a[i] + b[i];
}
int main(void){
float *a,*b,*c;
a = (float *)malloc(Nbytes);
b = (float *)malloc(Nbytes);
c = (float *)malloc(Nbytes);
init(a,b,c);
add(a,b,c);
free(a);
free(b);
free(c);
return 0;
}
CPUプログラム(メモリの動的確保)
GPGPU実践基礎工学9
vectoradd_malloc.c
2015/11/18
- 16. #include<stdlib.h>
#define N (1024*1024)
#define Nbytes (N*sizeof(float))
void init(float *a, float *b,
float *c){
int i;
for(i=0; i<N; i++){
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
}
void add(float *a, float *b,
float *c){
int i;
for(i=0; i<N; i++)
c[i] = a[i] + b[i];
}
int main(void){
float *a,*b,*c;
a = (float *)malloc(Nbytes);
b = (float *)malloc(Nbytes);
c = (float *)malloc(Nbytes);
init(a,b,c);
add(a,b,c);
free(a);
free(b);
free(c);
return 0;
}
CPUプログラム(メモリの動的確保)
GPGPU実践基礎工学16
vectoradd_malloc.c
2015/11/18
- 17. #define N (1024*1024)
#define Nbytes (N*sizeof(float))
__global__ void init(float *a,float *b,
float *c){
int i;
for(i=0; i<N; i++){
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
}
__global__ void add(float *a,float *b,
float *c){
int i;
for(i=0; i<N; i++)
c[i] = a[i] + b[i];
}
int main(void){
float *a,*b,*c;
cudaMalloc((void **)&a, Nbytes);
cudaMalloc((void **)&b, Nbytes);
cudaMalloc((void **)&c, Nbytes);
init<<< 1, 1>>>(a,b,c);
add<<< 1, 1>>>(a,b,c);
cudaDeviceSynchronize();
cudaFree(a);
cudaFree(b);
cudaFree(c);
return 0;
}
GPUプログラム(1スレッド実行版)
GPGPU実践基礎工学
vectoradd_1thread.cu
17 2015/11/18
- 18. #define N (1024*1024)
#define Nbytes (N*sizeof(float))
__global__ void init(float *a,float *b,
float *c){
int i;
for(i=0; i<N; i++){
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
}
__global__ void add(float *a,float *b,
float *c){
int i;
for(i=0; i<N; i++)
c[i] = a[i] + b[i];
}
int main(void){
float *a,*b,*c;
cudaMalloc((void **)&a, Nbytes);
cudaMalloc((void **)&b, Nbytes);
cudaMalloc((void **)&c, Nbytes);
init<<< 1, 1>>>(a,b,c);
add<<< 1, 1>>>(a,b,c);
cudaDeviceSynchronize();
cudaFree(a);
cudaFree(b);
cudaFree(c);
return 0;
}
GPUプログラム(1スレッド実行版)
GPGPU実践基礎工学18 2015/11/18
vectoradd_1thread.cu
GPUカーネルの
目印
並列実行の度
合を指定
GPUカーネルの
目印
GPUのメモリに
確保
確保したメモリ
を解放
- 22. 実行結果
GPGPU実践基礎工学22
プロファイルの一連の流れ
method カーネルや関数(API)の名称
gputime GPU上で処理に要した時間(s単位)
cputime CPUで処理(=カーネル起動)に要した時間
実際の実行時間=cputime+gputime
occupancy GPUがどれだけ効率よく利用されているか
‐bash‐3.2$ nvcc vectoradd_1thread.cu プログラムをコンパイル(実行ファイルa.outが作られる)
‐bash‐3.2$ export CUDA_PROFILE=1 環境変数CUDA_PROFILEを1にしてプロファイラを有効化
‐bash‐3.2$ ./a.out プログラムを実行(cuda_profile_0.logというファイルが作られる)
‐bash‐3.2$ cat cuda_profile_0.log cuda_profile_0.logの内容を画面に表示
# CUDA_PROFILE_LOG_VERSION 2.0
# CUDA_DEVICE 0 Tesla M2050
# TIMESTAMPFACTOR fffff5f8a8002b58
method,gputime,cputime,occupancy
method=[ _Z4initPfS_S_ ] gputime=[ 201039.484 ] cputime=[ 17.000 ] occupancy=[ 0.021 ]
method=[ _Z3addPfS_S_ ] gputime=[ 205958.375 ] cputime=[ 6.000 ] occupancy=[ 0.021 ]
2015/11/18
- 25. #define N (1024*1024)
#define Nbytes (N*sizeof(float))
__global__
void init(float *a,float *b,float *c){
for(int i=0; i<N; i++){
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
}
__global__
void add(float *a,float *b, float *c){
for(int i=0; i<N; i++)
c[i] = a[i] + b[i];
}
int main(void){
float *a,*b,*c;
float *host_c, sum=0.0f;
cudaMalloc((void **)&a, Nbytes);
cudaMalloc((void **)&b, Nbytes);
cudaMalloc((void **)&c, Nbytes);
host_c = (float *)malloc(Nbytes);
init<<< 1, 1>>>(a,b,c);
add<<< 1, 1>>>(a,b,c);
cudaMemcpy(host_c,c,Nbytes,
cudaMemcpyDeviceToHost);
for(int i=0;i<N;i++)
sum += host_c[i];
printf("average:%f¥n",sum/N);
cudaFree(a);
cudaFree(b);
cudaFree(c);
free(host_c);
return 0;
}
GPUプログラム(cudaMemcpy利用)
GPGPU実践基礎工学
vectoradd_copy.cu
25 2015/11/18
- 27. #define N (1024*1024)
#define Nbytes (N*sizeof(float))
__global__ void add(float *a, float x,
float *b, float y, float *c){
for(int i=0; i<N; i++)
c[i] = x*a[i] + y*b[i];
}
int main(void){
float *a,*b,*c;
float *host_a, *host_b, *host_c;
float x=1.0f, y=2.0f;
cudaMalloc((void **)&a, Nbytes);
cudaMalloc((void **)&b, Nbytes);
cudaMalloc((void **)&c, Nbytes);
host_a = (float *)malloc(Nbytes);
host_b = (float *)malloc(Nbytes);
host_c = (float *)malloc(Nbytes);
for(int i=0; i<N; i++){
host_a[i] = 1.0;
host_b[i] = 2.0;
}
cudaMemcpy(a,host_a,Nbytes,
cudaMemcpyHostToDevice);
cudaMemcpy(b,host_b,Nbytes,
cudaMemcpyHostToDevice);
add<<< 1, 1>>>(a, x, b, y, c);
cudaMemcpy(host_c,c,Nbytes,
cudaMemcpyDeviceToHost);
cudaFree(a);
cudaFree(b);
cudaFree(c);
free(host_a);
free(host_b);
free(host_c);
return 0;
}
GPUプログラム
GPGPU実践基礎工学
vectoradd_copy_twoway.cu
27 2015/11/18
- 28. CUDAでカーネルを作成するときの制限
GPGPU実践基礎工学28
x,yはCPU側のメモリに存在
値渡し
CPU→GPUへ値がコピーされる
host_a,host_b,host_c
もCPU側のメモリに存在
ポインタ渡し(変数のアドレス
を渡す)
GPUは渡されたメモリアドレス
が分かってもCPUのメモリに
アクセスできない
__global__ void add(float *a, float x,
float *b, float y, float *c){
for(int i=0; i<N; i++)
c[i] = x*a[i] + y*b[i];
}
int main(void){
float *a,*b,*c;
float *host_a,host_b,host_c;
float x=1.0, y=2.0;
:
add<<< 1, 1>>>(a, x, b, y, c);
//add<<< 1, 1>>>(host_a, x,
host_b, y,host_c);
:
}
2015/11/18
- 32. カーネルの書き換え
1スレッドが実行する処理になるよう変更
1スレッドがある添字 i の要素を担当
#define N (8)
#define Nbytes (N*sizeof(float))
__global__ void init(float *a, float *b, float *c){
int i=...;
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
__global__ void add(float *a, float *b, float *c){
int i=...;
c[i] = a[i] + b[i];
}
GPGPU実践基礎工学32
1スレッドがあるiの担当となり,変数
の初期化と足し算の計算を実行
2015/11/18
- 36. Hello Threads(Fermi世代以降)
<<<,>>>内の数字で表示される内容が変化
2015/11/18GPGPU実践基礎工学36
#include<stdio.h>
__global__ void hello(){
printf("gridDim.x=%d, blockIdx.x=%d,
blockDim.x=%d, threadIdx.x=%d¥n",
gridDim.x, blockIdx.x, blockDim.x, threadIdx.x);
}
int main(void){
hello<<<2,4>>>();
cudaDeviceSynchronize();
return 0;
}
<<<,>>>内の数字を変えると画面表
示される内容が変わる
<<<,>>>内の数字とどのパラメータが
対応しているかを確認
・・・
- 41. 各スレッドが異なるiを参照するには
N=8, <<<4, 2>>>で実行
c[i]
a[i]
b[i]
+ + + + + + + +
gridDim.x=4
blockIdx.x=0
blockDim.x=2threadIdx.x=
0 1 0 1 0 1 0 1
2015/11/18GPGPU実践基礎工学41
blockIdx.x=1
blockDim.x=2
blockIdx.x=2
blockDim.x=2
blockIdx.x=3
blockDim.x=2
= blockIdx.x*blockDim.x + threadIdx.x
i= 0 1 2 3 4 5 6 7
- 42. カーネルの書き換え
1スレッドが実行する処理になるよう変更
1スレッドがある添字 i の要素を担当
#define N (8)
#define Nbytes (N*sizeof(float))
__global__ void init(float *a, float *b, float *c){
int i=blockIdx.x*blockDim.x + threadIdx.x;
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
__global__ void add(float *a, float *b, float *c){
int i=blockIdx.x*blockDim.x + threadIdx.x;
c[i] = a[i] + b[i];
}
GPGPU実践基礎工学42 2015/11/18
- 43. #define N (1024*1024)
#define Nbytes (N*sizeof(float))
__global__ void init(float *a,
float *b, float *c){
int i = blockIdx.x*blockDim.x
+ threadIdx.x;
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
__global__ void add(float *a,
float *b, float *c){
int i = blockIdx.x*blockDim.x
+ threadIdx.x;
c[i] = a[i] + b[i];
}
int main(void){
float *a,*b,*c;
cudaMalloc((void **)&a, Nbytes);
cudaMalloc((void **)&b, Nbytes);
cudaMalloc((void **)&c, Nbytes);
init<<< N/256, 256>>>(a,b,c);
add<<< N/256, 256>>>(a,b,c);
cudaFree(a);
cudaFree(b);
cudaFree(c);
return 0;
}
GPUで並列実行するプログラム
GPGPU実践基礎工学
vectoradd.cu
43 2015/11/18
- 44. 処理時間の比較
配列の要素数 N=220
1ブロックあたりのスレッド数 256
GPUはマルチスレッドで処理しないと遅い
GPUを使えばどのような問題でも速くなるわけではない
並列に処理できるようプログラムを作成する必要がある
implementation
Processing time [ms]
init add
CPU (1 Thread) 4.15 4.55
GPU (1 Thread) 201 206
GPU (256 Threads) 0.108 0.112
GPGPU実践基礎工学44 2015/11/18
- 45. 各階層の値の設定
設定の条件
GPUの世代によって設定できる上限値が変化
確認の方法
pgaccelinfo
deviceQuery
GPU Computing SDKに含まれているサンプル
CUDA Programming Guide
https://docs.nvidia.com/cuda/cuda‐c‐programming‐
guide/#compute‐capabilities
階層の値によって実行時の性能が変化
GPUの一番基本的なチューニング
2015/11/18GPGPU実践基礎工学45
- 47. pgaccelinfo実行結果
Revision Number: 2.0
Global Memory Size: 2817982464
Warp Size: 32
Maximum Threads per Block: 1024
Maximum Block Dimensions: 1024, 1024, 64
Maximum Grid Dimensions: 65535 x 65535 x 65535
GPUの世代
(どのような機能を有しているか)
実
行
時
の
パ
ラ
メ
ー
タ
選
択
の
際
に
重
要
各方向の最大値
1ブロックあたりのスレッド数は最大1024
(1024, 1, 1), (1, 1024, 1)
(32, 32, 1), (4, 4, 64)など
2015/11/18GPGPU実践基礎工学47
- 48. #define N (1024*1024)
#define NT (256) //この数字を変更
#define NB (N/NT)
#define Nbytes (N*sizeof(float))
__global__ void init(float *a,
float *b, float *c){
int i = blockIdx.x*blockDim.x
+ threadIdx.x;
a[i] = 1.0;
b[i] = 2.0;
c[i] = 0.0;
}
__global__ void add(float *a,
float *b, float *c){
int i = blockIdx.x*blockDim.x
+ threadIdx.x;
c[i] = a[i] + b[i];
}
int main(void){
float *a,*b,*c;
cudaMalloc((void **)&a, Nbytes);
cudaMalloc((void **)&b, Nbytes);
cudaMalloc((void **)&c, Nbytes);
init<<< NB, NT>>>(a,b,c);
add<<< NB, NT>>>(a,b,c);
cudaFree(a);
cudaFree(b);
cudaFree(c);
return 0;
}
並列度の変更によるチューニング
GPGPU実践基礎工学48
#defineでNB,NTを定義,変更して実行
vectoradd_param.cu
2015/11/18