121
4GPUのメモリ階層の詳細 (共有メモリ) 長岡技術科学大学 電気電子情報工学専攻 出川智啓

2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

  • Upload
    -

  • View
    208

  • Download
    2

Embed Size (px)

Citation preview

Page 1: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

第4回 GPUのメモリ階層の詳細(共有メモリ)

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

Page 2: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

今回の内容

2015/05/07先端GPGPUシミュレーション工学特論2

GPUのメモリ

グローバルメモリ

共有メモリ バンクコンフリクト

共有メモリを利用した配列の転置

Page 3: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

GPU(Graphics Processing Unit)とは

画像処理専用のハードウェア 具体的には画像処理用のチップ

チップ単体では販売されていない

PCI‐Exカードで販売 チップ単体と区別せずにGPUと呼ぶことも多い

ノートPCに搭載

PCI‐Exカードとして販売されるGPUには,ビデオメモリと呼ばれるRAMが搭載

2015/05/07先端GPGPUシミュレーション工学特論3

Page 4: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

GPUの主要部品

2015/05/07先端GPGPUシミュレーション工学特論4

基盤

画面出力端子

電源入力端子

GPU(チップ)+冷却部品

メモリ

このメモリの特性の把握が重要

http://www.geforce.com/whats‐new/articles /introducing‐the‐geforce‐gtx‐780に公開されている写真を基に作成

画面出力端子

PCI‐Ex端子

電源入力端子

メモリ

チップ

Page 5: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

メモリの階層

2015/05/07先端GPGPUシミュレーション工学特論5

オフチップメモリ GPUのチップ外部に置かれたメモリ

基板上に実装

ビデオメモリ(数GB)

オンチップメモリ GPUのチップ内部に置かれたメモリ

レジスタ

レベル1(L1)キャッシュ

レベル2(L2)キャッシュ

高速,容量小

低速,容量大

CPUの構造に類似

Page 6: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

メモリの階層

2015/05/07先端GPGPUシミュレーション工学特論6

CPUのメモリ階層に類似

CPUのメモリ階層 オフチップ メインメモリ

オンチップ レジスタ,L1,L2(,L3)キャッシュ

GPUメモリの独自の特徴 GPUのチップから読み書き可能か

CPUから読み書き可能か

Page 7: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

メモリの階層

2015/05/07先端GPGPUシミュレーション工学特論7

CPUのメモリ階層 コアごとにL2キャッシュ,全体でL3キャッシュを持つこともある

メインメモリ

L2キャッシュ

L1キャッシュ L1キャッシュ L1キャッシュ

コア

レジスタ レジスタ

コア

レジスタ レジスタ

・・・

・・・

チップ

コア

レジスタ レジスタ

Page 8: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

メモリの階層

2015/05/07先端GPGPUシミュレーション工学特論8

GPUのメモリ階層 CPUにはない独自のメモリを複数持つ

グローバルメモリ

L2キャッシュ

L1キャッシュ 共有メモリ

コア

レジスタ

チップ

テクスチャメモリ

コンスタントメモリ

ローカルメモリ

テクスチャキャッシュ

コンスタントキャッシュ

Page 9: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

メモリの種類

オンチップメモリ(GPUのチップ内部のメモリ) 高速アクセス,小容量

CPUからはアクセス不可

L1キャッシュと共有メモリは一定サイズを共用

2015/05/07先端GPGPUシミュレーション工学特論9

L1キャッシュ/共有(シェアード)メモリ

レジスタ

容量 小 小

速度 高速 高速

GPUからの読み書き

読み書き可ブロック内の全スレッドが同じメモリにアクセス(データを共有する)ことが可

能*

読み書き可各スレッドが異なるレジスタ

にアクセス

CPUからのアクセス

読み書き不可 読み書き不可

*同じメモリ,異

なるメモリについては後ろのスライドで説明

Page 10: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

メモリの種類

オフチップメモリ(GPUのチップ外部のメモリ) 低速アクセス,大容量

CPUから直接アクセス可能

ローカルメモリだけはアクセス不可

2015/05/07先端GPGPUシミュレーション工学特論10

グローバルメモリ ローカルメモリ テクスチャメモリ コンスタントメモリ

容量 大 小 大 小

速度 低速 低速 高速*1 高速*1

GPUからの読み書き

読み書き可全てのスレッドが同じメモリにアクセス可能*2

読み書き可各スレッドが異なるメモリにアクセス*2

読み込み可全てのスレッドが同じメモリにアクセス可能*2

読み込み可全てのスレッドが同じメモリにアクセス*2

CPUからのアクセス

読み書き可 読み書き不可 読み書き可 読み書き可

*1キャッシュが効く場合*2同じメモリ,異なるメモリについては後ろのスライドで説明

Page 11: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

同じメモリ

2015/05/07先端GPGPUシミュレーション工学特論11

複数のスレッドがメモリアドレスを共有 複数のスレッドが変数を共有

他のスレッドが書き込んだデータを読むことが可能

共有できるスレッドの範囲はメモリの種類によって変化

//a,b[]がグローバルメモリに確保されている場合*1

__global__ void kernel(...){int i = blockIdx.x*blockDim.x + threadIdx.x;:

b[i] = i; //スレッドiが配列要素b[i]に自身のスレッド番号を代入//b[0,1,...,i‐1,i,...]の値は0,1,...,i‐1,i,...

a = b[i‐1];*2 //スレッドi‐1が書き込んだ値を読み*3,aに代入:          // 後に書き込まれたaの値を全スレッドが共有

} *1 あくまで動作のイメージを説明するための例で正しく実行できない*2 iが0の場合は考えない*3 配列bを全スレッドが共有しているので,書き込んだ値以外を読む事が可能

Page 12: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

異なるメモリ

2015/05/07先端GPGPUシミュレーション工学特論12

メモリアドレスが共有できず,一つのスレッドのみがそのメモリアドレスにアクセス あるスレッドが宣言した変数へアクセスできない

//a,b[]がレジスタに確保されている場合*1

