• 検索結果がありません。

N 体問題 長岡技術科学大学電気電子情報工学専攻出川智啓

N/A
N/A
Protected

Academic year: 2021

シェア "N 体問題 長岡技術科学大学電気電子情報工学専攻出川智啓"

Copied!
58
0
0

読み込み中.... (全文を見る)

全文

(1)

N体問題

(2)

今回の内容

天体の運動方程式

天体運動のGPU実装

最適化による性能変化

(3)

計算の種類

画像処理,差分法

空間に固定された観測点を配置

観測点上で物理量がどのように

変化するかを追跡

Euler型

多粒子の運動

観測点を配置せず,観測点が粒

子と共に移動

Lagrange型

観測点

(固定)

観測点

(粒子と共に移動)

(4)

N体問題

万有引力によって運動する天体群のシミュレーション

天体を質点と考え,衝突を無視

天体は自身以外の天体から受ける万有引力のみで運動

天体

iの加速度

b

N

i

j

j

ji

ji

j

i

m

,

1

3

r

r

g

a

r

ji

: 2天体

j, iの距離

g : 重力加速度

m

j

: 天体の質量

N

b

: 天体の総数

(5)

時間微分の離散化

天体

iの位置rと速度v

時間微分の離散化

テイラー展開を利用

i

i

dt

d

v

r 

i

i

dt

d

a

v 

2 22 3 33

!

3

!

2

)

(

)

(

dt

d

Δt

dt

d

Δt

dt

d

Δt

t

Δt

t

r

r

r

r

r

v

r

r

r

r

r

2 22 3 33

!

3

!

2

1

)

(

)

(

dt

d

Δt

dt

d

Δt

Δt

Δt

t

Δt

t

dt

d

(6)

時間微分の離散化

離散時刻を上付き添字

nで表現

位置

r,速度vの時間発展

時刻

nでの天体位置r,速度vが既知

加速度

a

n

を求めることで時刻

n+1の天体位置を予測

n

t

r

r

(

)

1

)