__global__ void kernel(...){int i = blockIdx.x*blockDim.x + threadIdx.x;:

b[i] = i; //スレッドiが配列要素b[i]に自身のスレッド番号を代入//b[0,1,...,i‐1,i,...]の値はb[i]以外不定

a = b[i‐1];*2 //b[i‐1]の値(不定)をaに代入*3

:          //aの値はスレッドによって異なる} *1 あくまで動作のイメージを説明するための例で正しく実行できない

*2 iが0の場合は考えない*3 配列bは他のスレッドからアクセスできないため,代入した値以外は不定のまま

Page 13: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有メモリとL1キャッシュは一定サイズを共用

グローバルメモリへのアクセスはL2キャッシュ経由*1

Fermi世代では標準でL1キャッシュも有効化*2

メモリの種類

2015/05/07先端GPGPUシミュレーション工学特論13

オフチップメモリ

オンチップメモリ

L2キャッシュ

コンスタントメモリ

テクスチャメモリ

GPUChip

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

グローバルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

・・・

・・・*1Tesla世代でもテクスチャキャッシュとコンスタントキャッシュは存在*2Kepler世代では標準でL1キャッシュが無効化

ホストメモリ

Page 14: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

メモリの種類と並列化階層の対応

オンチップメモリ

ブロックまたはスレッドごとに異なる値を持つ

オフチップメモリ GPU全体で共通の値を持つ

ローカルメモリはレジスタが不足した時に使われる

2015/05/07先端GPGPUシミュレーション工学特論14

各GPU(Grid)内でデータを共有

各ブロック内でデータを共有

各スレッドが個別のデータを保有

L2キャッシュ

コンスタントメモリ

テクスチャメモリ

Grid

レジスタ

レジスタ

レジスタ

レジスタ

Thread 0

Thread 1

Thread 2

Thread 3

L1キャッシュ

共有メモリ

Block(0,0,0)

レジスタ

レジスタ

レジスタ

レジスタ

Thread 0

Thread 1

Thread 2

Thread 3

L1キャッシュ

共有メモリ

Block(1,0,0)

グローバルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

・・・

・・・

ホストメモリ

Page 15: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

L2キャッシュ

コンスタントメモリ

テクスチャメモリ

GPU

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

グローバルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

・・・

・・・

グローバルメモリ

ビデオメモリ(数GB) CPUのメインメモリに相当

読み込みがある一定サイズでまとめて行われる

レイテンシが大きい

効率よくアクセスするための条件がある コアレスアクセス

アラインアクセス

2015/05/07先端GPGPUシミュレーション工学特論15

Tesla世代ではコアレスアクセスの条件にメモリのアラインが含まれている

Chip

ホストメモリ

Page 16: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

グローバルメモリへのアクセス(Fermi世代以降)

2015/05/07先端GPGPUシミュレーション工学特論16

メモリ操作の命令はWarpごとに発行 1 Warp内の32スレッドが協調

各スレッドのメモリアクセス要求を一つに集約

メモリアクセス要求の処理 128バイトもしくは32バイト単位

すべてL2キャッシュを通過

アーキテクチャによってはL1キャッシュも通過

L1キャッシュの使用はコンパイルオプションで設定可能

Fermi世代は標準で使用,Kepler世代は標準で未使用

Page 17: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

グローバルメモリへのアクセス(Fermi世代以降)

2015/05/07先端GPGPUシミュレーション工学特論17

コアレスメモリアクセス(coalesce access) 1 Warp内の32スレッドが隣り合ったメモリにアクセス

データサイズが4バイトの時,スレッド1がアクセスするメモリアドレスはスレッド0がアクセスするメモリアドレス+4

メモリアドレスの連続性に着目

アラインメモリアクセス(align access) Warpがアクセスするデータの先頭アドレスがキャッシュ粒度の倍数

L2キャッシュのみを使う場合は32バイトの倍数

L1キャッシュとL2キャッシュを使う場合は128バイトの倍数

Page 18: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされる読込

2015/05/07先端GPGPUシミュレーション工学特論18

L1キャッシュとL2キャッシュを通過

読込は128バイト単位で実行 L1キャッシュのキャッシュラインのサイズで実行

読込の評価に利用する用語 メモリトランザクション

メモリのアクセス要求に対して排他的にメモリにアクセスして行う処理の単位

バスの利用率

必要なデータサイズ/読込完了に必要な読込データサイズ

Page 19: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

アライン/コアレスアクセス

Warp内の全スレッドが要求するメモリアドレスが128バイトの範囲内

全スレッドが隣り合ったメモリにアクセス

先頭データのメモリアドレスが128バイトの倍数

読込に必要な128バイトのトランザクションは一つ

読み込んだデータ全てを利用

バスの利用率は128/128=100%

0 16

32

48

64

80

96

112

キャッシュされる読込の例

2015/05/07先端GPGPUシミュレーション工学特論19

128

144

160

176

192

208

224

240

012345678910111213141516171819202122232425262728293031

256

272

288

304

320

336

352

358

Warp内でのスレッドID(カーネル内でのスレッド番号とは異なる)

メモリアドレス

メモリアドレスに対するスレッドのアクセス要求

読込に必要な128バイトトランザクション

128バイトのキャッシュライン読み込むデータ

Page 20: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされる読込の例

2015/05/07先端GPGPUシミュレーション工学特論20

アライン/アンコアレスアクセス

Warp内の全スレッドが要求するメモリアドレスが128バイトの範囲内(一つのキャッシュラインに収まる)

各スレッドがアクセスするメモリアドレスが不連続

先頭データのメモリアドレスが128バイトの倍数

読込に必要な128バイトのトランザクションは一つ

読み込んだデータ全てを利用

バスの利用率は128/128=100%

0 16

32

48

64

80

96

112

012345678910111213141516171819202122232425262728293031

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 21: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされる読込の例

2015/05/07先端GPGPUシミュレーション工学特論21

ミスアライン/コアレスアクセス

Warpがアクセスするデータの先頭アドレスが128の倍数ではない(一つのキャッシュラインに収まらない)

全スレッドが隣り合ったメモリにアクセス

先頭データのメモリアドレスが128バイトの倍数ではない

読込に必要な128バイトのトランザクションは二つ

読み込んだデータの半分だけを利用

バスの利用率は128/(128×2)=50%

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 22: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされる読込の例

2015/05/07先端GPGPUシミュレーション工学特論22

ミスアライン/コアレスアクセス

Warp内の全スレッドが同じアドレスにアクセス要求

一つのキャッシュラインに収まる

読込に必要な128バイトのトランザクションは一つ

読み込んだ128バイトのうち利用されるのは4バイトのみ

バスの利用率は4/128=3.125%

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 23: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされる読込の例

2015/05/07先端GPGPUシミュレーション工学特論23

ミスアライン/コアレスアクセス

Warp内の各スレッドが広範囲に点在するデータにアクセス

複数のキャッシュラインにまたがる(上の例では3個)

読込に必要な128バイトのトランザクションは 悪で32個 読み込んだデータのうち128バイトのみを利用

バスの利用率は 悪で128/(128×32)=3.125%上の例では128/(128×3)=33.3%

何度も読み込むための待ちが発生

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 24: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされない読込

2015/05/07先端GPGPUシミュレーション工学特論24

L1キャッシュを無効化

L2キャッシュのみを通過

読込は32バイト単位で実行 メモリセグメントのサイズで実行

細かい単位で実行されるため,ミスアライン・アンコアレスメモリアクセスのパフォーマンスが改善される可能性がある

セグメント

メモリの管理方式の一つ

まとまった大きさで管理されたメモリ空間

Page 25: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

アライン/コアレスアクセス

Warp内の全スレッドが要求するメモリアドレスが128バイト(四つのセグメントに収まる)

全スレッドが隣り合ったメモリにアクセス

先頭データのメモリアドレスが32バイトの倍数

読込に必要な32バイトのトランザクションは四つ

読み込んだデータ全てを利用

バスの利用率は128/(32×4)=100%

キャッシュされない読込の例

2015/05/07先端GPGPUシミュレーション工学特論25

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Warp内でのスレッドID(カーネル内でのスレッド番号とは異なる)

メモリアドレス

メモリアドレスに対するスレッドのアクセス要求

読込に必要な32バイトトランザクション

32バイトのメモリセグメント読み込むデータ

Page 26: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされない読込の例

2015/05/07先端GPGPUシミュレーション工学特論26

アライン/アンコアレスアクセス

Warp内の全スレッドが要求するメモリアドレスが128バイト(四つのセグメントに収まる)

各スレッドがアクセスするメモリアドレスが不連続

先頭データのメモリアドレスが32バイトの倍数

読込に必要な32バイトのトランザクションは四つ

読み込んだデータ全てを利用

バスの利用率は128/(32×4)=100%

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 27: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされない読込の例

2015/05/07先端GPGPUシミュレーション工学特論27

ミスアライン/コアレスアクセス

Warpがアクセスするデータの先頭アドレスが128の倍数ではない(五つのセグメントにまたがる)

全スレッドが隣り合ったメモリにアクセス

先頭データのメモリアドレスが32バイトの倍数ではない

読込に必要な32バイトのトランザクションは五つ

読み込んだデータの8割は利用

バスの利用率は128/(32×5)=80% 改善!

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 28: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされない読込の例

2015/05/07先端GPGPUシミュレーション工学特論28

ミスアライン/アンコアレスアクセス

Warp内の全スレッドが同じアドレスにアクセス要求

一つのセグメントに収まる

読込に必要な32バイトのトランザクションは一つ

読み込んだ32バイトのうち利用されるのは4バイトのみ

バスの利用率は4/32=12.5% 改善!

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 29: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

キャッシュされない読込の例

2015/05/07先端GPGPUシミュレーション工学特論29

ミスアライン/アンコアレスアクセス

Warp内の各スレッドが広範囲に点在するデータにアクセス

複数のセグメントにまたがる(上の例では10個)

読込に必要な32バイトのトランザクションは 悪で32個 悪でも32バイトのセグメント32個に分散

バスの利用率は 悪で128/(32×32)=12.5% 改善!上の例では128/(32×10)=40% 改善!

何度も読み込むための待ちは依然として発生

012345678910111213141516171819202122232425262728293031

0 16

32

48

64

80

96

112

128

144

160

176

192

208

224

240

256

272

288

304

320

336

352

358

Page 30: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

L2キャッシュ

コンスタントメモリ

テクスチャメモリ

GPU

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

グローバルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

・・・

・・・

Chip

共有(シェアード)メモリ

ブロック内のスレッドが共通のデータ(メモリアドレス)にアクセス可能

物理的にSMに近い

遅延はグローバルメモリの20~30分の1,帯域幅は10倍

2015/05/07先端GPGPUシミュレーション工学特論30

Fermi世代以前のGPUでマネージドキャッシュとして利用

1ブロックあたり16,32*,48kB

*Kepler世代から

ホストメモリ

Page 31: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有(シェアード)メモリ

修飾子 __shared__ を付けて宣言

データをブロック内で共有するために同期を取る

共有メモリ上でデータを変更してもグローバルメモリには反映されない グローバルメモリへの書き戻しが必要

2015/05/07先端GPGPUシミュレーション工学特論31

__global__ void kernel(flaot *a){__shared__ float shared_a[NT];//NTはスレッド数int i = blockDim.x*blockIdx.x + theadIdx.x;

shared_a[threadIdx.x] = a[i];__syncthreads();//共有メモリを使った処理__syncrthreads();a[i] = shared_a[threadIdx.x];

}

Page 32: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有(シェアード)メモリ利用のイメージ

2015/05/07先端GPGPUシミュレーション工学特論32

a[i]

a[i]

shared_a[tx]

i=   0    1   2    3   4    5   6    7tx=threadIdx.x=   0    1   2    3   0    1   2    3

tx=  0    1   2    3     0    1   2    3ブロック内で同期

共有メモリを使った処理

shared_a[tx]

blockIdx.x=0 blockIdx.x=1

共有メモリを使った処理

一つのブロック内で使用する分のみを確保

同期を取り,共有メモリ内に正しくデータが入っていることを保証ブロック内で同期

処理

の流

Page 33: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

ブロック内でのスレッドの同期

2015/05/07先端GPGPUシミュレーション工学特論33

__syncthreads(); カーネル実行中にスレッドの同期を取る

__syncthreads()が書かれた行にスレッドが到達する

と,同一ブロック内の他の全てのスレッドがその行に達するまで待機

異なるブロック間での同期は不可能

1ブロックあたりのスレッド数が32以下では不要*

32スレッドが一つのwarpとして協調して処理を実行するため

ifの中に記述するとカーネルが終了しないことがあるif(条件){

__syncthreads();//条件が真にならないスレッドはifの中に入らないため,//カーネルが永久に終わらない

}

*Warp同期プログラミングは将来のGPUでサポートが廃止される予定

Page 34: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有(シェアード)メモリの宣言

修飾子 __shared__ を付けて宣言

配列として宣言 要素数を静的(コンパイル時)に決定する場合

__shared__ 型 変数名[要素数] 多次元配列も宣言可能(1,2,3次元)

要素数を動的(カーネル実行時)に決定する場合

extern __shared__ 型 変数名[] メモリサイズをカーネル呼出時のパラメータで指定

<<<ブロック数,スレッド数,共有メモリのサイズ>>>

2015/05/07先端GPGPUシミュレーション工学特論34=要素数*sizeof(共有メモリの型)

Page 35: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有(シェアード)メモリ容量の選択

2015/05/07先端GPGPUシミュレーション工学特論35

共有メモリとL1キャッシュは64kBを共用 どちらを多く利用するかを決定する関数が用意されている

64kB全ての利用は不可能

L1キャッシュ48kB/共有メモリ16kB cudaDeviceSetCacheConfig(cudaFuncCachePreferL1);

L1キャッシュ16kB/共有メモリ48kB cudaDeviceSetCacheConfig(cudaFuncCachePreferShared); コンパイルオプションとして ‐Xptxas ‐dlcm=cgを与えるとL1キャッシュを利用しなくなるが,48kB以上は利用できない

L1キャッシュ32kB/共有メモリ32kB* cudaDeviceSetCacheConfig(cudaFuncCachePreferEqual);

*Kepler世代から

Page 36: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

カーネル単位での共有メモリ容量の選択

2015/05/07先端GPGPUシミュレーション工学特論36

デバイス(GPU)単位ではなくカーネル単位で共有メモリの容量を決定する関数も用意 cudaFuncSetCacheConfig(関数ポインタ,容量の設定) 容量の設定はcudaDeviceSetCacheConfigと同じ

cudaFuncCachePreferL1 cudaFuncCachePreferShared cudaFuncCachePreferEqual* cudaFuncCachePreferNone(デフォルト)

カーネルごとに一度設定するだけでよい

デバイスごとの設定(cudaDeviceSetCacheConfig)を上書きできる

*Kepler世代から

Page 37: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有(シェアード)メモリへのアクセス(Tesla世代)

高速にアクセスするための制約が緩い

16スレッド(Half Warp)単位でアクセス

16個のバンクから構成 32bit=4バイトが1バンク

一つのバンクにアクセスできるのはHalf Warp内の1スレッドのみ 複数のスレッドが一つのバンクに同時にアクセスするとバンクコンフリクト(バンク衝突)が発生

共有メモリへのアクセスが逐次化される2015/05/07先端GPGPUシミュレーション工学特論37

Page 38: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトにならない例(Tesla世代)

Half Warpが異なるバンクにアクセス

隣接データにアクセス

データのサイズは32bit (float型)

コアレスアクセスに類似

Half Warpが異なるバンクにアクセス

ランダムアクセス

データのサイズは32bit

アドレスが不連続でもよい

コアレスアクセスと異なる

15

14

13

12

11

10

9

8

7

6

5

4

3

2

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1 1

0 0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1 1

0 0

2015/05/07先端GPGPUシミュレーション工学特論38

メモリアドレスに対するスレッドのアクセス要求 Half Warp内でのスレッドID

バンク番号

Page 39: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

96bit(12バイト)ごとにアクセス float型データ3個分の構造体など

同じバンクにはアクセスしていない

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

128

バンクコンフリクトにならない例(Tesla世代)

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

2015/05/07先端GPGPUシミュレーション工学特論39

メモリアドレスに対するスレッドのアクセス要求

メモリアドレス

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

Page 40: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトする例(Tesla世代)

64bit(8バイト)ごとにアクセス double型では必ずバンクコンフリクトが発生

2wayバンクコンフリクト スレッド0と8, 1と9,2と10...は同時に共有メモリにアクセスできない

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

2015/05/07先端GPGPUシミュレーション工学特論40

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンクコンフリクト

バンクコンフリクト

バンクコンフリクト

バンクコンフリクト

バンクコンフリクト

バンクコンフリクト

バンクコンフリクト

バンクコンフリクト

バンク番号

Page 41: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトする例(Tesla世代)

256bit(32バイト)ごとにアクセス

8wayバンクコンフリクト

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

128

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

252

248

244

240

236

232

228

224

220

216

212

208

204

200

196

192

2015/05/07先端GPGPUシミュレーション工学特論41

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンクコンフリクト

バンクコンフリクト

バンク番号

Page 42: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトしない例(Tesla世代)

16スレッドが一つの

バンクの同一アドレスにアクセス

配列のある要素のデータを全スレッドが共有

バンクコンフリクトは発生しない

ブロードキャストが行われる

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

2015/05/07先端GPGPUシミュレーション工学特論42

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

Page 43: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有(シェアード)メモリへのアクセス(Fermi世代以降)

32スレッド(1 Warp)単位でアクセス

32個のバンクから構成 Compute Capabilityが2.x 32bit=4バイトが1バンク

帯域幅はクロックサイクルふたつあたり32ビット

Compute Capabilityが3.x 64bit=8バイトが1バンク

帯域幅はクロックサイクルあたり64ビット

バンクコンフリクトはFermiと同じか少ない

関数でバンクサイズを設定可能 cudaDeviceSetShareMemConfig(設定);設定 cudaSharedMemBankSizeFourByte 4バイト cudaSharedMemBankSizeEightByte 8バイト

2015/05/07先端GPGPUシミュレーション工学特論43

Page 44: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

128

バンクコンフリクトにならないアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論44

Warp内の32スレッドが異なるバンクにある32ビットのデータに隣接アクセス 理想的なアクセスパターン

Warpが発行した共有メモリの読込,書込命令が一つのトランザクションで処理される

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

バンク番号 0 1 2 3

144

4 5 6 7

160

8 9 10 11

176

12 13 14 15

192

16 17 18 19

208

20 21 22 23

224

24 25 26 27

240

28 29 30 31

Page 45: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトにならないアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論45

Warp内の32スレッドが異なるバンクにある32ビットのデータにランダムアクセス 各スレッドは異なるバンクにアクセス

バンクコンフリクトは発生しない

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

128

0 1 2 3

144

4 5 6 7

160

8 9 10 11

176

12 13 14 15

192

16 17 18 19

208

20 21 22 23

224

24 25 26 27

240

28 29 30 31バンク番号

Page 46: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトにならないアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論46

複数のスレッドが一つのバンクの同一アドレスにアクセス バンクコンフリクトは発生しない

メモリトランザクションが一つ実行され,アクセスした複数のスレッドに値がブロードキャストされる

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

128

0 1 2 3

144

4 5 6 7

160

8 9 10 11

176

12 13 14 15

192

16 17 18 19

208

20 21 22 23

224

24 25 26 27

240

28 29 30 31バンク番号

Page 47: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトになるアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論47

複数のスレッドが一つのバンクの異なるアドレスにアクセス バンクコンフリクトが発生(下の例では4‐way) メモリアクセスが逐次化( 悪で32倍の時間がかかる)

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0

128

256

384

0 1 2 3

16

144

272

400

4 5 6 7

32

160

288

416

8 9 10 11

48

176

304

432

12 13 14 15

64

192

320

448

16 17 18 19

80

208

336

464

20 21 22 23

96

224

352

480

24 25 26 27

112

240

358

496

28 29 30 31バンク番号

バンクコンフリクト

バンクコンフリクト

バンクコンフリクト

Page 48: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

レジスタ

各スレッドが個別に利用

カーネル内で変数を宣言するとレジスタを利用

非常に高速 キャッシュとしても利用可能

2015/05/07先端GPGPUシミュレーション工学特論48*Keplerからは65536本

少容量 32768本*×32bit 利用可能分を超えるとローカルメモリへ追い出される

レジスタスピル

L2キャッシュ

コンスタントメモリ

テクスチャメモリ

GPU

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

レジスタ

レジスタ

レジスタ

レジスタ

CUDA Core

CUDA Core

CUDA Core

CUDA Core

L1キャッシュ

共有メモリ

SM

グローバルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

ローカルメモリ

・・・

・・・

Chip

ホストメモリ

Page 49: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

並列化の階層とメモリの階層

並列化の階層 メモリの階層

Grid

Block

Thread

Warp

グローバルメモリ

共有メモリ

GPU

Streaming Multiproc

essor

CUDA Core

オフチップメモリ

オンチップメモリ

ハードウェア構成

ハードウェア構成

レジスタ

2015/05/07先端GPGPUシミュレーション工学特論49

Page 50: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有メモリの使いどころ

2015/05/07先端GPGPUシミュレーション工学特論50

Tesla世代以前では共有メモリの利用は必須 キャッシュを未搭載

同じデータに2回以上アクセスする場合は共有メモリに保持して再利用

Fermi世代以降 キャッシュを搭載

単純な処理ではキャッシュが大いに活躍

プログラマが管理できるキャッシュ

キャッシュされない条件下で共有メモリを利用してデータを再利用

メモリアクセスパターンの 適化

グローバルメモリへのアクセスの制約を回避

Page 51: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

配列(画像や行列)の転置

2015/05/07先端GPGPUシミュレーション工学特論51

読込と書込で配列へのアクセスパターンが異なる

一方はコアレッシング可,一方はコアレッシング不可

共有メモリを利用してメモリアクセスを改善

1 2

3 4

1 3

2 4j

i

j

i

Page 52: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

配列(画像や行列)の転置

2015/05/07先端GPGPUシミュレーション工学特論52

2次元配列の転置

out[j][i] = in[i][j]

in[][] out[][]

Ny

Nx

Nx

Ny

Page 53: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

配列(画像や行列)の転置

2015/05/07先端GPGPUシミュレーション工学特論53

1次元配列に保存されたデータの転置

out[i*Ny+j] = in[j*Nx+i]

Ny

Nx

Nx

Ny

in[] out[]

Page 54: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

#include<stdio.h>#include<stdlib.h>#define Nx 4096#define Ny 2048#define Nbytes (Nx*Ny*sizeof(int))

void init(int *in, int *out){int i,j;for(i=0; i<Nx; i++){for(j=0; j<Ny; j++){

in[i*Ny + j] = j;out[i*Ny + j] = ‐1;

}}

}

void transpose(int *in, int *out){int i,j;for(i=0; i<Nx; i++){

for(j=0; j<Ny; j++){out[j*Nx+i] = in[i*Ny+j];

}}

}

int main(){int *in,*out;

in  = (int *)malloc(Nbytes);out = (int *)malloc(Nbytes);

init(in,out);transpose(in,out);

return 0;}

CPUプログラム

2015/05/07先端GPGPUシミュレーション工学特論54

transpose.c

Page 55: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

GPUへの移植

2015/05/07先端GPGPUシミュレーション工学特論55

2次元的に並列化し,1スレッドが1要素を転置

blockIdx.x=0 blockIdx.x=1

blockIdx.y=0

blockIdx.y=1

gridDim.x=2

gridDim.y=2

blockDim.x=4

blockDim.y=4

threadIdx.x=threadIdx.y=

Page 56: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

1スレッドが読み込む配列要素の決定

2015/05/07先端GPGPUシミュレーション工学特論56

i = blockIdx.x*blockDim.x + threadIdx.x j = blockIdx.y*blockDim.y + threadIdx.y

(0,0)(1,0)(2,0)(3,0)(0,0)

(3,3) (3,3)

(0,1)(1,1)(2,1)(3,1)

(0,2)(1,2)(2,2)(3,2)

(0,3)(1,3)(2,3)(3,3) (3,3)

(0,0) (0,0)

block(0,0) block(1,0)

block(0,1) block(1,1)

thread

threadIdx.xthreadIdx.y

i= 0 1 2 3 4 5 6 7j=

01

23

45

67

Page 57: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

1スレッドが書き込む配列要素の決定

2015/05/07先端GPGPUシミュレーション工学特論57

グローバルメモリへの書込は,読込の際に設定したブロックやスレッドの配置に制限されない スレッド番号と配列添字を対応付ける便宜的な概念

in[ij] out[ij]

Page 58: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

#include<stdio.h>#define Nx 4096#define Ny 2048#define Nbytes (Nx*Ny*sizeof(int))#define Tx 16#define Ty 16

__global__ void init(int *in, int *out){

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

int j = blockIdx.y*blockDim.y+ threadIdx.y;

in[i*Ny + j] = j;out[i*Ny + j] = ‐1;

}__global__ void transpose(int *in, int *out){

int i = blockIdx.x*blockDim.x

+ threadIdx.x;int j = blockIdx.y*blockDim.y

+ threadIdx.y;out[j*Nx + i] = in[i*Ny + j];

}

int main(){int *in,*out;dim3 Thread(Tx,Ty,1),

Block(Nx/Tx,Ny/Ty,1);

cudaMalloc((void**)&in,Nbytes);cudaMalloc((void**)&out,Nbytes);init<<<Block, Thread>>>(in,out);      transpose<<<Block, Thread>>>

(in,out);return 0;

}

GPUプログラム

2015/05/07先端GPGPUシミュレーション工学特論58

simple_transpose.cu

Page 59: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論59

x, yのどちらをメモリが連続な方向とするか threadIdx.xが連続な方向にアクセスする場合

(0,0)(1,0)(2,0)(3,0)(0,0)

(3,3) (3,3)

(0,1)(1,1)(2,1)(3,1)

(0,2)(1,2)(2,2)(3,2)

(0,3)(1,3)(2,3)(3,3) (3,3)

(0,0) (0,0)

block(0,0) block(1,0) threadIdx.x=0~15,threadIdx.y=0

threadIdx.x=0~15,threadIdx.y=1...

[i][j]=[j*Nx+i]

メモリが連続な方向

thre

adId

x.y

threadIdx.x

Page 60: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論60

x, yのどちらをメモリが連続な方向とするか threadIdx.yが連続な方向にアクセスする場合

(0,0)(1,0)(2,0)(3,0)(0,0)

(3,3) (3,3)

(0,1)(1,1)(2,1)(3,1)

(0,2)(1,2)(2,2)(3,2)

(0,3)(1,3)(2,3)(3,3) (3,3)

(0,0) (0,0)

block(0,0) block(1,0) threadIdx.x=0,  threadIdx.y=0~15

threadIdx.x=1,  threadIdx.y=0~15...

[i][j]=[i*Ny+j]

メモリが連続な方向

thre

adId

x.y

threadIdx.x

Page 61: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

#include<stdio.h>#define Nx 4096#define Ny 2048#define Nbytes (Nx*Ny*sizeof(int))#define Tx 16#define Ty 16

__global__ void init(int *in, int *out){

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

int j = blockIdx.y*blockDim.y+ threadIdx.y;

in[i*Ny + j] = j;out[i*Ny + j] = ‐1;

}__global__ void copy(int *in, int *out){

int i = blockIdx.x*blockDim.x

+ threadIdx.x;int j = blockIdx.y*blockDim.y

+ threadIdx.y;out[j*Nx + i] = in[j*Nx + i];out[i*Ny + j] = in[i*Ny + j];

}

int main(){int *in,*out;dim3 Thread(Tx,Ty,1),

Block(Nx/Tx,Ny/Ty,1);

cudaMalloc((void**)&in,Nbytes);cudaMalloc((void**)&out,Nbytes);init<<<Block, Thread>>>(in,out);copy<<<Block, Thread>>>(in,out);return 0;

}

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論61

simple_copy.cu

どちらが高速?

Page 62: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

実行時間

2015/05/07先端GPGPUシミュレーション工学特論62

入力配列サイズ Nx×Ny = 4096×2048 スレッド数 Tx×Ty = 16×16

カーネル 実行時間 [ms]

copy(目標値) 0.802 / 1.57

Page 63: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論63

2次元配列の場合

in[][],out[][]

Nx

Ny

j

ifor(i=0;i<Nx;i++)

for(j=0;j<Ny;j++)out[i][j]=in[i][j];

for(j=0;j<Ny;j++)for(i=0;i<Nx;i++)

out[i][j]=in[i][j];

Page 64: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論64

2次元配列の場合

for(i=0;i<Nx;i++)for(j=0;j<Ny;j++)

out[i][j]=in[i][j];

in[][],out[][]

Nx

Ny

j

i

for(j=0;j<Ny;j++)for(i=0;i<Nx;i++)

out[i][j]=in[i][j];

Page 65: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論65

2次元配列の1次元配列的表現(前回資料参照)

for(i=0;i<Nx;i++)for(j=0;j<Ny;j++)

out[i][j]=in[i][j];

in[],out[]

Nx

Ny

j

i

for(i=0;i<Nx;i++)for(j=0;j<Ny;j++)

out[i*Ny+j]=in[i*Ny+j];

Page 66: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論66

CUDAで2次元的に並列化してアクセスする場合

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

j = blockIdx.y*blockDim.y+ threadIdx.y;

out[j*Nx+i]=in[j*Nx+i];

in[],out[]

Nx

Ny

j

ifor(i=0;i<Nx;i++)

for(j=0;j<Ny;j++)out[i*Ny+j]=

in[i*Ny+j];

threadIdx.x

thre

adId

x.y

threadIdx.xのスレッド群(threadIdx.yが一定)

が連続なメモリアドレスにアクセス

Page 67: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

#include<stdio.h>#define Nx 4096#define Ny 2048#define Nbytes (Nx*Ny*sizeof(int))#define Tx 16#define Ty 16

__global__ void init(int *in, int *out){

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

int j = blockIdx.y*blockDim.y+ threadIdx.y;

in[j*Nx + i] = j;out[j*Nx + i] = ‐1;

}__global__ void transpose(int *in, int *out){

int i = blockIdx.x*blockDim.x

+ threadIdx.x;int j = blockIdx.y*blockDim.y

+ threadIdx.y;out[i*Ny + j] = in[j*Nx + i];

}

int main(){int *in,*out;dim3 Thread(Tx,Ty,1),

Block(Nx/Tx,Ny/Ty,1);

cudaMalloc((void**)&in,Nbytes);cudaMalloc((void**)&out,Nbytes);init<<<Block, Thread>>>(in,out);      transpose<<<Block, Thread>>>

(in,out);return 0;

}

GPUプログラム

2015/05/07先端GPGPUシミュレーション工学特論67

transpose.cu

Page 68: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

実行時間

2015/05/07先端GPGPUシミュレーション工学特論68

入力配列サイズ Nx×Ny = 4096×2048 スレッド数 Tx×Ty = 16×16

カーネル 実行時間 [ms]

copy(目標値) 0.802 / 1.57

transpose 1.34

Page 69: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

転置時のメモリアクセス

2015/05/07先端GPGPUシミュレーション工学特論69

読込はコアレスアクセス

書込はストライドアクセス キャッシュはメモリアクセスの改善には利用できない

in[]

out[]

out[i*Ny + j] = in[j*Nx + i];

・・・ ・・・ ・・・ ・・・ ・・・ ・・・ ・・・

・・・ ・・・ ・・・ ・・・ ・・・ ・・・ ・・・

Ny*sizeof(int)バイトのストライドアクセス

Page 70: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

転置時のメモリアクセス

2015/05/07先端GPGPUシミュレーション工学特論70

読込はコアレスアクセス

書込は非コアレスアクセス キャッシュはメモリアクセスの改善には利用できない

in[] out[]

threadIdx.xの群が連続

なメモリアドレスにアクセス

out[i*Ny + j] = in[j*Nx + i];

Ny

Nx

Nx

Ny

threadIdx.yの群が連続

なメモリアドレスにアクセスth

read

Idx.

y

threadIdx.y

thre

adId

x.x

threadIdx.x

Page 71: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

in[]

共有メモリによるメモリアクセスの改善

2015/05/07先端GPGPUシミュレーション工学特論71

共有メモリは制約が緩い 一度グローバルメモリから共有メモリにコピー

ここは元々コアレスアクセス

out[]

thre

adId

x.y

threadIdx.x

threadIdx.x

thre

adId

x.y

Page 72: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

in[]

共有メモリによるメモリアクセスの改善

2015/05/07先端GPGPUシミュレーション工学特論72

共有メモリは制約が緩い 共有メモリ内で転置

共有メモリからグローバルメモリへコアレスアクセス

out[]

threadIdx.y

thre

adId

x.x

threadIdx.x

thre

adId

x.y

Page 73: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

グローバルメモリから共有メモリへの書込

2015/05/07先端GPGPUシミュレーション工学特論73

__shared__ int data[Tx][Ty]; //ブロック内のスレッドが使うサイズだけ宣言int i = blockIdx.x*blockDim.x + threadIdx.x; //配列添字とスレッド番号のint j = blockIdx.y*blockDim.y + threadIdx.y; //対応を計算

原点からのズレ//グローバルメモリから共有メモリへコピー(コアレスアクセス)data[threadIdx.x][threadIdx.y] = in[j*Nx + i];__syncthreads(); //ブロック内の全スレッドがコピーを完了するのを待機

(0,0)

(0,1)

(0,2)

(0,3)

(1,0)

(1,1)

(1,2)

(1,3)

(2,0)

(2,1)

(2,2)

(2,3)

(3,0)

(3,1)

(2,3)

(3,3)

(0,0)

(1,0)

(2,0)

(3,0)

(0,1)

(1,1)

(2,1)

(3,1)

(0,2)

(1,2)

(2,2)

(3,2)

(0,3)

(1,3)

(2,3)

(3,3)

グローバルメモリから読み込んだデータをそのまま共有メモリへ書込み

blockIdx.x*blockDim.x=1*4

blockIdx.y*blockDim.y=0*4 threadIdx.x

thre

adId

x.y

threadIdx.x

thre

adId

x.y

Page 74: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

共有メモリからグローバルメモリへの書込

2015/05/07先端GPGPUシミュレーション工学特論74

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

原点からのズレ配列out[]の横幅(コピー時の書き方out[j*Nx + i] = in[j*Nx + i];と同じ)

out[j*Ny + i] = data[threadIdx.y][threadIdx.x];

(0,0)(1,0)(2,0)(3,0)

(0,1)(1,1)(2,1)(3,1)

(0,2)(1,2)(2,2)(3,2)

(0,3)(1,3)(2,3)(3,3)

(0,0)

(1,0)

(2,0)

(3,0)

(0,1)

(1,1)

(2,1)

(3,1)

(0,2)

(1,2)

(2,2)

(3,2)

(0,3)

(1,3)

(2,3)

(3,3)

各スレッドが共有メモリへアクセスする位置を転置

blockIdx.y*blockDim.y=0*4

blockIdx.x*blockDim.x=1*4

Ny

threadIdx.x

thre

adId

x.y

threadIdx.y

thre

adId

x.xthreadIdx.x,

threadIdx.y が

参照する次元が入れ替わっている

Page 75: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

__global__ void transpose_shared(int *in, int *,out){__shared__ int data[Tx][Ty]; //ブロック内のスレッドが使うサイズだけ宣言int i = blockIdx.x*blockDim.x + threadIdx.x; //配列添字とスレッド番号のint j = blockIdx.y*blockDim.y + threadIdx.y; //対応を計算

//グローバルメモリから共有メモリへコピー(コアレスアクセス)data[threadIdx.x][threadIdx.y] = in[j*Nx + i];__syncthreads(); //ブロック内の全スレッドがコピーを完了するのを待機

i = blockIdx.y*blockDim.y + threadIdx.x;j = blockIdx.x*blockDim.x + threadIdx.y;out[j*Ny + i] = data[threadIdx.y][threadIdx.x];

}

共有メモリを利用するカーネル

2015/05/07先端GPGPUシミュレーション工学特論75

transpose_shared.cu

Page 76: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

実行時間

2015/05/07先端GPGPUシミュレーション工学特論76

入力配列サイズ Nx×Ny = 4096×2048 スレッド数 Tx×Ty = 16×16

1.4倍高速化*

*高速化率=基準となる実行時間/高速化したカーネルによる実行時間

カーネル 実行時間 [ms]

copy(目標値) 0.802 / 1.57

transpose 1.34

transpose_shared 0.977

Page 77: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元配列におけるバンクコンフリクト(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論77

転置の計算

共有メモリにアクセスする添字が入れ替わる

読込か書込のどちらかでバンクコンフリクトが発生

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

128

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

192

data[16][16]

・・・

Half Warp内でのスレッドID メモリアドレス

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

Page 78: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

128

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

192

2次元配列におけるバンクコンフリクト(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論78

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

//16‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

・・・

バンクコンフリクト

data[threadIdx.x][0]

data[threadIdx.y][threadIdx.x]

Page 79: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

2次元配列におけるバンクコンフリクト(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論79

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

//16‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

・・・

バンクコンフリクト

data[threadIdx.y][threadIdx.x]

64 1280 192

data[threadIdx.x][1]

Page 80: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

128

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

192

2次元配列におけるバンクコンフリクト(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論80

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

data[threadIdx.x][threadIdx.y]

・・・

data[0][threadIdx.x]

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

Page 81: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

2次元配列におけるバンクコンフリクト(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論81

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

・・・

64 1280 192

data[1][threadIdx.x]

data[threadIdx.x][threadIdx.y]

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

Page 82: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトの低減(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論82

解消は非常に簡単

配列を余分に確保してバンクをずらす

data[16][16]

data[16__][16__]

210

15

14

13

12

11

10

9

8

7

6

5

4

3

2

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1 1

0 0

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

メモリアドレスに対するスレッドのアクセス要求

バンク番号

Page 83: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトの低減(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論83

解消は非常に簡単

配列を余分に確保してバンクをずらす

data[16][16]

data[16  ][16+1] 配列を余分に確保することをパディング(詰め物)するという

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

210

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

Page 84: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

1 2 30

バンクコンフリクトの低減(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論84

メモリパディングをした場合 読込のアクセス

書込のアクセス・・・

メモリアドレスに対するスレッドのアクセス要求

//コンフリクトフリーdata[threadIdx.x][threadIdx.y]

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

2

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

data[threadIdx.x][0]

data[threadIdx.y][threadIdx.x]

Page 85: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトの低減(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論85

メモリパディングをした場合 読込のアクセス

書込のアクセス

メモリアドレスに対するスレッドのアクセス要求 1 2 30

・・・

//コンフリクトフリーdata[threadIdx.x][threadIdx.y]

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

2

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

data[threadIdx.x][1]

data[threadIdx.y][threadIdx.x]

Page 86: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトの低減(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論86

メモリパディングをした場合 読込のアクセス

書込のアクセス

メモリアドレスに対するスレッドのアクセス要求 1 2 30

・・・

data[threadIdx.x][threadIdx.y]

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

2

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

data[0][threadIdx.x]

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

Page 87: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトの低減(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論87

メモリパディングをした場合 読込のアクセス

書込のアクセス

メモリアドレスに対するスレッドのアクセス要求 1 2 30

・・・

data[threadIdx.x][threadIdx.y]

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

2

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

2

1

0

15

14

13

12

11

10

9

8

7

6

5

4

3

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

data[1][threadIdx.x]

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

Page 88: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論88

バンクの数が32に増加

配列要素数に応じてバンクが折りたたまれる

配列の2次元の要素数とバンクの数が同じ場合

0

128

256

384

0 1 2 3

16

144

272

400

4 5 6 7

32

160

288

416

8 9 10 11

48

176

304

432

12 13 14 15

data[8][32]

data[0][32]

data[1][32]

data[2][32]

data[3][32]

64

192

320

448

16 17 18 19

80

208

336

464

20 21 22 23

96

224

352

480

24 25 26 27

112

240

358

496

28 29 30 31

メモリアドレス

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

バンク番号

Warp内でのスレッドID

Page 89: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論89

バンクの数が32に増加

配列要素数に応じてバンクが折りたたまれる

配列の2次元の要素数とバンクの数が異なる場合

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16]

0

128

64

192

16

144

80

208

32

160

96

224

48

176

112

240

data[0][16]

data[1][16]

data[2][16]

data[3][16]

Page 90: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論90

バンクの数が32に増加

配列要素数に応じてバンクが折りたたまれる

配列の2次元の要素数とバンクの数が異なる場合

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16]

data[0][16]

data[1][16]

data[2][16]

data[3][16]

バンク番号

Page 91: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的なスレッドとWarpの対応(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論91

1ブロック内のスレッドはWarp単位で実行 32個の連続したスレッド

1ブロック内にスレッドが2次元的に配置されていても,ハードウェア的には1次元的に配置

ブロック内のスレッド番号とWarpの対応 threadIdx.xの値が 初に変化( も内側)

threadIdx.xがカーネル起動時に設定された数字を超えるとthreadIdx.yの値が変化

スレッド数を(16,16,1)として起動した場合

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

・・・0 1 2 3 4 5 6 7

02

12

22

32

42

52

62

72 ・・・

Warp 0 Warp 1

Warp内でのスレッドID

Page 92: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論92

バンクの数が32に増加

配列要素数に応じてバンクが折りたたまれる

配列の2次元の要素数とバンクの数が異なる場合0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16]

data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

コンフリクトフリー

Page 93: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論93

転置の計算 共有メモリにアクセスする添字が入れ替わる

読込か書込のどちらかでバンクコンフリクトが発生

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16]

data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16] …

Page 94: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論94

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

//8‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

data[threadIdx.y][threadIdx.x]

data[threadIdx.x][0] data[threadIdx.x][1]

バンクコンフリクト

バンクコンフリクト

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 95: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論95

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

//8‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

data[threadIdx.x][2] data[threadIdx.x][3]

バンクコンフリクト

バンクコンフリクト

data[threadIdx.y][threadIdx.x]

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 96: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論96

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

data[threadIdx.x][threadIdx.y]

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

data[0][threadIdx.x] data[1][threadIdx.x]

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 97: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

2次元配列におけるバンクコンフリクト(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論97

transpose_shared.cuの場合 読込のアクセス

書込のアクセス

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

data[threadIdx.x][threadIdx.y]

data[2][threadIdx.x] data[3][threadIdx.x]

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 98: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

バンクコンフリクトの低減(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論98

配列を余分に確保してバンクをずらす data[16][16]

data[16][16+1]

data[16][17]

0 16 32 48 64

追加分の配列要素

80 96 112

128

144

160

176

192

208

224

240

256

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[0][17]

data[1][17]

data[2][17]

data[3][17]

Page 99: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

19 20 21 22 23 24 25 26 27 28 29 30 31 0 1

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

バンクコンフリクトの低減(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論99

配列を余分に確保してバンクをずらす data[16][16]

data[16][16+1]

data[16][17]

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

1 2 3

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[0][17]

data[1][17]

data[2][17]

data[3][17]

Page 100: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

19 20 21 22 23 24 25 26 27 28 29 30 31 0 11 2 3

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

バンクコンフリクトの低減(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論100

メモリパディングをした場合 読込のアクセス

書込のアクセス

//コンフリクトフリーdata[threadIdx.x][threadIdx.y]

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][17] data[0][17]

data[1][17]

data[2][17]

data[3][17]

data[threadIdx.x][0] data[threadIdx.x][1]

00

10

20

30

40

50

60

70

80

90100110120130140150

threadIdx.xthreadIdx.y

01

11

21

31

41

51

61

71

81

91101111121131141151

data[threadIdx.y][threadIdx.x]

Page 101: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

19 20 21 22 23 24 25 26 27 28 29 30 31 0 11 2 3

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

バンクコンフリクトの低減(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論101

メモリパディングをした場合 読込のアクセス

書込のアクセス

//コンフリクトフリーdata[threadIdx.x][threadIdx.y]

data[threadIdx.y][threadIdx.x]

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][17] data[0][17]

data[1][17]

data[2][17]

data[3][17]

data[threadIdx.x][2] data[threadIdx.x][3]

00

10

20

30

40

50

60

70

80

90100110120130140150

threadIdx.xthreadIdx.y

01

11

21

31

41

51

61

71

81

91101111121131141151

Page 102: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

19 20 21 22 23 24 25 26 27 28 29 30 31 0 11 2 3

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

バンクコンフリクトの低減(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論102

メモリパディングをした場合 読込のアクセス

書込のアクセス

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][17] data[0][17]

data[1][17]

data[2][17]

data[3][17]

data[threadIdx.x][threadIdx.y]

//2‐wayバンクコンフリクトdata[threadIdx.y][threadIdx.x]

data[0][threadIdx.x] data[1][threadIdx.x]

バンクコンフリクト

00

10

20

30

40

50

60

70

80

90100110120130140150

threadIdx.xthreadIdx.y

01

11

21

31

41

51

61

71

81

91101111121131141151

Page 103: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

19 20 21 22 23 24 25 26 27 28 29 30 31 0 11 2 3

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18

17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

バンクコンフリクトの低減(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論103

メモリパディングをした場合 読込のアクセス

書込のアクセス

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][17] data[0][17]

data[1][17]

data[2][17]

data[3][17]

data[threadIdx.x][threadIdx.y]

//2‐wayバンクコンフリクトdata[threadIdx.y][threadIdx.x]

data[2][threadIdx.x] data[3][threadIdx.x]

バンクコンフリクト

00

10

20

30

40

50

60

70

80

90100110120130140150

threadIdx.xthreadIdx.y

01

11

21

31

41

51

61

71

81

91101111121131141151

Page 104: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

__global__ void transpose_reducebankconflict(int *in, int *,out){__shared__ int data[Tx][Ty+1]; //バンクコンフリクトを回避int i = blockIdx.x*blockDim.x + threadIdx.x; //配列添字とスレッド番号のint j = blockIdx.y*blockDim.y + threadIdx.y; //対応を計算

//グローバルメモリから共有メモリへコピー(コアレスアクセス)data[threadIdx.x][threadIdx.y] = in[j*Nx + i];__syncthreads(); //ブロック内の全スレッドがコピーを完了するのを待機

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

out[j*Ny + i] = data[threadIdx.y][threadIdx.x];

}

バンクコンフリクトを低減したカーネル

2015/05/07先端GPGPUシミュレーション工学特論104

transpose_reducebankconflict.cu

Page 105: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

実行時間

2015/05/07先端GPGPUシミュレーション工学特論105

入力配列サイズ Nx×Ny = 4096×2048 スレッド数 Tx×Ty = 16×16

1.1倍高速化*

カーネル 実行時間 [ms]

copy(目標値) 0.802 / 1.57

transpose 1.34

transpose_shared 0.977transpose_reducebankconflict 0.926

*高速化率=基準となる実行時間/高速化したカーネルによる実行時間

Page 106: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論106

CUDAで2次元的に並列化してアクセスする場合 threadIdx.xのスレッド群(threadIdx.yが一定)が連続なメモリアドレスにアクセス

C言語の多次元配列 2次元目の要素が連続になるようメモリに確保

transpose_shared.cuの共有メモリの使い方は不適切

in[],out[]

Nx

Ny

j

ithreadIdx.x

thre

adId

x.y

data[Tx][Ty]

Tx

Ty

j

ithreadIdx.x

thre

adId

x.y

Page 107: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

2次元的な配列アクセスの優先方向

2015/05/07先端GPGPUシミュレーション工学特論107

共有メモリの宣言の変更 1次元目と2次元目を入れ替え

data[Tx][Ty]

data[Ty][Tx] 配列参照 1次元目の添字はthreadIdx.yを利用

2次元目の添字はthreadIdx.xを利用

threadIdx.xのスレッド群(threadIdx.yが一定)が連続なメモリアドレスにアクセス

data[Tx][Ty]

Tx

Ty

j

ithreadIdx.x

thre

adId

x.y

data[Ty][Tx]

Ty

Tx

i

jthreadIdx.y

thre

adId

x.x

Page 108: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

__global__ void transpose_shared(int *in, int *,out){__shared__ int data[Tx][Ty]; //ブロック内のスレッドが使うサイズだけ宣言int i = blockIdx.x*blockDim.x + threadIdx.x; //配列添字とスレッド番号のint j = blockIdx.y*blockDim.y + threadIdx.y; //対応を計算

//グローバルメモリから共有メモリへコピー(コアレスアクセス)data[threadIdx.x][threadIdx.y] = in[j*Nx + i];__syncthreads(); //ブロック内の全スレッドがコピーを完了するのを待機

i = blockIdx.y*blockDim.y + threadIdx.x;j = blockIdx.x*blockDim.x + threadIdx.y;out[j*Ny + i] = data[threadIdx.y][threadIdx.x];

}

共有メモリを利用するカーネル

2015/05/07先端GPGPUシミュレーション工学特論108

transpose_shared.cu

Page 109: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

__global__ void transpose_shared(int *in, int *,out){__shared__ int data[Ty][Tx]; //ブロック内のスレッドが使うサイズだけ宣言int i = blockIdx.x*blockDim.x + threadIdx.x; //配列添字とスレッド番号のint j = blockIdx.y*blockDim.y + threadIdx.y; //対応を計算

//グローバルメモリから共有メモリへコピー(コアレスアクセス)data[threadIdx.y][threadIdx.x] = in[j*Nx + i];__syncthreads(); //ブロック内の全スレッドがコピーを完了するのを待機

i = blockIdx.y*blockDim.y + threadIdx.x;j = blockIdx.x*blockDim.x + threadIdx.y;out[j*Ny + i] = data[threadIdx.x][threadIdx.y];

}

共有メモリの添字を交換したカーネル

2015/05/07先端GPGPUシミュレーション工学特論109

transpose_shared_indexchange.cu

Page 110: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

128

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

192

配列添字を入れ替えた場合の共有メモリへのアクセス(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論110

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

・・・

data[0][threadIdx.x]

data[threadIdx.x][threadIdx.y]

Page 111: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

配列添字を入れ替えた場合の共有メモリへのアクセス(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論111

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

・・・

data[threadIdx.x][threadIdx.y]

64 1280 192

data[1][threadIdx.x]

Page 112: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

64

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

128

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

0

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

192

配列添字を入れ替えた場合の共有メモリへのアクセス(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論112

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

data[threadIdx.y][threadIdx.x]

・・・

data[threadIdx.x][0]

//16‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

バンクコンフリクト

Page 113: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

124

120

116

112

108

104

100

96

92

88

84

80

76

72

68

188

184

180

176

172

164

160

160

156

152

148

144

140

136

132

60

56

52

48

44

40

36

32

28

24

20

16

12

8

4

256

252

248

244

240

236

232

228

224

220

216

208

204

200

196

配列添字を入れ替えた場合の共有メモリへのアクセス(Tesla世代)

2015/05/07先端GPGPUシミュレーション工学特論113

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

・・・

メモリアドレスに対するスレッドのアクセス要求

0

23

5

1

6

8

14

4

7

9

15

10111213

バンク番号

・・・

data[threadIdx.y][threadIdx.x]

//16‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

バンクコンフリクト

64 1280 192

data[threadIdx.x][1]

Page 114: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

配列添字を入れ替えた場合の共有メモリへのアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論114

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

data[threadIdx.x][threadIdx.y]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

data[0][threadIdx.x] data[1][threadIdx.x]

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 115: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

配列添字を入れ替えた場合の共有メモリへのアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論115

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

//コンフリクトフリーdata[threadIdx.y][threadIdx.x]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

data[2][threadIdx.x] data[3][threadIdx.x]

data[threadIdx.x][threadIdx.y]

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 116: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

配列添字を入れ替えた場合の共有メモリへのアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論116

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

data[threadIdx.y][threadIdx.x]

//8‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16] …

data[threadIdx.x][0] data[threadIdx.x][1]

バンクコンフリクト

バンクコンフリクト

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 117: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

配列添字を入れ替えた場合の共有メモリへのアクセス(Fermi世代)

2015/05/07先端GPGPUシミュレーション工学特論117

配列添字を入れ替えた場合 読込のアクセス

書込のアクセス

data[threadIdx.y][threadIdx.x]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

data[16][16] data[0][16]

data[1][16]

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15data[2][16]

data[3][16]

data[threadIdx.x][2] data[threadIdx.x][3]

バンクコンフリクト

バンクコンフリクト

//8‐wayバンクコンフリクトdata[threadIdx.x][threadIdx.y]

00

10

20

30

40

50

60

70

80

90100110120130140150

01

11

21

31

41

51

61

71

81

91101111121131141151

threadIdx.xthreadIdx.y

Page 118: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

実行時間

2015/05/07先端GPGPUシミュレーション工学特論118

入力配列サイズ Nx×Ny = 4096×2048 スレッド数 Tx×Ty = 16×16

カーネル 実行時間 [ms]

copy(目標値) 0.802 / 1.57

transpose 1.34

transpose_shared 0.977transpose_reducebankconflict 0.926transpose_shared_indexchange 0.939

有意に高速化

Page 119: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

__global__ void transpose_reducebankconflict(int *in, int *,out){__shared__ int data[Ty][Tx+1]; //バンクコンフリクトを回避int i = blockIdx.x*blockDim.x + threadIdx.x; //配列添字とスレッド番号のint j = blockIdx.y*blockDim.y + threadIdx.y; //対応を計算

//グローバルメモリから共有メモリへコピー(コアレスアクセス)data[threadIdx.y][threadIdx.x] = in[j*Nx + i];__syncthreads(); //ブロック内の全スレッドがコピーを完了するのを待機

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

out[j*Ny + i] = data[threadIdx.x][threadIdx.y];

}

共有メモリの添字を交換,パディングしたカーネル

2015/05/07先端GPGPUシミュレーション工学特論119

transpose_reducebankconflict_indexchange.cu

Page 120: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

実行時間

2015/05/07先端GPGPUシミュレーション工学特論120

入力配列サイズ Nx×Ny = 4096×2048 スレッド数 Tx×Ty = 16×16

カーネル 実行時間 [ms]

copy(目標値) 0.802 / 1.57

transpose 1.34

transpose_shared 0.977transpose_reducebankconflict 0.926transpose_shared_indexchange 0.939transpose_reducebankconflict

_indexchange 0.926

ほぼ同じ

Page 121: 2015年度先端GPGPUシミュレーション工学特論 第4回 GPUのメモリ階層の詳細(共有メモリ)

付録 書込と読込のアクセスの影響

2015/05/07先端GPGPUシミュレーション工学特論121

スレッド数(Tx×Ty=16×16)で配列サイズを変更

読込と書込でコアレス・ストライドアクセスが変化 書込がコアレスアクセスになる方が高速になる傾向

GPUでは書込をキャッシュできないことが理由と思われる

カーネル実行時間 [ms]

4096×2048 2048×1024 1024×512

copy(目標値)(rw:コアレス/rw:ストライド)

0.802/1.57 0.202/0.389 0.055/0.103

transpose(r:コアレス,w:ストライド)

1.39  0.348 0.089

simple_transpose(r:ストライド,w:コアレス)

1.13 0.289 0.077