(

t

Δt

r

n

r

Δt

n

i

n

i

n

i

r

v

r

1

Δt

n

i

n

i

n

i

v

a

v

1

(7)

プログラムの流れ

プログラムは2重ループ

全ペア相互作用(all pair interaction)

全ての天体が全ての天体のデータを利用

一度読み込んだデータの再利用が重要

計算量は天体個数の2乗に比例

for 全ての天体について{

for 全ての天体について{

天体間の距離を計算

if(同じ天体でなければ){

万有引力を計算

加速度aの値を更新

}

}

}    

(8)

プログラムの流れ

プログラムは2重ループ

全ペア相互作用(all pair interaction)

全ての天体が全ての天体のデータを利用

一度読み込んだデータの再利用が重要

計算量は天体個数の2乗に比例

for 全ての天体について{

for 全ての天体について{

天体間の距離を計算

if(同じ天体でなければ){

万有引力を計算

加速度aの値を更新

}

}

}    

(9)

プログラムの流れ

プログラムは2重ループ

全ペア相互作用(all pair interaction)

全ての天体が全ての天体のデータを利用

一度読み込んだデータの再利用が重要

計算量は天体個数の2乗に比例

for 全ての天体について{

for 全ての天体について{

天体間の距離を計算

if(同じ天体でなければ){

万有引力を計算

加速度aの値を更新

}

}

}    

(10)

プログラムの流れ

プログラムは2重ループ

全ペア相互作用(all pair interaction)

全ての天体が全ての天体のデータを利用

一度読み込んだデータの再利用が重要

計算量は天体個数の2乗に比例

for 全ての天体について{

for 全ての天体について{

天体間の距離を計算

if(同じ天体でなければ){

万有引力を計算

加速度aの値を更新

}

}

}    

(11)

プログラムの流れ

プログラムは2重ループ

全ペア相互作用(all pair interaction)

全ての天体が全ての天体のデータを利用

一度読み込んだデータの再利用が重要

計算量は天体個数の2乗に比例

for 全ての天体について{

for 全ての天体について{

天体間の距離を計算

if(同じ天体でなければ){

万有引力を計算

加速度aの値を更新

}

}

}    

(12)

プログラムの流れ

万有引力は同一天体には影響しない

同一天体間の万有引力の計算は不可能(ゼロ除算)

ifで区別

if文を排除し,ゼロ除算を回避するため,微小値を付加

: 軟化因子

同一天体なら分子が0となるので計算結果に影響しない

b

N

i

j

j

ji

ji

j

n

i

m

,

1

2

/

3

2

2

r

r

g

a

(13)

//重力加速度が1になるように規格化 #include<stdio.h> #include<stdlib.h> #include<math.h> #define N      (4096) #define dt 0.001 #define Soften (1e‐6) //プロトタイプ宣言 void initial(…); void kernel(…); void integrate(…); int main(void){ float *x,*y,*z,*m; float *vx,*vy,*vz; float *ax,*ay,*az; x = (float *)malloc(N*sizeof(float)); y = (float *)malloc(N*sizeof(float)); z = (float *)malloc(N*sizeof(float)); m = (float *)malloc(N*sizeof(float)); vx = (float *)malloc(N*sizeof(float)); vy = (float *)malloc(N*sizeof(float)); vz = (float *)malloc(N*sizeof(float)); ax = (float *)malloc(N*sizeof(float)); ay = (float *)malloc(N*sizeof(float)); az = (float *)malloc(N*sizeof(float)); //初期値設定 initial(x,y,z,vx,vy,vz,m); //for(){ //本来なら必要な回数だけ繰り返す //加速度の計算 kernel(x,y,z,vx,vy,vz,ax,ay,az,m); //時間積分 integrate(x,y,z,vx,vy,vz,ax,ay,az); //} return 0; }

CPUプログラム

nbody.c

(14)

//初期値の設定

void initial(float *x,float *y,float *z,float *vx,float *vy,float *vz,float *m){ int i; //乱数で配置を決定 //x,y座標,x,y方向速度が‐1~1の範囲に収まるように決定 srand(N);  for(i=0;i<N;i++){ x[i] = (float)rand()/RAND_MAX*2.0 ‐ 1.0; y[i] = (float)rand()/RAND_MAX*2.0 ‐ 1.0; z[i] = 0.0f; m[i] = 1.0f; vx[i] = (float)rand()/RAND_MAX*2.0 ‐ 1.0; vy[i] = (float)rand()/RAND_MAX*2.0 ‐ 1.0; vz[i] = 0.0f; } }

CPUプログラム

nbody.c

(15)

//時間積分 void integrate(float *x, float *y, float *z, float *vx, float *vy, float *vz, float *ax, float *ay, float *az){ int i; //Euler法で位置と速度を積分 //必ず位置の積分を先に実行 for(i=0;i<N;i++){ x[i] =  x[i] + dt*vx[i]; y[i] =  y[i] + dt*vy[i]; z[i] =  z[i] + dt*vz[i]; vx[i] = vx[i] + dt*ax[i]; vy[i] = vy[i] + dt*ay[i]; vz[i] = vz[i] + dt*az[i]; } }

CPUプログラム

nbody.c

(16)

//加速度の計算 void kernel(float *x, float *y, float *z, float *vx, float *vy, float *vz, float *ax, float *ay, float *az, float *m){ int i,j; float rx,ry,rz; float dist2, dist6, invDist3,s; for(i=0;i<N;i++){ ax[i] = 0.0f; ay[i] = 0.0f; az[i] = 0.0f; } for(i=0;i<N;i++){ for(j=0;j<N;j++){ //if(i==j)continue; rx=x[j]‐x[i];  ry=y[j]‐y[i]; rz=z[j]‐z[i]; //2天体間の距離を計算 dist2 = rx*rx + ry*ry + rz*rz + Soften;//軟化パラメータ // m/r^3 の計算 dist6 = dist2*dist2*dist2; invDist3 = 1.0/sqrt(dist6); s = m[j]*invDist3; //天体jによる加速度を加算 ax[i] = ax[i] + rx*s; ay[i] = ay[i] + ry*s; az[i] = az[i] + rz*s; } } }

CPUプログラム

nbody.c

(17)

#include<stdio.h> #include<stdlib.h> #include<math.h> #define N      (64*64) #define dt 0.001 #define Soften (1e‐6) #include "kernel0.cu"//カーネルを切替 int main(void){ //GPUのメモリ上に確保 float *x,*y,*z,*m; float *vx,*vy,*vz; float *ax,*ay,*az; //CPUのメモリ上に確保 初期設定用 float *host_x,*host_y,*host_z,*host_m; float *host_vx,*host_vy,*host_vz; cudaMalloc((void **)&x, (N*sizeof(float))); cudaMalloc((void **)&y, (N*sizeof(float))); cudaMalloc((void **)&z, (N*sizeof(float))); cudaMalloc((void **)&m, (N*sizeof(float))); cudaMalloc((void **)&vx, (N*sizeof(float))); cudaMalloc((void **)&vy, (N*sizeof(float))); cudaMalloc((void **)&vz, (N*sizeof(float))); cudaMalloc((void **)&ax, (N*sizeof(float))); cudaMalloc((void **)&ay, (N*sizeof(float))); cudaMalloc((void **)&az, (N*sizeof(float))); host_x = (float *)malloc(N*sizeof(float)); //以下,host_y等も確保 //初期設定はCPUと同じ initial(host_x,host_y,host_z, host_vx,host_vy,host_vz,host_m); cudaMemcpy(x, host_x, N*sizeof(float),  cudaMemcpyHostToDevice); //以下,host_y等もGPUへコピー

GPUプログラム(1スレッド版)

nbody.cu

(18)

//for(){ //本来は必要な回数だけ繰り返す kernel<<<NB,NT>>> (x,y,z,vx,vy,vz,ax,ay,az,m); integrate<<<NB,NT>>> (x,y,z,vx,vy,vz,ax,ay,az); //必要な結果をCPUへコピー //} free(host_x); free(host_y); free(host_z); free(host_m); free(host_vx); free(host_vy); free(host_vz); cudaFree(x); cudaFree(y); cudaFree(z); cudaFree(m); cudaFree(vx); cudaFree(vy); cudaFree(vz); cudaFree(ax); cudaFree(ay); cudaFree(az); return 0; }

GPUプログラム(1スレッド版)

nbody.cu

(19)

#define NT 1 #define NB 1 //加速度の計算 __global__ void kernel(float *x,float *y, float *z,float *vx, float *vy, float *vz,float *ax, float *ay, float *az,float *m){ int i,j; float rx,ry,rz; float dist2, dist6, invDist3,s; for(i=0;i<N;i++){ ax[i] = 0.0f; ay[i] = 0.0f; az[i] = 0.0f; } for(i=0;i<N;i++){ for(j=0;j<N;j++){ if(i==j)continue; rx=x[j]‐x[i];  ry=y[j]‐y[i]; rz=z[j]‐z[i]; //2天体間の距離を計算 dist2 = rx*rx + ry*ry + rz*rz; // m/r^3 の計算 dist6 = dist2*dist2*dist2; invDist3 = 1.0/sqrt(dist6); s = m[j]*invDist3; //天体jによる加速度を加算 ax[i] = ax[i] + rx*s; ay[i] = ay[i] + ry*s; az[i] = az[i] + rz*s; } } }

GPUプログラム(1スレッド版)

kernel0.cu

(20)

//時間積分 __global__ void integrate(float *x, float *y, float *z, float *vx, float *vy, float *vz, float *ax, float *ay, float *az){ int i; for(i=0;i<N;i++){ x[i] =  x[i] + dt*vx[i]; y[i] =  y[i] + dt*vy[i]; z[i] =  z[i] + dt*vz[i]; vx[i] = vx[i] + dt*ax[i]; vy[i] = vy[i] + dt*ay[i]; vz[i] = vz[i] + dt*az[i]; } }

GPUプログラム(1スレッド版)

kernel0.cu

(21)

実行時間

天体の個数 N = 4096

カーネル

実行時間 [ms]

(22)

#define NT 1 #define NB 1 //加速度の計算 __global__ void kernel(float *x,float *y, float *z,float *vx, float *vy, float *vz,float *ax, float *ay, float *az,float *m){ int i,j; float rx,ry,rz; float dist2, dist6, invDist3,s; for(i=0;i<N;i++){ ax[i] = 0.0f; ay[i] = 0.0f; az[i] = 0.0f; } for(i=0;i<N;i++){ for(j=0;j<N;j++){ rx=x[j]‐x[i];  ry=y[j]‐y[i]; rz=z[j]‐z[i]; //2天体間の距離を計算 dist2 = rx*rx + ry*ry + rz*rz +Soften; // m/r^3 の計算 dist6 = dist2*dist2*dist2; invDist3 = 1.0/sqrt(dist6); s = m[j]*invDist3; //天体jによる加速度を加算 ax[i] = ax[i] + rx*s; ay[i] = ay[i] + ry*s; az[i] = az[i] + rz*s; } } }

GPUプログラム(1スレッド版,if消去)

kernel1.cu

(23)

実行時間

天体の個数 N = 4096

カーネル

実行時間 [ms]

1スレッド実行

33×10

3

(24)

1スレッドが天体一つの加速度を計算

天体のデータを1次元配列で保持

加速度を求めたい天体iのforループ

相互作用の計算のために参照される天体jのループ

x[i]

x[j]

加速度を求めたい

天体

相互作用の計算の

ために参照される

天体

・・・

(25)

GPUによる並列処理の方針

ベクトル和と本質的には同じ

・・・

・・・

・・・

c[i]

a[i]

b[i]

for(i=0;i<N;i++){

c[i]=a[i]+b[i];

}

(26)

GPUによる並列処理の方針

1スレッドが一つの配列添字を計算

・・・

・・・

・・・

c[i]

a[i]

b[i]

i=blockIdx.x*blockDim.x+threadIdx.x;

c[i]=a[i]+b[i];

(27)

GPUによる並列処理の方針

加速度の計算

・・・

x[j]

for(i=0;i<N;i++){

for(j=0;j<N;j++){

加速度を積算

}

}

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

jのループ

(28)

GPUによる並列処理の方針

加速度の計算

・・・

x[j]

for(i=0;i<N;i++){

for(j=0;j<N;j++){

加速度を積算

}

}

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

jのループ

(29)

GPUによる並列処理の方針

加速度の計算

・・・

x[j]

for(i=0;i<N;i++){

for(j=0;j<N;j++){

加速度を積算

}

}

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

jのループ

(30)

GPUによる並列処理の方針

加速度の計算

・・・

x[j]

for(i=0;i<N;i++){

for(j=0;j<N;j++){

加速度を積算

}

}

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

jのループ

(31)

GPUによる並列処理の方針

加速度の計算

・・・

x[j]

for(i=0;i<N;i++){

for(j=0;j<N;j++){

加速度を積算

}

}

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

jのループ

(32)

GPUによる並列処理の方針

加速度の計算

・・・

x[j]

for(i=0;i<N;i++){

for(j=0;j<N;j++){

加速度を積算

}

}

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

jのループ

(33)

GPUによる並列処理の方針

ベクトル和と同様に1スレッドが一つの天体を計算

i=blockIdx.x*blockDim.x+threadIdx.x;

for(j=0;j<N;j++){

加速度を積算

}

・・・

x[j]

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

(34)

GPUによる並列処理の方針

ベクトル和と同様に1スレッドが一つの天体を計算

i=blockIdx.x*blockDim.x+threadIdx.x;

for(j=0;j<N;j++){

加速度を積算

}

・・・

x[j]

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

(35)

GPUによる並列処理の方針

ベクトル和と同様に1スレッドが一つの天体を計算

i=blockIdx.x*blockDim.x+threadIdx.x;

for(j=0;j<N;j++){

加速度を積算

}

・・・

x[j]

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

(36)

GPUによる並列処理の方針

ベクトル和と同様に1スレッドが一つの天体を計算

i=blockIdx.x*blockDim.x+threadIdx.x;

for(j=0;j<N;j++){

加速度を積算

}

・・・

x[j]

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

(37)

GPUによる並列処理の方針

ベクトル和と同様に1スレッドが一つの天体を計算

i=blockIdx.x*blockDim.x+threadIdx.x;

for(j=0;j<N;j++){

加速度を積算

}

・・・

x[j]

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

(38)

GPUによる並列処理の方針

ベクトル和と同様に1スレッドが一つの天体を計算

i=blockIdx.x*blockDim.x+threadIdx.x;

for(j=0;j<N;j++){

加速度を積算

}

・・・

x[j]

・・・

x[i]

加速度を求めたい

天体

相互作用の計算の

ために参照される

(39)

#define NT 256 #define NB (N/NT) //加速度の計算 __global__ void kernel(float *x,float *y, float *z,float *vx, float *vy, float *vz,float *ax, float *ay, float *az,float *m){ int i,j; float rx,ry,rz; float dist2, dist6, invDist3,s; i = blockDim.x*blockIdx.x+threadIdx.x; for(j=0;j<N;j++){ rx=x[j]‐x[i];  ry=y[j]‐y[i]; rz=z[j]‐z[i]; //2天体間の距離を計算 dist2 = rx*rx + ry*ry + rz*rz + Soften;//軟化パラメータ // m/r^3 の計算 dist6 = dist2*dist2*dist2; invDist3 = 1.0/sqrt(dist6); s = m[j]*invDist3; //天体jによる加速度を加算 ax[i] = ax[i] + rx*s; ay[i] = ay[i] + ry*s; az[i] = az[i] + rz*s; } }

GPUプログラム(1スレッドが天体一つを計算)

kernel2.cu

(40)

//時間積分

__global__ void integrate(float *x, float *y, float *z,

float *vx, float *vy, float *vz, float *ax, float *ay, float *az){

int i=blockIdx.x*blockDim.x + threadIdx.x;

x[i] =  x[i] + dt*vx[i]; y[i] =  y[i] + dt*vy[i]; z[i] =  z[i] + dt*vz[i]; vx[i] = vx[i] + dt*ax[i]; vy[i] = vy[i] + dt*ay[i]; vz[i] = vz[i] + dt*az[i]; }

GPUプログラム(1スレッドが天体一つを計算)

kernel2.cu

(41)

実行時間

天体の個数 N = 4096

スレッド数

NT = 256

カーネル

実行時間 [ms]

1スレッド実行

33×10

3

1スレッド実行(ifの消去)

29×10

3

1スレッド1天体

7.63

(42)

#define NT 256 #define NB (N/NT) //加速度の計算 __global__ void kernel(float *x,float *y, float *z,float *vx, float *vy, float *vz,float *ax, float *ay, float *az,float *m){ int i,j; float rx,ry,rz; float dist2, dist6, invDist3,s; //加速度のデータをレジスタに置く float r_ax, r_ay, r_az; i = blockDim.x*blockIdx.x+threadIdx.x;

r_ax = r_ay = r_az = 0.0f; for(j=0;j<N;j++){ rx=x[j]‐x[i];  ry=y[j]‐y[i]; rz=z[j]‐z[i]; //2天体間の距離を計算 dist2 = rx*rx + ry*ry + rz*rz + Soften;//軟化パラメータ // m/r^3 の計算 dist6 = dist2*dist2*dist2; invDist3 = 1.0/sqrt(dist6); s = m[j]*invDist3; //天体jによる加速度を加算 r_ax = r_ax + rx*s; r_ay = r_ay + ry*s; r_az = r_az + rz*s; } ax[i] = r_ax; ay[i] = r_ay; az[i] = r_az; }

GPUプログラム(レジスタ利用)

kernel3.cu

(43)

実行時間

天体の個数 N = 4096

スレッド数

NT = 256

カーネル

実行時間 [ms]

1スレッド実行

33×10

3

1スレッド実行(ifの消去)

29×10

3

1スレッド1天体

7.63

レジスタ利用

4.49

(44)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=   0    1   2    3   4    5   6    7

threadIdx.x=   0    1   2    3   0    1   2    3

x[0] x[1] x[2] x[3]   x[0] x[1] x[2] x[3]

j=   0    1   2    3   4    5   6    7

0+threadIdx.x

0+threadIdx.x

(45)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=0~3の天体で

加速度を計算

i=4~7の天体と

j=0~3の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

x[0] x[1] x[2] x[3]   x[0] x[1] x[2] x[3]

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

(46)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=0~3の天体で

加速度を計算

i=4~7の天体と

j=0~3の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

x[0] x[1] x[2] x[3]   x[0] x[1] x[2] x[3]

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

(47)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=0~3の天体で

加速度を計算

i=4~7の天体と

j=0~3の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

x[0] x[1] x[2] x[3]   x[0] x[1] x[2] x[3]

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

(48)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=0~3の天体で

加速度を計算

i=4~7の天体と

j=0~3の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

x[0] x[1] x[2] x[3]   x[0] x[1] x[2] x[3]

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

(49)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=   0    1   2    3   4    5   6    7

threadIdx.x=   0    1   2    3   0    1   2    3

x[4] x[5] x[6] x[7]   x[4] x[5] x[6] x[7]

j=   0    1   2    3   4    5   6    7

4(=NT)+threadIdx.x

4(=NT)+threadIdx.x

(50)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=4~7の天体で

加速度を計算

i=4~7の天体と

j=4~7の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

x[4] x[5] x[6] x[7]   x[4] x[5] x[6] x[7]

(51)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=4~7の天体で

加速度を計算

i=4~7の天体と

j=4~7の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

x[4] x[5] x[6] x[7]   x[4] x[5] x[6] x[7]

(52)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=4~7の天体で

加速度を計算

i=4~7の天体と

j=4~7の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

x[4] x[5] x[6] x[7]   x[4] x[5] x[6] x[7]

(53)

GPUプログラム(共有メモリによる再利用)

x[i]

x[j]

・・・

共有メモリ

blockIdx.x=0

blockIdx.x=1

i=0~3の天体と

j=4~7の天体で

加速度を計算

i=4~7の天体と

j=4~7の天体で

加速度を計算

threadIdx.x=   0    1   2    3   0    1   2    3

j=   0    1   2    3   4    5   6    7

i=   0    1   2    3   4    5   6    7

x[4] x[5] x[6] x[7]   x[4] x[5] x[6] x[7]

(54)

#define NT 256 #define NB (N/NT) //加速度の計算 __global__ void kernel(…){ int i,j; float rx,ry,rz; float dist2, dist6, invDist3,s; //加速度と座標のデータをレジスタに置く float r_ax,r_ay,r_az,r_x,r_y,r_z; __shared__ float  s_x[NT],s_y[NT],s_z[NT],s_m[NT]; i = blockDim.x*blockIdx.x+threadIdx.x; r_ax = r_ay = r_az = 0.0f;

r_x = x[i]; r_y = y[i]; r_z = z[i]; for(j=0;j<N;j+=NT){ s_x[threadIdx.x] = x[j+threadIdx.x]; s_y[threadIdx.x] = y[j+threadIdx.x]; s_z[threadIdx.x] = z[j+threadIdx.x]; s_m[threadIdx.x] = m[j+threadIdx.x]; __syncthreads(); for(js = 0;js<NT;js++){ rx=s_x[js]‐r_x; ry=s_y[js]‐r_y; rz=s_z[js]‐r_z; //2天体間の距離を計算 dist2 = rx*rx + ry*ry + rz*rz + Soften;//軟化パラメータ // m/r^3 の計算 dist6 = dist2*dist2*dist2; invDist3 = 1.0/sqrt(dist6); s = s_m[js]*invDist3; //天体jによる加速度を加算 r_ax = r_ax + rx*s; r_ay = r_ay + ry*s; r_az = r_az + rz*s; } } ax[i] = r_ax; ay[i] = r_ay; az[i] = r_az; }

GPUプログラム(共有メモリによる再利用)

kernel4.cu

(55)

実行時間

天体の個数 N = 4096

スレッド数

NT = 256

カーネル

実行時間 [ms]

1スレッド実行

33×10

3

1スレッド実行(ifの消去)

29×10

3

1スレッド1天体

7.63

レジスタ利用

4.49

共有メモリ利用

4.27

(56)

#define NT 256 #define NB (N/NT) //加速度の計算 __global__ void kernel(…){ int i,j; float rx,ry,rz; float dist2, dist6, invDist3,s; //加速度と座標のデータをレジスタに置く float r_ax,r_ay,r_az,r_x,r_y,r_z; __shared__ float  s_x[NT],s_y[NT],s_z[NT],s_m[NT]; i = blockDim.x*blockIdx.x+threadIdx.x; r_ax = r_ay = r_az = 0.0f;

r_x = x[i]; r_y = y[i]; r_z = z[i]; for(j=0;j<N;j+=NT){ s_x[threadIdx.x] = x[j+threadIdx.x]; s_y[threadIdx.x] = y[j+threadIdx.x]; s_z[threadIdx.x] = z[j+threadIdx.x]; s_m[threadIdx.x] = m[j+threadIdx.x]; #pragma unroll for(js = 0;js<NT;js++){ rx=s_x[js]‐r_x; ry=s_y[js]‐r_y; rz=s_z[js]‐r_z; //2天体間の距離を計算 dist2 = rx*rx + ry*ry + rz*rz + Soften;//軟化パラメータ // m/r^3 の計算 dist6 = dist2*dist2*dist2; invDist3 = 1.0/sqrt(dist6); s = s_m[js]*invDist3; //天体jによる加速度を加算 r_ax = r_ax + rx*s; r_ay = r_ay + ry*s; r_az = r_az + rz*s; } } ax[i] = r_ax; ay[i] = r_ay; az[i] = r_az; }

GPUプログラム(ループアンロール)

kernel5.cu

(57)

実行時間

天体の個数 N = 4096

スレッド数

NT = 256

カーネル

実行時間 [ms]

1スレッド実行

33×10

3

1スレッド実行(ifの消去)

29×10

3

1スレッド1天体

7.63

レジスタ利用

4.49

共有メモリ利用

4.27

共有メモリ利用+ループアンロール

3.50

(58)

実行時間

天体の個数 N = 65536

スレッド数

NT = 256

共有メモリを単純に利用しただけでは遅くなる

共有メモリを利用することは高速化に有効

「共有メモリを利用するために追加される処理」が遅くなる要因

カーネル

実行時間 [ms]

1スレッド1天体

916

レジスタ利用

638

共有メモリ利用

646

共有メモリ利用+ループアンロール

499

参照

関連したドキュメント

関東総合通信局 東京電機大学 工学部電気電子工学科 電気通信システム 昭和62年3月以降

After that, applying the well-known results for elliptic boundary-value problems (without parameter) in the considered domains, we receive the asymptotic formu- las of the solutions

In the second section, we study the continuity of the functions f p (for the definition of this function see the abstract) when (X, f ) is a dynamical system in which X is a

Algebraic curvature tensor satisfying the condition of type (1.2) If ∇J ̸= 0, the anti-K¨ ahler condition (1.2) does not hold.. Yet, for any almost anti-Hermitian manifold there

F rom the point of view of analysis of turbulent kineti energy models the result.. presented in this paper an be onsidered as a natural ontinuation of

In Section 3 we collect and prove the remaining facts, which we need to show that (X, Φ) 7→ ⊕ i,j H Φ i (X, WΩ j X ) is a weak cohomology theory with supports in the sense of

 当図書室は、専門図書館として数学、応用数学、計算機科学、理論物理学の分野の文

物質工学課程 ⚕名 電気電子応用工学課程 ⚓名 情報工学課程 ⚕名 知能・機械工学課程