View
409
Download
4
Category
Preview:
Citation preview
長岡技術科学大学 電気電子情報工学専攻 出川智啓
GPGPU講習会補足資料GPGPUとCUDA Fortran
長岡技術科学大学 電気電子情報工学専攻 出川智啓
GPUのアーキテクチャ
GPU(Graphics Processing Unit)とは
画像処理専用のハードウェア
具体的には画像処理用のチップ
チップ単体では販売されていない
PCI‐Exカードで販売
チップ単体と区別せずにGPUと呼ぶことも多い
ノートPCに搭載
PCI‐Exカードとして販売されるGPUには,ビデオメモリと呼ばれるDRAMが搭載
GPGPU講習会3 2016/01/13
GPU(Graphics Processing Unit)とは
GPGPU講習会4
代表的な製品
NVIDIA GeForce AMD Radeon Intel HD Graphics(内蔵)
代表的な用途
3Dグラフィックス処理
3Dゲーム,3DCAD,3DCG作成
エンコード・デコード支援
GPU上に専用チップを搭載していることが多い
デスクトップPCのGUI処理
Windows Aeroが比較的高性能なGPUを要求
2016/01/13
GPU(Graphics Processing Unit)の役割
グラフィックスを表示するために様々な処理を行い,処理の結果をディスプレイに出力
3次元グラフィックスの発展に伴って役割が大きく変化
3次元座標変換
ポリゴンとピクセルの対応付け
ピクセル色計算テクスチャ参照
フレームバッファ(ビデオメモリ)への書き込み
ディスプレイ出力
CPU
ディスプレイコントローラ GPU
3次元座標変換
ポリゴンとピクセルの対応付け
ピクセル色計算テクスチャ参照
フレームバッファ(ビデオメモリ)への書き込み
ディスプレイ出力
現在過去
CPUが3D描画の演算を実行
GPUが出力
描画情報
画面出力
GPUが演算から出力までの全てを担当
CPUは描画情報の生成やGPUへの情報の引き渡し,GPUの制御を行う
描画情報
画面出力
GPGPU講習会5 2016/01/13
GPUの描画の流れ
1. CPUからGPUへ描画情報を送信
2. 頂点処理(頂点シェーダ) 座標変換
画面上での頂点やポリゴンの位置・大きさの決定
頂点単位での照明の計算
3. 頂点やポリゴンからピクセルを生成(ラスタライザ)
4. ピクセル処理(ピクセルシェーダ) 画面上のピクセルの色
テクスチャの模様
5. 画面出力 ピクセルの色情報をフレームバッファに書き込み
2.
3.
4.
GPGPU講習会6 2016/01/13
ビデオカードの利点
CPUで描画のための演算を行うと,CPUにかかる負荷が大きい
3次元画像処理の専用回路を備えたハードウェアを導入
○CPUにかかる負荷を減らすことができる
○頂点・ピクセルごとに並列処理が可能なため,ハードウェアによる並列処理が可能
GPGPU講習会7 2016/01/13
ビデオカードの欠点
3次元画像処理の専用回路を備えたハードウェアを導入
×新しい描画方法を開発しても,GPUへ実装・製品化されるまで利用できない
×ユーザが所有しているGPUによって利用できる機能にばらつきが生じる
×ある描画手法用の専用回路を実装しても,その描画方法が常に使われる訳ではないのでGPU全体の利用効率が下がる
GPGPU講習会8 2016/01/13
ビデオカードからGPUへ
CGの多様化と共に固定機能の実装が困難に
頂点処理とピクセル処理をユーザが書き換えられるプログラマブルシェーダの実装
頂点処理用回路
ピクセル処理用回路
ビデオカード
頂点シェーダユニット
ピクセルシェーダユニット
GPU
GPGPU講習会9 2016/01/13
ビデオカードからGPUへ
描画する画像によって頂点処理とピクセル処理の負荷が変化
処理によっては利用効率に差が発生し,利用効率が低下
GPU
頂点シェーダユニット
ピクセルシェーダユニット
頂点処理重視の処理
GPU
頂点シェーダユニット
ピクセルシェーダユニット
ピクセル処理重視の処理
空きユニット
空きユニット
GPGPU講習会10 2016/01/13
ビデオカードからGPUへ
頂点シェーダとピクセルシェーダを統合したユニファイドシェーダへの進化
頂点処理とピクセル処理を切り替えることで利用率を向上
GPU
ユニファイドシェーダユニット
頂点処理重視の処理 ピクセル処理重視の処理
GPU
ユニファイドシェーダユニット
GPGPU講習会11 2016/01/13
ビデオカードからGPUへ
各ピクセルに対して並列に処理実行できるように進化
単純な処理を行う演算器を大量に搭載
高い並列度で処理を実行
GPUの誕生とGPGPUの普及
高性能な3DCG画像処理への要求→GPUの高性能化
GPUの長所
消費電力あたりの浮動小数点理論演算性能が高い
GPU単体の消費電力は高い
(相対的に)安価
CPUだけで同等の計算能力を達成するより安価
GPGPU講習会12 2016/01/13
Teslaアーキテクチャ*
GPGPU講習会
Tesla C1060の仕様
SM数 30 CUDA Core数 240(=8 Core/SM×30 SM) キャッシュを搭載せず
13
*CUDAのサポートから外れます
2016/01/13
SP SP
SP SP
SP SP
SP SP
SFU SFU16 KB
Shared Memory
Register File (16384×32‐bit)
Streaming Multiprocessor
SMSMSM
Teslaアーキテクチャの構造
GPGPU講習会
Tesla C1060の仕様
CUDAコア数(単精度) 240 Cores
CUDAコアクロック周波数 1,296 MHz
単精度演算ピーク性能 622*1 (933*2) GFLOPS
倍精度演算ユニット数 30*3 Units
倍精度演算ピーク性能 78 GFLOPS
メモリクロック周波数 800 MHz
メモリバス幅 512 bit
大メモリバンド幅*4 102 GB/s
*1単精度演算ピーク性能 = コアクロック周波数×コア数×命令の同時発行数(2)*2CUDA CoreとSFUが同時に命令を発行できれば1296 MHz×240×3*3一つのSMに倍精度演算器が一つ搭載(と言われている)
*4 大メモリバンド幅=メモリクロック周波数×メモリバス幅/8×2(Double Data Rate)
14 2016/01/13
Fermiアーキテクチャ
GPGPU講習会
Tesla M2050の仕様
SM数 14 CUDA Core数 448(=32 Core/SM×14 SM) L1/L2 キャッシュを搭載
ECC(誤り訂正機能)を搭載
15 2016/01/13
Register File (16384 × 32‐bit)
64 KB Shared Memory / L1 Cache
SM
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
SFU×4
L2 Cache
GigaThread Engine
PCI Express 3.0 Host Interface
Memory Controller
GPCRaster Engine
GPCRaster Engine
SM
Raster EngineGPC
Raster EngineGPC
Memory ControllerMemory Controller
Memory ControllerMemory Controller
Memory Controller
詳細はhttp://www.nvidia.co.jp/docs/IO/81860/NVIDIA_Fermi_Architecture_Whitepaper_FINAL_J.pdfを参照のこと
Fermiアーキテクチャの構造
GPGPU講習会
Tesla M2050の仕様
CUDAコア数(単精度) 448 Cores
CUDAコアクロック周波数 1,150 MHz
単精度演算ピーク性能 1.03 TFLOPS
倍精度演算ユニット数 0*1 Unit
倍精度演算ピーク性能 515 GFLOPS
メモリクロック周波数 1.55 GHz
メモリバス幅 384 bit
大メモリバンド幅 148 GB/s
*1単精度CUDA Coreを2基使って倍精度演算を実行
16 2016/01/13
Keplerアーキテクチャの構造
GPGPU講習会
Tesla K20c/mの仕様
SMX数 13 Streaming Multiprocessor eXtreme (?)
CUDA Core数 2,496(=192 Core/SM×13 SMX)
17 2016/01/13
詳細はhttps://www.nvidia.co.jp/content/apac/pdf/tesla/nvidia‐kepler‐gk110‐architecture‐whitepaper‐jp.pdfを参照のこと
Register File (65536 × 32‐bit)
64 KB Shared Memory / L1 Cache
48 KB Read‐Only Data Cache
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
DP Unit
SMX
SMX
L2 Cache
GigaThread Engine
PCI Express 3.0 Host Interface
Memory ControllerMemory Controller
Memory Controller
Memory ControllerMemory Controller
Memory Controller
Keplerアーキテクチャの構造
GPGPU講習会
Tesla K20c/mの仕様
CUDAコア数(単精度) 2,496 Cores
CUDAコアクロック周波数 706 MHz
単精度演算ピーク性能 3.52 TFLOPS
倍精度演算ユニット数 832*1 Units
倍精度演算ピーク性能 1.17 TFLOPS
メモリクロック周波数 2.6 GHz
メモリバス幅 320 bit
大メモリバンド幅 208 GB/s
*164基/SMX×13基
18 2016/01/13
Maxwellアーキテクチャ
GeForce GTX TITAN Xの仕様
SM数 24 CUDA Core数 3,072(=128 Core/SM×24 SM)
GPGPU講習会19 2016/01/13
第1世代の詳細はhttps://www.nvidia.co.jp/content/product‐detail‐pages/geforce‐gtx‐750‐ti/geforce‐gtx‐750ti‐whitepaper.pdfを参照のこと
64 KB Shared Memory
L1 Cache
SMM
Register File (16,384 × 32‐
bit)Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
L1 Cache
Register File (16,384 × 32‐
bit)Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
Register File (16,384 × 32‐
bit)Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
Register File (16,384 × 32‐
bit)Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
SFU
SFU
SFU
SFU
SFU
SFU
SFU
SFU
PolyMorph Engine 3.0
SMM
Raster EngineGPC
Raster EngineGPC
L2 Cache
GigaThread EnginePCI Express 3.0 Host Interface
Memory Controller
Raster EngineGPC
Raster EngineGPC
Memory Controller
Memory ControllerMemory Controller
Maxwellアーキテクチャ
GeForce GTX TITAN Xの仕様*
CUDAコア数(単精度) 3,072 Cores
CUDAコアクロック周波数 1,002 MHz
単精度演算ピーク性能 6.14 TFLOPS
倍精度演算ユニット数 0*1 Units
倍精度演算ピーク性能 192 GFLOPS*2
メモリクロック周波数 3.5 GHz*3
メモリバス幅 384 bit
大メモリバンド幅 336.5 GB/s
*1http://www.4gamer.net/games/121/G012181/20141225075/*2倍精度演算は単精度演算の性能の1/32 (1/16 Flop/Core/clock)*3DDR(Double Data Rate) 7GHz相当と書かれている場合もある
GPGPU講習会
http://http://www.geforce.com/hardware/desktop‐gpus/geforce‐gtx‐titan‐x/specifications
*http://ja.wikipedia.org/wiki/FLOPS
20 2016/01/13
Pascalアーキテクチャ
2016年にリリース予定
倍精度演算器を搭載予定
NVLink GPU同士やGPUとCPUを接続する独自の方式
通信(CPU ↔ メモリ ↔ PCI Express ↔ メモリ ↔ GPU)のボトルネックを解消(PCI Express3.0の5~12倍)
複数のGPUを使って大規模な計算が可能
3Dメモリ(High Bandwidth Memory, HBM)* 3次元積層技術を利用し,メモリの容量と帯域を大幅に増加
大32GB,メモリ帯域1TB/s
GPGPU講習会
*http://pc.watch.impress.co.jp/docs/column/kaigai/20150421_698806.html
21 2016/01/13
Voltaアーキテクチャ
Pascalの後継
詳しい情報は不明
アメリカの次世代スーパーコンピュータへ採用予定
オークリッジ国立研究所 SUMMIT 150~300PFLOPS ローレンス・リバモア研究所 SIERRA 100PFLOPS以上
地球シミュレータと同等の演算性能を1ノードで実現
現在Top500 2位のスーパーコンピュータと同じ電力で5~10倍高速,サイズは1/5
GPGPU講習会
*http://www.4gamer.net/games/121/G012181/20141225075/
22 2016/01/13
GPUの普及の要因
GPGPU講習会23
GPUの進展は15年程
普及の速度は驚異的
CPUは数十年かけて進展
CPUも驚異的な速度で進展
様々な高速化技術を導入
GPUが普及している要因は何か?
2016/01/13
TOP500 List(2015, Nov.) スーパーコンピュータの性能の世界ランキング
GPUを搭載したコンピュータは2基だけ
GPGPU講習会24
http://www.top500.org/より引用
2016/01/13
計算機名称(設置国) アクセラレータ実効性能[PFlop/s]
/ピーク性能[PFlop/s] 消費電力[MW]
1 Tianhe‐2 (China) Intel Xeon Phi 33.9/54.9 17.82 Titan (U.S.A.) NVIDIA K20x 17.6/27.1 8.203 Sequoia (U.S.A.) − 17.2/20.1 7.904 K computer (Japan) − 10.5/11.3 12.75 Mira (U.S.A.) − 8.59/10.1 3.956 Trinity (U.S.A.) − 8.10/11.17 Piz Daint (Switzerland) NVIDIA K20x 6.27/7.79 2.338 Hazel Hen (Germany) ‐ 5.64/7.409 Shaheen II(Saudi Arabia) ‐ 5.54/7.24 2.8310 Stampede (U.S.A.) Intel Xeon Phi 5.17/8.52 4.51
CPUの性能向上サイクル
GPGPU講習会25
半導体回路の細線化
消費電力が低下
低下分の電力をトランジスタのスイッチングに利用
動作周波数向上
性能向上
2016/01/13
ムーアの法則
CPUの性能向上サイクル
GPGPU講習会26
半導体回路の細線化
消費電力が低下
低下分の電力をトランジスタのスイッチングに利用
動作周波数向上
性能向上
絶縁部が狭くなり漏れ電流が発生,電力が低下しない
消費電力の増加によって発熱量が増加,空冷の限界
2倍のトランジスタ
を使っても性能は1.4倍程度にしか伸びない
2016/01/13
ムーアの法則
ポラックの法則
CPUの性能向上サイクル
GPGPU講習会27
半導体回路の細線化
消費電力が低下
低下分の電力をトランジスタのスイッチングに利用
動作周波数向上
性能向上
絶縁部が狭くなり漏れ電流が発生,電力が低下しない
消費電力の増加によって発熱量が増加,空冷の限界
2倍のトランジスタ
を使っても性能は1.4倍程度にしか伸びない
コア数の増加
2016/01/13
ムーアの法則
ポラックの法則
CPUの性能向上
FLOPS = 1コアの演算性能× コア数× CPUの動作周波数
1コアの演算性能の向上
演算器(トランジスタ)の増加
コア数の増加
トランジスタ数の増加
CPUの動作周波数
回路の効率化や印可電圧の向上劇的な性能向上は期待できない
コンパイラの 適化を利用
複数のコアを使うようにプログラムを書かないと速くならない
GPGPU講習会28 2016/01/13
GPUを使うという選択
GPU普及の要因の一つはCPUクロックの頭打ち
クロックを下げてマルチコア化したCPUへの対応が必要
なぜGPUという選択か?
CPU用プログラムの並列化でもいいのでは?
消費電力の低減
数値計算や高性能計算(HPC)の業界がGPUに注目
スーパーコンピュータの性能向上
高機能なCPUを大量に使うと消費電力が問題に
高機能な制御用プロセッサと,計算を実行する低性能なアクセラレータの組み合わせ
GPGPU講習会29 2016/01/13
Green500(2015, Nov.) TOP3の計算機がそれぞれ異なるアクセラレータを搭載
インターネットのサービス提供に利用されている(と思われる)計算機が大量にランクイン
GPGPU講習会30http://www.green500.org/より引用
2016/01/13
計算機名称 アクセラレータ GFLOPS/W 消費電力[kW]
1 Shoubu PEZY‐SC 7.03 50.322 TSUBAME‐KFC NVIDIA Tesla K80 5.33 51.133 ASUS ESC4000 AMD FirePro S9150 5.27 57.154 Sugon Cluster NVIDIA Tesla K80 4.78 65.005 Xstream NVIDIA Tesla K80 4.11 190.06 Inspur TS10000 NVIDIA Tesla K40 3.86 58.007 Inspur TS10000 NVIDIA Tesla K40 3.78 110.08 Inspur TS10000 NVIDIA Tesla K40 3.78 110.09 Inspur TS10000 NVIDIA Tesla K40 3.78 110.010 Inspur TS10000 NVIDIA Tesla K40 3.78 110.0
まとめ
GPGPU講習会31
GPUの特徴
低性能の演算器を大量に搭載(~3000コア)
GPUが使われる理由
理論演算性能が高い
メモリとチップ間の帯域も広い
省電力と高性能を両立
今後の計算機の主流になると考えられる
将来に対する投資
GPUだけでなく,制御用CPU+計算用アクセラレータという思想は今後しばらく主流であり続ける
2016/01/13
GROUSEの利用方法
情報処理センターGPGPUシステム
16台の計算サーバで構成
NVIDIA Tesla M2050を搭載
各サーバに4機ずつ計64機 grouse
tesla01 ‐ tesla04
M2050×16
tesla05 ‐ tesla08
M2050×16
tesla09 – tesla12
M2050×16
tesla13 – tesla16
M2050×16
外部ネットワーク
GPGPU講習会33 2016/01/13
grouseへのログイン
2016/01/13GPGPU講習会34
2013年度GPGPU講習会資料より引用
grouseへのログイン
2016/01/13GPGPU講習会35
2013年度GPGPU講習会資料より引用
統合アカウントとパスワード入力
ターミナルの起動
2016/01/13GPGPU講習会36
2013年度GPGPU講習会資料より引用
System→Terminal
ターミナルの起動
2016/01/13GPGPU講習会37
2013年度GPGPU講習会資料より引用
実行イメージ
grouse
処理
処理結果出力
キー入力,マウス入力
2016/01/13GPGPU講習会38
プログラムの作成と保存
2016/01/13GPGPU講習会39
2013年度GPGPU講習会資料より引用
実行イメージ
grouse
ファイル保存
ハードディスク
共有
共有
2016/01/13GPGPU講習会40
tesla01 ‐ tesla04 tesla05 ‐ tesla08 tesla09 – tesla12 tesla13 – tesla16
共有
tesla??へのログイン
もう一つターミナルを起動し,下のターミナルでログイン$ ssh␣–l␣ユーザID␣tesla??(??には01~16の番号を入力)
2016/01/13GPGPU講習会41
2013年度GPGPU講習会資料より引用
tesla??でのコンパイルとプログラム実行
2016/01/13GPGPU講習会42
grouseでの作業用
tesla??でのコンパイルと実行用
2013年度GPGPU講習会資料より引用
tesla??でコンパイルとプログラム実行
コンパイル
$ pgf90˽ソースファイル名
pgf90がコンパイル対象とするソースファイルの拡張子は.cuf エラーがなければa.outという実行ファイルが作成される
CUDAに関係するオプションは‐Mcuda=...で指定
実行
$ ./a.out
対応オプションの一覧は‐helpオプションで確認
$ pgf90˽‐help
2016/01/13GPGPU講習会43
実行イメージ
grouse
処理
処理結果出力
キー入力,マウス入力
$ ssh␣tesla16
tesla16
キー入力
処理処理結果
2016/01/13GPGPU講習会44
実行イメージ
grouse
キー入力,マウス入力
$ ssh␣tesla16$ pgf90 ??.cuf
キー入力
処理結果
ハードディスク
??.cuf
コンパイル
2016/01/13GPGPU講習会
処理結果出力
tesla1645
実行イメージ
grouse処理結果出力
キー入力,マウス入力
$ ssh␣tesla16$ pgf90 ??.cuf$ ./a.out
キー入力
処理結果
ハードディスク
a.out
実行
2016/01/13GPGPU講習会
tesla1646
実行イメージ
grouse
キー入力,マウス入力
$ ssh␣tesla16$ pgf90 ??.cuf$ ./a.out
キー入力
ハードディスク
a.out
実行
2016/01/13GPGPU講習会
tesla16GPU0GPU1GPU2GPU3
処理結果出力
処理結果
47
情報処理センターでのCUDAの使い方
1. grouseやtesla??で開発する場合
grouseやtesla??にログイン
ソースファイルを作成し,tesla??上でコンパイル・実行
grouseはGPUを搭載していないため実行できない(コンパイルは可能)
2. 研究室のPC等,情報処理センター外で開発する場合
研究室のPCでソースファイルを作成
WinSCPなどでファイルをgrouseにアップロード
grouseを経由してtesla??にログインした後,コンパイル・実行
2016/01/13GPGPU講習会48
ターミナルのみの利用(特に演習室外から利用する場合)
1. Tera Termでgrouseにログイン
2013年度GPGPU講習会資料より引用
2016/01/13GPGPU講習会49
ターミナルのみの利用(特に演習室外から利用する場合)
2. sshでtesla??にログイン
$ ssh␣–l␣ユーザID␣tesla??(??には01~16の番号を入力)
2013年度GPGPU講習会資料より引用
2016/01/13GPGPU講習会50
grouseへのファイル転送(WinSCP) Unixコマンドscp(secure copy)のWindows GUIクライアント
Secure Shell (ssh) に含まれるsshの機能を利用して安全性の高いファイル転送を行う
Host名 grouse
統合アカウントのユーザ名とパスワード
login2016/01/13GPGPU講習会51
Windows上のソースファイルをコピー
grouseハードディスク
WinSCPでコピー
ハードディスク
共有
共有
2016/01/13GPGPU講習会
ソースファイル
52
tesla01 ‐ tesla04 tesla05 ‐ tesla08 tesla09 – tesla12 tesla13 – tesla16
共有
ソースファイル
ログインしているサーバの確認
grouseにログインしているかtesla??にログインしているか分からなくなったら
$ hostname
2016/01/13GPGPU講習会53
GPUの選択
計算機がGPUを複数搭載している場合
CUDAで利用するGPUを選択
CUDA APIを利用したGPUの選択
cudaSetDevice()命令
GPGPU講習会
program mainuse cudafor変数宣言 !ここでは標準でGPU0が使われるGPUやCPUを使った処理 !stat = cudaSetDevice(3) !ここからGPU3が使われる...
end program main
54 2016/01/13
長岡技術科学大学 電気電子情報工学専攻 出川智啓
GPUのプログラム構造
今回の内容
GPGPU講習会
GPUプログラミング環境(CUDA)
GPUプログラムの実行の流れ
CUDAによるプログラムの記述
カーネル(GPUで処理する関数)の構造
記述方法とその理由
GPU固有のパラメータの確認
56 2016/01/13
GPU(Graphics Processing Unit)とは
画像処理専用のハードウェア
具体的には画像処理用のチップ
チップ単体では販売されていない
PCI‐Exカードで販売
チップ単体と区別せずにGPUと呼ぶことも多い
ノートPCに搭載
PCI‐Exカードとして販売されるGPUには,ビデオメモリと呼ばれるDRAMが搭載
2016/01/13GPGPU講習会57
GPUのハードウェア構造
CUDA Core(旧Streaming Processor, SP)と呼ばれる演算器を多数搭載
Streaming Multiprocessor(SM, SMX)が複数のCUDA CoreとSFU,メモリをまとめて管理
SFU(Special Function Unit) 数学関数を計算するユニット
複数のSMが集まってGPUを構成
2016/01/13GPGPU講習会58
Fermiアーキテクチャ
2016/01/13GPGPU講習会59
Tesla M2050の仕様
SM数 14 CUDA Core数 448(=32 Core/SM×14 SM)
動作周波数 1,150 MHz 単精度演算ピーク性能 1.03 TFLOPS
Register File (16384 × 32‐bit)
64 KB Shared Memory / L1 Cache
SM
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
Core
SFU×4
L2 Cache
GigaThread Engine
PCI Express 3.0 Host Interface
Memory Controller
GPCRaster Engine
GPCRaster Engine
SM
Raster EngineGPC
Raster EngineGPC
Memory ControllerMemory Controller
Memory ControllerMemory Controller
Memory Controller
詳細はhttp://www.nvidia.co.jp/docs/IO/81860/NVIDIA_Fermi_Architecture_Whitepaper_FINAL_J.pdfを参照のこと
CUDA CoreCUDA CoreCUDA CoreCUDA CoreCUDA CoreCUDA CoreCUDA CoreCUDA Core
Streaming Multiprocessor
GPUの模式図
2016/01/13GPGPU講習会60
GPU
Streaming Multiprocessor
L2キャッシュ
コンスタントメモリ
テクスチャメモリ
GPUChip
グローバルメモリ
SM SM SM SM・・・
・・・
SM SM SM SM・・・ レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
L1キャッシュ
共有メモリ
StreamingMultiprocessor
SM SM SM SM・・・
ローカルメモリ
ローカルメモリ ・・・
ローカルメモリ
ローカルメモリ ・・・
CUDA Compute Unified Device Architecture NVIDIA社製GPU向け開発環境(Windows,Linux,Mac OS X) 2007年頃発表
C/C++言語+独自のGPU向け拡張
専用コンパイラ(nvcc)とランタイムライブラリ
いくつかの数値計算ライブラリ(線形代数計算,FFTなど)
CUDA登場以前
グラフィクスプログラミングを利用
足し算を行うために,色を混ぜる処理を実行
汎用計算のためには多大な労力が必要
GPGPU講習会61 2016/01/13
プログラマブルシェーダを用いた汎用計算
グラフィックスAPI(DirectX, OpenGL)による描画処理+シェーダ言語(HLSL, GLSL)による演算
void gpumain(){vec4 ColorA = vec4(0.0, 0.0, 0.0, 0.0); vec4 ColorB = vec4(0.0, 0.0, 0.0, 0.0);vec2 TexA = vec2(0.0, 0.0); vec2 TexB = vec2(0.0, 0.0);TexA.x = gl_FragCoord.x; TexA.y = gl_FragCoord.y;TexB.x = gl_FragCoord.x; TexB.y = gl_FragCoord.y;ColorA = texRECT( texUnit0, TexA );ColorB = texRECT( texUnit1, TexB );gl_FragColor = F_ALPHA*ColorA + F_BETA*ColorB;
}
void main(){glutInit( &argc, argv );glutInitWindowSize(64,64);glutCreateWindow("GpgpuHelloWorld");glGenFramebuffersEXT(1, &g_fb);glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, g_fb);glGenTextures(4, g_nTexID); // create (reference to) a new textureglBindTexture(opt1, texid);glTexParameteri(opt1, GL_TEXTURE_MIN_FILTER, GL_NEAREST);glTexParameteri(......);glTexImage2D(opt1, 0, opt2, width, height, 0, GL_RGBA, GL_FLOAT, 0);……(以下省略)
GPUの処理(GLSL)各ピクセルに対して実行
CPUの処理(OpenGL)
シェーダ言語を用いた配列加算(c=*a + *b)の例
GPGPU講習会62 2016/01/13
CUDA Fortran
2016/01/13GPGPU講習会63
FortranのNVIDIA GPU向け拡張
PGI社の販売するFortranコンパイラで利用可能
10.0以降で利用可能
2016年1月7日現在の 新版は15.10
CUDA Cを利用するが,新機能はFortranコンパイラが対応しないと利用できない
CUDA Cのバージョンが4.0でも,PGIコンパイラのバージョンが古いとバージョン3.2までしか利用できない
FortranによるGPGPU
2016/01/13GPGPU講習会64
GPGPUの普及と裾野の広がり
FORTRANからC言語を経由してGPUへ移植
資産を多く持つFortranユーザからの要求の高まり
新しい概念(GPUのプログラミングモデル)と開発言語の習得は高負荷
CUDA Fortranの登場
かけた労力と得られる利得(性能向上)のバランスがよい
並列計算の知識だけである程度の性能が得られる
CUDA Fortran
2016/01/13GPGPU講習会65
CUDA Cと比較してコーディングが簡単
CPUでプログラムを組む様な感覚
GPUの制御を隠して数値計算に集中
ライブラリよりも手間はかかるがチューニングが可能
労力(チューニング)と利得(高速化)の比較
CUDA Cよりも労力を少なく
CUDAによるプログラミング
CPUをホスト(Host),GPUをデバイス(Device)と表現
ホスト(CPU) 処理の流れやGPUを利用するための手続きを記述
プログラムの書き方は従来のFortranと同じ
利用するGPUの決定,GPUへのデータ転送,GPUで実行する関数の呼び出し等
GPGPU講習会66 2016/01/13
CUDAによるプログラミング
CPUをホスト(Host),GPUをデバイス(Device)と表現
デバイス(GPU) 処理する内容を関数として記述
引数は利用可能,返値は利用不可(subroutineを使用)
関数はkernelと呼ばれる
関数呼び出しはlaunch, invokeなどと呼ばれる
GPGPU講習会67 2016/01/13
Hello World 何を確認するか
小構成のプログラムの作り方
ファイル命名規則(拡張子は.f90) コンパイルの方法(gfortran, pgf90等を使用)
program mainimplicit none
print *,"hello world"
end program main
GPGPU講習会68 2016/01/13
helloworld.f90
CUDA FortranでHello World 何を確認するか
小構成のプログラムの作り方
ファイル命名規則(拡張子は.cuf) コンパイルの方法(pgf90を使用)
program mainimplicit none
print *,"hello world"
end program main
GPGPU講習会69
program mainimplicit none
print *,"hello world"
end program main違いは拡張子だけ?
2016/01/13
helloworld.cuf helloworld.f90
CUDA Fortranプログラムのコンパイル
ソースファイルの拡張子は.cuf
pgf90を用いてコンパイル* プリプロセッサがソースをホストコード(CPUが処理する内容)とデバイスコード(GPUが処理する内容)に分離
ホストコードはPGIコンパイラがコンパイル
デバイスコードはCUDA Cのコードへと変換
helloworld.cufにはCPUで処理する箇所しかない
GPGPU講習会70 2016/01/13
*伊藤智義 編,GPUプログラミング入門,講談社,2013,p.142.
CUDA FortranでHello World CUDA Fortran専用の処理を追加
2016/01/13GPGPU講習会71
module cuf_kernelimplicit nonecontains
attributes(global) subroutine kernel()end subroutine kernelend module cuf_kernel
program mainuse cudaforuse cuf_kernelimplicit none
call kernel<<<1,1>>>()print *,"hello world"
end program main
GPUで実行されるサブルーチン
(カーネル)attributes(global)が追加
・・・
通常のサブルーチン呼出とは異なり,<<<>>>が追加
・・・
helloworld_kernel.cuf
CUDAプログラムの実行
実行時の流れ(CPU視点)
利用するGPUの初期化やデータの転送などを実行
GPUで実行する関数を呼び出し
GPUから結果を取得
初期化の指示初期化
カーネルの実行指示カーネルを実行
結果の取得実行結果をコピー
time
CPUとGPUは非同期CPUは別の処理を実行可能
GPGPU講習会72
必要なデータのコピーメモリに書込
2016/01/13
Hello Thread(Fermi世代以降)
print文をGPUから呼び出し,並列に実行
2016/01/13GPGPU講習会73
module kernelimplicit nonecontains
subroutine hello()print *,"Hello Thread"
end subroutine helloend module kernel
program main
use kernelimplicit none
call hello()
end program main
画面表示・・・
サブルーチン実行・・・
hellothread.f90
Hello Thread(Fermi世代以降)
GPUの各スレッドが画面表示
2016/01/13GPGPU講習会74
module cuf_kernelimplicit nonecontains
attributes(global) subroutine hello()print *,"Hello Thread"
end subroutine helloend module cuf_kernel
program mainuse cudaforuse cuf_kernelimplicit noneinteger :: statcall hello<<<1,1>>>()stat = cudaThreadSynchronize()
end program main
画面表示(Fermi世代以降で可能)コンパイル時にオプションが必要‐Mcuda=cc20以降
・・・
カーネル実行・・・
ホストとデバイスの同期をとるCPUとGPUは原則同期しないので, 同期しないとカーネルを実行した直後にプログラムが終了
・・・
hellothread.cuf
CUDAでカーネルを作成するときの制限
2016/01/13GPGPU講習会75
print文による画面出力
Fermi世代以降のGPUで,コンパイルオプションを付与
‐Mcuda=cc{20|2x|2+|30|3x|35|50}
エミュレーションモード
GPUの動作(並列実行)をCPUで模擬
CUDA4.0以降では消滅
オプション付きのコンパイル
pgf90 ‐Mcuda=cc20 hellothread.cuf カーネル内でprintを使うコードは,GROUSEではコンパイルが通りません
GPUプログラムへの変更
2016/01/13GPGPU講習会76
変更点
サブルーチンの前にattributes(global)をつけた
変更の理由
2016/01/13GPGPU講習会77
変更点
サブルーチンの前にattributes(global)をつけた
変更によって実現されること
GPUで実行する関数という目印になる
変更が必要な理由
ホスト(CPU)からGPUで実行する関数(カーネル)を呼び出し
CPUが処理する箇所とGPUが処理する箇所は別のコンパイラがコンパイル
コンパイルの時点でどれがカーネルかを明記
GPUプログラムへの変更
2016/01/13GPGPU講習会78
変更点(ではないが・・・)
helloをfunctionではなくsubroutineとした
変更の理由
2016/01/13GPGPU講習会79
変更点(ではないが・・・)
helloをfunctionではなくsubroutineとした
変更によって実現されること
GPUのハードウェア構造に適したプログラムを作成できる
変更が必要な理由
GPUはホストと別に独立したメモリを持つ
GPUは描画情報を受け取り,画面に出力
GPU→CPUの頻繁なデータ転送は苦手
プログラマがメモリ管理を行い,無駄なデータ転送による実行速度低下を回避
描画情報画面出力
GPUプログラムへの変更
2016/01/13GPGPU講習会80
変更点
サブルーチン呼出の際にサブルーチン名と引数の間に<<<1,1>>>を付けた
変更の理由
2016/01/13GPGPU講習会81
変更点
サブルーチン呼出の際にサブルーチン名と引数の間に<<<1,1>>>を付けた
変更によって実現されること
GPUのハードウェア構造に適したプログラムを作成できる
変更が必要な理由
GPUには数百から数千のCUDAコアが搭載されており,それらが協調して並列処理を実行
1スレッドが実行する処理を書くことでカーネルの作成を簡略化
並列処理の度合いはカーネル呼出の際に指定
GPUプログラムへの変更
2016/01/13GPGPU講習会82
変更点
カーネルを呼び出した後に同期を取る関数を呼んだ
変更の理由
2016/01/13GPGPU講習会83
変更点
カーネルを呼び出した後に同期を取る関数を呼んだ
変更によって実現されること
GPUで実行した結果が正しく得られる
変更が必要な理由
CPUとGPUは非同期に処理を実行
関数を呼んでCPU側に制御が戻った直後にプログラムが終了(画面表示が行われない)
正しい結果を得るためにカーネルの終了を待つ
<<< , >>>内の数字で並列度が変わることの確認module cuf_kernel
implicit nonecontains
attributes(global) subroutine hello()print *,"Hello Thread"
end subroutine helloend module cuf_kernel
program mainuse cudaforuse cuf_kernelimplicit noneinteger :: statcall hello<<<?,?>>>()stat = cudaThreadSynchronize()
end program main
Hello Thread(Fermi世代以降)
2016/01/13GPGPU講習会84
<<<>>>内の数字を変えると画面表示される行数が変わる<<<1,8>>>, <<<8,1>>>, <<<4,2>>>
・・・
hellothread.cuf
<<<,>>>内の2個の数字の意味は?
GPUのハードウェアの構成に対応させて並列性を管理
各階層における並列実行の度合を指定
<<<,>>>内に2個の数字を記述して,各階層の並列度を指定
GPU
Streaming Multiprocessor
CUDA Core
ハードウェア構成
並列に実行する処理
スレッドの集まり
スレッド
並列化の階層
Grid
Thread Block
Thread
CUDA
2016/01/13GPGPU講習会85
GPUの並列化の階層
グリッド-ブロック-スレッドの3階層
グリッド(Grid) 並列に実行する処理
GPUが処理を担当する領域全体
スレッド(Thread) GPUの処理の基本単位
CPUのスレッドと同じ
ブロック(Block)もしくはスレッドブロック(Thread Block)* スレッドの集まり
GPGPU講習会86 2016/01/13
*スレッドブロックだと長い上にスレッドや変数名との兼ね合いで混乱を招くのでブロックで統一
GPUの並列化の階層
各階層の情報を参照できる変数 x,y,zを成分(component)にもつdim3派生型
グリッド(Grid) gridDim グリッド内にあるブロックの数
ブロック(Block) blockIdx ブロックに割り当てられた番号
blockDim ブロック内にあるスレッドの数
スレッド(Thread) threadIdx スレッドに割り当てられた番号
GPGPU講習会87 2016/01/13
Hello Threads(Fermi世代以降)
<<< >>>内の数字で表示される内容が変化
2016/01/13GPGPU講習会88
module cuf_kernelimplicit nonecontains
attributes(global) subroutine hello()print *,"gridDim'%'x",gridDim%x,"blockIdx'%'x",blockIdx%x,&
"blockDim'%'x",blockDim%x,"threadIdx'%'x",threadIdx%xend subroutine helloend module cuf_kernelprogram main
use cudaforuse cuf_kernelimplicit noneinteger :: statcall hello<<<2,4>>>()stat = cudaThreadSynchronize()
end program main
<<<>>>内の数字を変えると画面表示される内容が変わる<<<>>>内の数字とどのパラメータが対応しているかを確認
・・・
hellothreads.cuf
GPUの構造とカーネルの書き方
GPUはマルチスレッド(メニースレッド)で並列処理
数百から数千のCUDAコアが搭載されており,それらが協調して並列処理を実行
カーネルには1スレッドが実行する処理を書く
カーネルの作成を簡略化
カーネルを呼び出す際に並列処理の度合いを指定
カーネルと引数の間に追加した<<<,>>>で並列処理の度合を指定
GPGPU講習会89 2016/01/13
各階層の値の設定
設定の条件
GPUの世代によって設定できる上限値が変化
確認の方法
pgaccelinfo deviceQuery
GPU Computing SDKに含まれているサンプル
CUDA Programming Guide https://docs.nvidia.com/cuda/cuda‐c‐programming‐guide/#compute‐capabilities
2016/01/13GPGPU講習会90
pgaccelinfoの実行結果Device Number: 0Device Name: Tesla M2050Device Revision Number: 2.0Global Memory Size: 2817982464Number of Multiprocessors: 14Number of Cores: 448Concurrent Copy and Execution: YesTotal Constant Memory: 65536Total Shared Memory per Block: 49152Registers per Block: 32768Warp Size: 32Maximum Threads per Block: 1024Maximum Block Dimensions: 1024, 1024, 64Maximum Grid Dimensions: 65535 x 65535 x 65535Maximum Memory Pitch: 2147483647BTexture Alignment: 512BClock Rate: 1147 MHzInitialization time: 4222411 microsecondsCurrent free memory: 2746736640Upload time (4MB): 2175 microseconds ( 829 ms pinned)Download time: 2062 microseconds ( 774 ms pinned)Upload bandwidth: 1928 MB/sec (5059 MB/sec pinned)Download bandwidth: 2034 MB/sec (5418 MB/sec pinned)
2016/01/13GPGPU講習会91
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)など
2016/01/13GPGPU講習会92
長岡技術科学大学 電気電子情報工学専攻 出川智啓
GPUでの並列プログラミング(ベクトル和)
ベクトル和C=A+Bの計算
配列要素に対して計算順序の依存性がなく, も単純に並列化可能
配列a, b, cの配列要素番号iが同じ
・・・
・・・
・・・c(i)
a(i)
b(i)
+ + + + + +
GPGPU講習会94 2016/01/13
module vectoradd_kernelimplicit noneinteger,parameter :: N=2**20contains
subroutine add(a, b, c)implicit none
real :: a(N)real :: b(N)real :: c(N)
integer :: i
do i=1,Nc(i) = a(i) + b(i)
end do
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kernelimplicit none
real :: a(N)real :: b(N)real :: c(N)
a=1.0b=2.0c=0.0
call add(a,b,c)
end program main
CPUプログラム(メモリの静的確保)
GPGPU講習会95 2016/01/13
vectoradd.f90
module vectoradd_kernelimplicit noneinteger,parameter :: N=2**20contains
subroutine add(a, b, c)implicit none
real :: a(N)real :: b(N)real :: c(N)
integer :: i
do i=1,Nc(i) = a(i) + b(i)
end do
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kernelimplicit none
real,allocatable :: a(:)real,allocatable :: b(:)real,allocatable :: c(:)
allocate(a(N)); a=1.0allocate(b(N)); b=2.0allocate(c(N)); c=0.0
call add(a,b,c)
deallocate(a)deallocate(b)deallocate(c)
end program main
CPUプログラム(メモリの動的確保)
GPGPU講習会96 2016/01/13
vectoradd_allocate.f90
CPUプログラム(メモリの動的確保)
GPGPU講習会
allocate/deallocate 指定した要素数分のメモリを確保
allocateする変数はallocatable属性を付けて宣言
配列の次元は:で明記
多次元配列も確保可能
97
integer,allocatable :: a(:) !1次元配列allocate(a(100))deallocate(a)
2016/01/13
integer,allocatable :: a(:,:) !2次元配列allocate(a(100,200))deallocate(a)
GPUへの移植
GPGPU講習会98
ソースファイルの拡張子を.f90から.cufに変更
GPUの都合を反映(前回の講義資料参照)
サブルーチンの前にattributes(global)をつけた
GPUで実行する関数という目印にするため
functionではなくsubroutineを利用
GPUのハードウェア構造に適したプログラムを作るため
サブルーチン呼出の際にサブルーチン名と引数の間に<<<1,1>>>を付けた
GPUのハードウェア構造に適したプログラムを作るため
関数には1スレッドが処理する内容を書き,実行時の並列度を指定
カーネルを呼び出した後に同期を取る関数を呼んだ
GPUで実行した結果を正しく得るため
2016/01/13
GPUへの移植(メモリの取り扱い)
GPGPU講習会99
ベクトルa,b,cを確保し,a,bの値を読んでcに書き込む
ホスト(CPU)にはプロセッサとメモリが存在
デバイス(GPU)にもプロセッサとメモリが存在
デバイスからホストのメモリは(原則)直接読み書きできない
real :: a(N),b(N),c(N)
do i=1,Nprint *,a(i),b(i),c(i);
end do
abc
attributes(global) subroutine add()do i=1,Nc(i) = a(i)+b(i)
end doend subroutine add
2016/01/13
attributes(global) subroutine add()do i=1,Nc(i) = a(i)+b(i)
end doend subroutine add
GPUへの移植(メモリの取り扱い)
GPGPU講習会100
ベクトルa,b,cを確保し,a,bの値を読んでcに書き込む
ホスト(CPU)にはプロセッサとメモリが存在
デバイス(GPU)にもプロセッサとメモリが存在
デバイスからホストのメモリは(原則)直接読み書きできない
GPUのメモリを確保し,カーネルから利用
do i=1,Nprint *,a(i),b(i),c(i);
end do
abc
2016/01/13
GPUのメモリの動的確保
2016/01/13GPGPU講習会101
GPU側のメモリに確保する変数にはdevice属性を付与
メモリの確保/解放はallocate/deallocateを利用
メモリの属性から判断して適切に処理
CUDA Cはメモリ確保/解放の関数をCUDA用に置き換え
integer,allocatable :: a(:,:)integer,allocatable,device :: b(:,;) !device属性を付与
allocate(a(N,N)) !CPU側のメモリに確保allocate(b(N,N)) !GPU側のメモリに確保,多次元配列も可能
deallocate(a) !メモリを解放deallocate(b) !
CUDA Fortranの利点の一つ
module vectoradd_kernelimplicit noneinteger,parameter :: N=2**20contains
subroutine add(a, b, c)implicit none
real :: a(N)real :: b(N)real :: c(N)
integer :: i
do i=1,Nc(i) = a(i) + b(i)
end do
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kernel
implicit none
real,allocatable :: a(:)real,allocatable :: b(:)real,allocatable :: c(:)
allocate(a(N)); a=1.0allocate(b(N)); b=2.0allocate(c(N)); c=0.0
call add(a,b,c)
deallocate(a)deallocate(b)deallocate(c)
end program main
CPUプログラム(メモリの動的確保)
GPGPU講習会102 2016/01/13
vectoradd_allocate.f90
module vectoradd_kernelimplicit noneinteger,parameter :: N=2**20contains
attributes(global)&subroutine add(a, b, c)
implicit none
real :: a(N)real :: b(N)real :: c(N)
integer :: i
do i=1,Nc(i) = a(i) + b(i)
end do
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kerneluse cudaforimplicit none
real,allocatable,device :: a(:)real,allocatable,device :: b(:)real,allocatable,device :: c(:)
allocate(a(N)); a=1.0allocate(b(N)); b=2.0allocate(c(N)); c=0.0
call add<<<1,1>>>(a,b,c)
deallocate(a)deallocate(b)deallocate(c)
end program main
GPUプログラム(1スレッド実行版)
GPGPU講習会103 2016/01/13
vectoradd_1thread.cuf
module vectoradd_kernelimplicit noneinteger,parameter :: N=2**20contains
attributes(global)&subroutine add(a, b, c)
implicit none
real :: a(N)real :: b(N)real :: c(N)
integer :: i
do i=1,Nc(i) = a(i) + b(i)
end do
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kerneluse cudaforimplicit none
real,allocatable,device :: a(:)real,allocatable,device :: b(:)real,allocatable,device :: c(:)
allocate(a(N)); a=1.0allocate(b(N)); b=2.0allocate(c(N)); c=0.0
call add<<<1,1>>>(a,b,c)
deallocate(a)deallocate(b)deallocate(c)
end program main
GPUプログラム(1スレッド実行版)
GPGPU講習会104
GPUカーネルの目印
並列実行の度合を指定
2016/01/13
vectoradd_1thread.cuf
device属性を付与
GPUプログラムへの変更
2016/01/13GPGPU講習会105
変更点
変数にdevice属性を付与
変更の理由
2016/01/13GPGPU講習会106
変更点
変数にdevice属性を付与
変更によって実現されること
CPUとGPUのハードウェア制約を回避できる
変更が必要な理由
GPUはPCI‐Exバスを経由してホストと接続されている
GPUはホストと別に独立したメモリを持っている
GPUはホストメモリ(CPU側のメモリ)に直接アクセスできないため,GPUが持っているメモリを利用
実行結果
GPGPU講習会107
実行時間の確認
CUDAの実行環境に組み込まれたプロファイラを利用
環境変数CUDA_PROFILEを1に設定する事で実行時間を測定
使い方
1. 環境変数の設定 $ export CUDA_PROFILE=1
2. プログラムの実行 $ ./a.out
3. プロファイル結果(標準はcuda_profile_0.log)の確認
2016/01/13
実行結果
GPGPU講習会108
プロファイルの一連の流れ
method カーネルや関数(API)の名称
gputime GPU上で処理に要した時間(s単位)
cputime CPUで処理(=カーネル起動)に要した時間
実際の実行時間=cputime+gputime occupancy GPUがどれだけ効率よく利用されているか
‐bash‐3.2$ pgf90 vectoradd_1thread.cuf プログラムをコンパイル‐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 fffff5f0d8759ef8method,gputime,cputime,occupancymethod=[ __pgi_dev_cumemset_4f ] gputime=[ 36.320 ] cputime=[ 16.000 ] occupancy=[ 1.000 ]method=[ __pgi_dev_cumemset_4f ] gputime=[ 35.200 ] cputime=[ 8.000 ] occupancy=[ 1.000 ]method=[ __pgi_dev_cumemset_4f ] gputime=[ 35.104 ] cputime=[ 7.000 ] occupancy=[ 1.000 ]method=[ add ] gputime=[ 206041.375 ] cputime=[ 6.000 ] occupancy=[ 0.021 ]
2016/01/13
実行結果
GPGPU講習会109
計算が正しく行われているかの確認
配列c(:)の値が全て3.0になっていれば正しい
print文を使って表示
大量に画面表示されて煩わしい
GPUのカーネルには実行時間の制限がある
配列c(:)の値の平均を計算
平均が3.0になっていれば正しく実行できているだろうと推察
配列c(:)の平均をGPUで計算するのは難しい
CPUで配列c(:)の平均を計算
CPUはGPUのメモリを直接読み書きできない
CUDA Cでは専用の命令を使ってGPUからCPUへコピー
2016/01/13
CPUとGPUのやりとり
GPGPU講習会
単純なコピーであれば代入演算子(=)が利用可能
配列の全要素に同じ値を代入
配列要素数が同じ配列同士のコピー
コピー可能な方向
CPU→GPU GPU→GPU GPU→CPU
110 2016/01/13
CUDA Fortranの利点の一つ
CUDAでカーネルを作成するときの制限
GPGPU講習会111
利用するデータの場所の把握
データがホストメモリにあるかデバイスメモリにあるか
CPUにあるデータを基にGPUで計算を行う場合
GPUで計算した結果をCPUで確認する場合
転送を明示的に指定
カーネルの引数
値を渡すことができる
GPUのメモリを指すアドレス
CPUのメモリを指すアドレスも渡すことは可能
そのアドレスを基にホスト側のメモリを参照することは不可能
2016/01/13
module vectoradd_kernelimplicit noneinteger,parameter :: N=2**20contains
attributes(global) &subroutine add(a, x, b, y, c)
implicit nonereal :: a(N)real :: b(N)real :: c(N)real,value :: x,y !値渡しinteger :: ido i=1,N
c(i) = x*a(i) + y*b(i)end do
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kernel
use cudaforimplicit nonereal,allocatable,device :: a(:)real,allocatable,device :: b(:)real,allocatable,device :: c(:)real,allocatable :: host_c(:)allocate(a(N)); a=1.0allocate(b(N)); b=2.0allocate(c(N)); c=0.0allocate(host_c(N))
call add<<<1,1>>>(a,1.0,b,2.0,c)host_c = cprint *,sum(host_c)/N
deallocate(a)deallocate(b)deallocate(c)deallocate(host_c)
end program main
GPUプログラム(双方向コピー)
GPGPU講習会
vectoradd_1thread_copy.cuf112 2016/01/13
CUDAでカーネルを作成するときの制限
GPGPU講習会113
x,yはCPU側のメモリに存在
値渡し
CPU→GPUへ値がコピーされる
Fortranはポインタ渡し
値渡しにする場合はvalue属性を付ける
attributes(global) &subroutine add(a, x, b, y, c)
implicit nonereal :: a(N)real :: b(N)real :: c(N)real,value :: x,y !値渡しinteger :: ido i=1,N
c(i) = x*a(i) + y*b(i)end do
end subroutine add:
program main:call add<<<1,1>>>(a,1.0,b,2.0,c):
end program main
2016/01/13
GPUで並列に処理を行うには
GPUは低性能の演算器(CUDAコア)を多数搭載
マルチスレッドで並列処理することで高い性能を達成
どのように並列処理を記述するか?
関数呼出の際に関数名と引数の間に<<<1,1>>>を付けた
GPUには数百から数千のCUDAコアが搭載されており,それらが協調して並列処理を実行
1スレッドが実行する処理を書くことでカーネルの作成を簡略化
並列処理の度合いはカーネル呼出の際に指定する
GPGPU講習会114 2016/01/13
GPUで並列に処理を行うには
配列サイズN=8 総スレッド数を8として並列実行する状況を想定
GPGPU講習会115
c(i)
a(i)
b(i)
+ + + + + + + +
i= 1 2 3 4 5 6 7 8
2016/01/13
GPUによる並列化の方針
doループをスレッドの数だけ分割
各スレッドが少量のデータを処理
i=1c(i) = a(i) + b(i)スレッド1
c(i)
a(i)
b(i)
+ + + +
スレッド
1スレッド
3スレッド
2スレッド
4
i=2c(i) = a(i) + b(i)スレッド2
i=3c(i) = a(i) + b(i)スレッド3
i=4c(i) = a(i) + b(i)スレッド4
スレッドの番号に応じて決定
1スレッドが実行する処理
GPGPU講習会116 2016/01/13
カーネルの書き換え
1スレッドが実行する処理になるよう変更
1スレッドがある添字 i の要素を担当
integer,parameter :: N=8
attributes(global) subroutine add(a, b, c)real :: a(N)real :: b(N)real :: c(N)integer :: ii = ...c(i) = a(i) + b(i)
end subroutine add
GPGPU講習会117
1スレッドがあるiの担当となり,変数の初期化と足し算の計算を実行
2016/01/13
カーネルの書き換え
1スレッドが実行する処理になるよう変更
どのようにiを決定するか?
integer,parameter :: N=8
attributes(global) subroutine add(a, b, c)real :: a(N)real :: b(N)real :: c(N)integer :: ii = 1c(i) = a(i) + b(i)
end subroutine add
全てのスレッドがi=1の要素を計算してしまう
GPGPU講習会118 2016/01/13
GPUの並列化の階層
GPUのハードウェアの構成に対応させて並列性を管理
並列化の各階層における情報を利用
GPU
Streaming Multiprocessor
CUDA Core
ハードウェア構成
並列に実行する処理
スレッドの集まり
スレッド
並列化の階層
Grid
Block
Thread
CUDA
GPGPU講習会119 2016/01/13
GPUの並列化の階層
グリッド-ブロック-スレッドの3階層
各階層の情報を参照できる変数 x,y,zを成分(component)にもつdim3派生型
グリッド(Grid) gridDim グリッド内にあるブロックの数
ブロック(Block) blockIdx ブロックに割り当てられた番号
blockDim ブロック内にあるスレッドの数
スレッド(Thread) threadIdx スレッドに割り当てられた番号
GPGPU講習会120 2016/01/13
Hello Threads(Fermi世代以降)
<<< , >>>内の数字で表示される内容が変化
2016/01/13GPGPU講習会121
module cuf_kernelimplicit nonecontains
attributes(global) subroutine hello()print *,"gridDim'%'x",gridDim%x,"blockIdx'%'x",blockIdx%x,&
"blockDim'%'x",blockDim%x,"threadIdx'%'x",threadIdx%xend subroutine helloend module cuf_kernelprogram main
use cudaforuse cuf_kernelimplicit noneinteger :: statcall hello<<<2,4>>>()stat = cudaThreadSynchronize()
end program main
<<<>>>内の数字を変えると画面表示される内容が変わる<<<>>>内の数字とどのパラメータが対応しているかを確認
・・・
hellothreads.cuf
Hello Threads
2016/01/13GPGPU講習会122
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 1gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 1gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 2gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 3gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 4
各スレッドが異なるiを参照するには
CUDAでは並列化に階層がある
全体の領域(グリッド)をブロックに分割
ブロックの中をスレッドに分割
<<<2, 4>>>
ブロックの数 1ブロックあたりのスレッドの数
ブロックの数×1ブロックあたりのスレッドの数=総スレッド数2 × 4 = 8
GPGPU講習会123
[block] [thread/block] [thread]
2016/01/13
各スレッドが異なるiを参照するには
N=8, <<<2, 4>>>で実行
c(i)
a(i)
b(i)
+ + + + + + + +
gridDim%x=2
blockIdx%x=1 blockIdx%x=2
blockDim%x=4blockDim%x=4threadIdx%x=
1 2 3 4 1 2 3 4
threadIdx%x=
GPGPU講習会124
i= 1 2 3 4 5 6 7 8
2016/01/13
各スレッドが異なるiを参照するには
N=8, <<<2, 4>>>で実行
c(i)
a(i)
b(i)
+ + + + + + + +
gridDim%x=2
blockIdx%x=1 blockIdx%x=2
blockDim%x=4blockDim%x=4threadIdx%x=
1 2 3 4 1 2 3 4
threadIdx%x=
GPGPU講習会125
i= 1 2 3 4 5 6 7 8
2016/01/13
= (blockIdx%x‐1)*blockDim%x + threadIdx%x
各スレッドが異なるiを参照するには
N=8, <<<1, 8>>>で実行
+ + + + + + + +
gridDim%x=1
blockIdx%x=1
blockDim%x=8threadIdx%x=
1 2 3 4 5 6 7 8
= (blockIdx%x‐1)*blockDim%x + threadIdx%x
2016/01/13GPGPU講習会126
c(i)
a(i)
b(i)
i= 1 2 3 4 5 6 7 8
各スレッドが異なるiを参照するには
N=8, <<<4, 2>>>で実行
+ + + + + + + +
gridDim%x=4
blockIdx%x=1
blockDim%x=2threadIdx%x=
1 2 1 2 1 2 1 2
2016/01/13GPGPU講習会127
blockIdx%x=2
blockDim%x=2
blockIdx%x=3
blockDim%x=2
blockIdx%x=4
blockDim%x=2
= (blockIdx%x‐1)*blockDim%x + threadIdx%x
c(i)
a(i)
b(i)
i= 1 2 3 4 5 6 7 8
カーネルの書き換え
1スレッドが実行する処理になるよう変更
1スレッドがある添字 i の要素を担当
integer,parameter :: N=8
attributes(global) subroutine add(a, b, c)real :: a(N)real :: b(N)real :: c(N)integer :: ii = (blockIdx%x‐1)*blockDim%x + threadIdx%xc(i) = a(i) + b(i)
end subroutine add
GPGPU講習会128 2016/01/13
module vectoradd_kernelimplicit noneinteger,parameter :: N=2**20contains
attributes(global)&subroutine add(a, b, c)
implicit none
real :: a(N)real :: b(N)real :: c(N)integer :: ii = (blockIdx%x‐1)*blockDim%x&
+ threadIdx%xc(i) = a(i) + b(i)
end subroutine addend module vectoradd_kernel
program main
use vectoradd_kerneluse cudaforimplicit none
real,allocatable,device :: a(:)real,allocatable,device :: b(:)real,allocatable,device :: c(:)
allocate(a(N)); a=1.0allocate(b(N)); b=2.0allocate(c(N)); c=0.0
call add<<<N/256,256>>>(a,b,c)
deallocate(a)deallocate(b)deallocate(c)
end program main
GPUで並列実行するプログラム
GPGPU講習会
vectoradd.cuf
129 2016/01/13
処理時間の比較
配列の要素数 N=220
1ブロックあたりのスレッド数 256
GPUはマルチスレッドで処理しないと遅い GPUを使えばどのような問題でも速くなるわけではない
並列に処理できるようプログラムを作成する必要がある
implementation Processing time [ms]
CPU (1 Thread) 4.55
GPU (1 Thread) 206
GPU (256 Threads) 0.115
GPGPU講習会130 2016/01/13
各階層の値の設定
設定の条件
GPUの世代によって設定できる上限値が変化
確認の方法
pgaccelinfo deviceQuery
GPU Computing SDKに含まれているサンプル
CUDA Programming Guide https://docs.nvidia.com/cuda/cuda‐c‐programming‐guide/#compute‐capabilities
階層の値によって実行時の性能が変化
GPUの一番基本的なチューニング
2016/01/13GPGPU講習会131
pgaccelinfoの実行結果Device Number: 0Device Name: Tesla M2050Device Revision Number: 2.0Global Memory Size: 2817982464Number of Multiprocessors: 14Number of Cores: 448Concurrent Copy and Execution: YesTotal Constant Memory: 65536Total Shared Memory per Block: 49152Registers per Block: 32768Warp Size: 32Maximum Threads per Block: 1024Maximum Block Dimensions: 1024, 1024, 64Maximum Grid Dimensions: 65535 x 65535 x 65535Maximum Memory Pitch: 2147483647BTexture Alignment: 512BClock Rate: 1147 MHzInitialization time: 4222411 microsecondsCurrent free memory: 2746736640Upload time (4MB): 2175 microseconds ( 829 ms pinned)Download time: 2062 microseconds ( 774 ms pinned)Upload bandwidth: 1928 MB/sec (5059 MB/sec pinned)Download bandwidth: 2034 MB/sec (5418 MB/sec pinned)
2016/01/13GPGPU講習会132
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)など
2016/01/13GPGPU講習会133
NB,NTをparameterとして定義,変更して実行module vectoradd_kernel
implicit noneinteger,parameter :: N=2**20integer,parameter :: NT=256integer,parameter :: NB=(N/NT)contains
attributes(global) &subroutine add(a, b, c)
implicit nonereal :: a(N)real :: b(N)real :: c(N)integer :: ii = (blockIdx%x‐1)*blockDim%x &
+ threadIdx%xc(i) = a(i) + b(i)
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kerneluse cudaforimplicit nonereal,allocatable,device :: a(:)real,allocatable,device :: b(:)real,allocatable,device :: c(:)allocate(a(N)); a=1.0allocate(b(N)); b=2.0allocate(c(N)); c=0.0
call add<<<NB,NT>>>(a,b,c)
deallocate(a)deallocate(b)deallocate(c)
end program main
並列度の変更によるチューニング
GPGPU講習会134
vectoradd_param.cu
2016/01/13
性能比較
2016/01/13GPGPU講習会135
1ブロックあたりのスレッド数が増加すると性能が向上
スレッド数を多くしすぎると性能が低下
CUDA CとCUDA Fortranで同じ傾向を示す
スレッド数が多いほど処理時間は短いが,多すぎると遅くなる
Number of Threads/Block
Processing time [ms]C Fortran
32 0.276 0.28064 0.169 0.170128 0.128 0.130256 0.119 0.116512 0.120 0.1171024 0.151 0.146
ベクトル和C=A+B(2次元版)
2016/01/13GPGPU講習会136
1次元のベクトル和とほぼ同じ
並列化が容易
do文の書く順番で実行速度が変化
c(:,:) a(:,:) b(:,:)
module vectoradd_kernelimplicit noneinteger,parameter :: Nx=2**10integer,parameter :: Ny=2**10contains
subroutine add(a, b, c)implicit none
real :: a(Nx,Ny)real :: b(Nx,Ny)real :: c(Nx,Ny)
integer :: i,j//iとjのループを入れ替えるとどうなるか?do j=1,Nydo i=1,Nx
c(i,j) = a(i,j) + b(i,j)end doend do
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kernelimplicit none
real :: a(Nx,Ny)real :: b(Nx,Ny)real :: c(Nx,Ny)
a=1.0b=2.0c=0.0
call add(a,b,c)
print *,sum(c)/(Nx*Ny)end program main
ベクトル和(2次元版)
2016/01/13GPGPU講習会137
vectoradd2d.f90
2次元配列の1次元配列表現
2016/01/13GPGPU講習会138
アドレス空間は1次元
2次元配列でも1次元のアドレスで表現
1次元目が連続か,2次元目が連続かが言語によって異なる
Fortranは1次元目が連続
j
i
j
i1次元目が連続
a(Nx,Ny) a(Nx,Ny)
2次元目が連続
GPUによる2次元的な並列処理
2016/01/13GPGPU講習会139
ブロックとスレッドを2次元的に設定
1スレッドが配列の1要素(画像の1ピクセル)を処理
スレッドを2次元的に配置してブロックを構成
GPUの並列化の階層
グリッド-ブロック-スレッドの3階層
各階層の情報を参照できる変数 x,y,zを成分(component)にもつdim3派生型
グリッド(Grid) gridDim グリッド内にあるブロックの数
ブロック(Block) blockIdx ブロックに割り当てられた番号
blockDim ブロック内にあるスレッドの数
スレッド(Thread) threadIdx スレッドに割り当てられた番号
GPGPU講習会140 2016/01/13
Hello Threads(2次元版)
<<< , >>>の中にどのように数字を書くか
2016/01/13GPGPU講習会141
module cuf_kernelimplicit nonecontains
attributes(global) subroutine hello()print *,"gridDim'%'x=", gridDim%x, "blockIdx'%'x=", blockIdx%x,&
"blockDim'%'x=",blockDim%x,"threadIdx'%'x=", threadIdx%xprint *,"gridDim'%'y=", gridDim%y, "blockIdx'%'y=", blockIdx%y,&
"blockDim'%'y=",blockDim%y,"threadIdx'%'y=", threadIdx%yend subroutine helloend module cuf_kernelprogram main
use cudaforuse cuf_kernelimplicit noneinteger :: statcall hello<<<?,?>>>()stat = cudaThreadSynchronize()
end program mainhellothreads2d.cu
Hello Threads(2次元版)
1次元と同様<<<2,4>>>等として実行
実行結果(画面出力)
2016/01/13GPGPU講習会142
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 1gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 1gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 2gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 3gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 4gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
並列度の指定が
できていない
2次元的な並列度の指定
2016/01/13GPGPU講習会143
<<<,>>>の中にどのように数字を書くか
1次元の場合は数字を書くことができた
2次元,3次元は数字を並べて書くことができない
dim3派生型を利用
type(dim3) block=dim3(2,4,1)type(dim3) thread=dim3(4,2,1);call hello<<<block, thread>>>()
call hello<<<dim3(2,4,1), dim3(4,2,1)>>>()
dim3型変数block, threadを利用
・・・
あるいは直接dim3派生型として記述・・・
Hello Threads(2次元版)
実行結果(画面出力)
2016/01/13GPGPU講習会144
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 1gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 1gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4:(中略)gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 2gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 2gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 2gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 2:
対応
対応
各スレッドが異なるi,jを参照するには
CUDAでは並列化に階層がある
全体の領域(グリッド)をブロックに分割
ブロックの中をスレッドに分割
<<<dim3(2,4,1), dim3(4,2,1)>>>
ブロックの数 1ブロックあたりのスレッドの数
x方向ブロック数×1ブロックあたりのスレッドの数×y方向ブロック数×1ブロックあたりのスレッドの数=総スレッド数
GPGPU講習会145 2016/01/13
総スレッド数=2×4×4×2=64
各スレッドが異なるi,jを参照するには
2016/01/13GPGPU講習会146
Nx=8, Ny=8, x,y方向スレッド数4,ブロック数2 gridDim%x=2, gridDim%y=2 blockDim%x=4,blockDim%y=4
(1,1)(2,1)(3,1)(4,1)(1,1)
(4,4) (4,4)
(1,2)(2,2)(3,2)(4,2)
(1,3)(2,3)(3,3)(4,3)
(1,4)(2,4)(3,4)(4,4) (4,4)
(1,1) (1,1)
threadIdx%x,threadIdx%y
i= 1 2 3 4 5 6 7 8j=
12 3
4 56
7 8・・・
・・・
・・・・・・
・・・
・・・
(1,1)(2,1)(3,1)(4,1)(1,1)
(4,4) (4,4)
(1,2)(2,2)(3,2)(4,2)
(1,3)(2,3)(3,3)(4,3)
(1,4)(2,4)(3,4)(4,4) (4,4)
(1,1) (1,1)
・・・
・・・
・・・・・・
・・・
・・・
各スレッドが異なるi,jを参照するには
2016/01/13GPGPU講習会147
Nx=8, Ny=8, x,y方向スレッド数4,ブロック数2
blockDim%x=4
blockDim%y=4
threadIdx%x,threadIdx%y
blockIdx%x=1 blockIdx%x=2
blockIdx%y=1
blockIdx%y=2
gridDim%x=2gridDim.y=2
(1,1)(2,1)(3,1)(4,1)(1,1)
(4,4) (4,4)
(1,2)(2,2)(3,2)(4,2)
(1,3)(2,3)(3,3)(4,3)
(1,4)(2,4)(3,4)(4,4) (4,4)
(1,1) (1,1)
・・・
・・・
・・・・・・
・・・
・・・
各スレッドが異なるi,jを参照するには
2016/01/13GPGPU講習会148
Nx=8, Ny=8, x,y方向スレッド数4,ブロック数2 i = (blockIdx%x‐1)*blockDim%x + threadIdx%x j = (blockIdx%y‐1)*blockDim%y + threadIdx%y
block(1,1) block(2,1)
block(1,2) block(2,2)
threadIdx%x,threadIdx%y
i= 1 2 3 4 5 6 7 8j=
12 3
4 56
7 8
module vectoradd_kernelimplicit noneinteger,parameter :: Nx=2**10integer,parameter :: Ny=2**10integer,parameter :: NTx=16integer,parameter :: NTy=16integer,parameter :: NBx=(Nx/NTx)integer,parameter :: NBy=(Ny/NTy)contains
attributes(global) subroutine add(a, b, c)implicit none
real :: a(Nx,Ny)real :: b(Nx,Ny)real :: c(Nx,Ny)integer :: i,ji=(blockIdx%x‐1)*blockDim%x+threadIdx%xj=(blockIdx%y‐1)*blockDim%y+threadIdx%yc(i,j) = a(i,j) + b(i,j)
end subroutine addend module vectoradd_kernel
program mainuse vectoradd_kerneluse cudaforimplicit nonereal,allocatable,device :: a(:,:)real,allocatable,device :: b(:,:)real,allocatable,device :: c(:,:)type(dim3) :: thread=dim3(NTx,NTy,1)type(dim3) :: block=dim3(NBx,NBy,1)allocate(a(Nx,Ny)); a=1.0allocate(b(Nx,Ny)); b=2.0allocate(c(Nx,Ny)); c=0.0
call add<<<block, thread>>>(a,b,c)
deallocate(a)deallocate(b)deallocate(c)
end program main
ベクトル和(2次元並列版)
2016/01/13GPGPU講習会149
vectoradd2d.cuf
実行結果
GPGPU講習会150
2次元版
カーネル スレッド数 実行時間[s]add 16×16(=256) 155
2016/01/13
# CUDA_PROFILE_LOG_VERSION 2.0# CUDA_DEVICE 0 Tesla M2050# TIMESTAMPFACTOR fffff5f14d408b28method,gputime,cputime,occupancy:method=[ add ] gputime=[ 154.976 ] cputime=[ 6.000 ] occupancy=[ 1.000 ]
実行結果
GPGPU講習会151
1次元版(vectoradd.cuf)
カーネル スレッド数 実行時間[s]add 256 113
# CUDA_PROFILE_LOG_VERSION 2.0# CUDA_DEVICE 0 Tesla M2050# TIMESTAMPFACTOR fffff5f0d1572620method,gputime,cputime,occupancy:method=[ add ] gputime=[ 114.816 ] cputime=[ 6.000 ] occupancy=[ 1.000 ]
2016/01/13
ベクトル和(2次元並列版)の実行結果
GPGPU講習会152
実行結果
1次元版と比較して実行時間がかかる
遅くなる要因は?
2次元は添字iだけでなくjも計算
添字の計算負荷は軽い
実行時の並列度の指定
2016/01/13
ベクトル和(2次元並列版)の実行結果
GPGPU講習会153
x,y方向スレッド数による実行時間の変化
1ブロックあたりのスレッド数を256に固定
2016/01/13
スレッド数 実行時間[s]1×256 11362×128 6014× 64 3418× 32 213
16× 16 15532× 8 11964× 4 135
128× 2 121256× 1 116
1次元の場合とほぼ同じ
GPUのメモリ階層
長岡技術科学大学 電気電子情報工学専攻 出川智啓
GPUの主要部品
GPGPU講習会
基盤
画面出力端子
電源入力端子
GPU(チップ)+冷却部品
メモリ
特性の把握が重要
http://www.geforce.com/whats‐new/articles /introducing‐the‐geforce‐gtx‐780に公開されている写真を基に作成
画面出力端子
PCI‐Ex端子
電源入力端子
メモリ
チップ
155 2016/01/13
CPUのメモリ階層
GPGPU講習会
オフチップ(off‐chip)メモリ
CPUのチップ外部に置かれたメモリ
メインメモリ(主記憶)
利用可能なメモリの中で 低速, 大容量
オンチップ(on‐chip)メモリ
CPUのチップ内部に置かれたメモリ
レジスタ
レベル1(L1)キャッシュ
レベル2(L2)キャッシュ
レベル2(L3)キャッシュ
156
高速,容量小
低速,容量大
2016/01/13
GPUのメモリ階層
GPGPU講習会
オフチップメモリ
PCI‐Exカードの基板上に実装
ビデオメモリ
利用可能なメモリの中で 低速, 大容量
オンチップメモリ
GPUのチップ内部に置かれたメモリ
レジスタ
レベル1(L1)キャッシュ
レベル2(L2)キャッシュ
CPUの構造に類似
157
高速,容量小
低速,容量大
2016/01/13
GPUメモリの独自の特徴
GPGPU講習会
CPUとは異なるメモリを複数搭載
各メモリの特徴を知り,適材適所で利用する事により高速化
GPUから読み書き可能か
処理を行うスレッドから読み書き可能か,読み込みのみか
複数のスレッドでデータを共有できるか
CPUから読み書き可能か
C言語の機能のみで直接読み書きは不可能
CUDAの専用関数(API)を利用して読み書き
158 2016/01/13
メモリの階層
GPGPU講習会
CPUのメモリ階層
コアごとにL2キャッシュ,全体でL3キャッシュを持つこともある
メインメモリ
L2キャッシュ
・・・
・・・
チップ
159
コア
L1キャッシュ
演算器
レジスタ レジスタ
演算器
L1キャッシュ
演算器
レジスタ レジスタ
演算器
L1キャッシュ
演算器
レジスタ レジスタ
演算器
コア コア
2016/01/13
メモリの階層
GPGPU講習会
GPUのメモリ階層
CPUにはない独自のメモリを複数持つ
グローバルメモリ
L2キャッシュ
L1キャッシュ 共有メモリ
CUDA Core
レジスタ
チップ
テクスチャメモリ
コンスタントメモリ
ローカルメモリ
テクスチャキャッシュ
コンスタントキャッシュ
160 2016/01/13
メモリの種類
オンチップメモリ(GPUのチップ内部に置かれたメモリ)
高速アクセス,小容量
CPUからはアクセス不可
L1キャッシュと共有メモリは一定サイズを共用
GPGPU講習会161
L1キャッシュ/共有(シェアード)メモリ
レジスタ
容量 小 小
速度 高速 高速
GPUからの読み書き
読み書き可ブロック内の全スレッドが同じメモリにアクセス(データを共有する)ことが可
能*
読み書き可各スレッドが異なるアドレス
にアクセス
CPUからのアクセス
読み書き不可 読み書き不可
2016/01/13
*同じメモリ,異
なるメモリについては後ろのスライドで説明
メモリの種類
オフチップメモリ(GPUのチップ外部に置かれたメモリ)
低速アクセス,大容量
CPUから直接アクセス可能
ローカルメモリだけはアクセス不可
GPGPU講習会162
グローバルメモリ ローカルメモリ テクスチャメモリ コンスタントメモリ
容量 大 小 大 小
速度 低速 低速 高速*1 高速*1
GPUからの読み書き
読み書き可全てのスレッドが同じメモリにアクセス可能*2
読み書き可各スレッドが異なるメモリにアクセス*2
読み込み可全てのスレッドが同じメモリにアクセス可能*2
読み込み可全てのスレッドが同じメモリにアクセス*2
CPUからのアクセス
読み書き可 読み書き不可 読み書き可 読み書き可
2016/01/13
*1キャッシュが効く場合*2同じメモリ,異なるメモリについては後ろのスライドで説明
同じメモリ
2016/01/13GPGPU講習会163
複数のスレッドがメモリアドレスを共有
複数のスレッドが変数を共有
他のスレッドが書き込んだデータを読むことが可能
共有できるスレッドの範囲はメモリの種類によって変化
!a,b()がグローバルメモリに確保されている場合*1
attributes(global) subroutine kernel(...)integer ii=blockIdx%x*blockDim%x + threadIdx%xb(i) = i !スレッドiが配列bのi番目に自身のスレッド番号を代入
!b(1,2,...,i‐1,i,...)の値は1,2,...,i‐1,i,...a = b(i‐1)*2 !スレッドi‐1が書き込んだ値を読み*3,aに代入: ! 後に書き込まれたaの値を全スレッドが共有
end subroutine *1 あくまで動作のイメージを説明するための例で正しく実行できない*2 iが1の場合は考えない*3 配列bを全スレッドが共有しているので,書き込んだ値以外を読む事が可能
異なるメモリ
2016/01/13GPGPU講習会164
メモリアドレスが共有できず,一つのスレッドのみがそのメモリアドレスにアクセス
あるスレッドが宣言した変数へアクセスできない
!a,b()がレジスタに確保されている場合*1
attributes(global) subroutine kernel(...)integer ii=blockIdx%x*blockDim%x + threadIdx%xb(i) = i !スレッドiが配列bのi番目に自身のスレッド番号を代入
!b(1,2,...,i‐1,i,...)の値はb(i)以外不定a = b(i‐1)*2 !b(i‐1)の値(不定)をaに代入*3
: !aの値はスレッドによって異なるend subroutine *1 あくまで動作のイメージを説明するための例で正しく実行できない
*2 iが1の場合は考えない*3 配列bは他のスレッドからアクセスできないため,代入した値以外は不定のまま
Tesla世代
L1,L2キャッシュなし
テクスチャキャッシュ,コンスタントキャッシュは利用可能
高速なメモリの活用が重要
共有メモリ
レジスタ
メモリの種類
2016/01/13GPGPU講習会165
オフチップメモリ
オンチップメモリホストメモリ
コンスタントメモリ
テクスチャメモリ
GPUChip
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
共有メモリ
SM
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
共有メモリ
SM
グローバルメモリ ローカルメモリ
ローカルメモリ ・・・
Fermi世代以降
共有メモリとL1キャッシュが一体で利用可能
グローバルメモリへのアクセスはL2キャッシュ経由
Fermi世代では標準でL1キャッシュも有効化*
メモリの種類
2016/01/13GPGPU講習会166
オフチップメモリ
オンチップメモリホストメモリ
L2キャッシュ
コンスタントメモリ
テクスチャメモリ
GPUChip
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
L1キャッシュ
共有メモリ
SM
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
L1キャッシュ
共有メモリ
SM
グローバルメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
・・・
・・・
*Kepler世代では標準でL1キャッシュが無効化
メモリの種類と並列化階層の対応
オンチップメモリ
ブロックまたはスレッドごとに異なる値を持つ
ローカルメモリはレジスタが不足した時に使われる
オフチップメモリ
GPU全体で共通の値を持つ
2016/01/13GPGPU講習会167
各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)
グローバルメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
・・・
・・・
ホストメモリ
レジスタ
各スレッドが個別に利用
カーネル内で変数を宣言するとレジスタを利用
非常に高速
キャッシュとしても利用可能
2016/01/13GPGPU講習会168*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
ホストメモリ
L2キャッシュ
コンスタントメモリ
テクスチャメモリ
GPU
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
L1キャッシュ
共有メモリ
SM
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
L1キャッシュ
共有メモリ
SM
グローバルメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
・・・
・・・
グローバルメモリ
ビデオメモリ(数GB) CPUのメインメモリに相当
読み込みがある一定サイズでまとめて行われる
レイテンシが大きい
効率よくアクセスするための条件がある
コアレスアクセス
アラインアクセス
2016/01/13GPGPU講習会169
Tesla世代ではコアレスアクセスの条件にメモリのアラインが含まれている
Chip
ホストメモリ
グローバルメモリへのアクセス(Tesla世代)
16スレッドが協調して同時にアクセス
1 Warp = 32スレッド
Warpの半分(Half Warp,16スレッド)が協調して処理を実行
コアレスアクセスか否かで読み込みの速度が変化
新しい世代のGPUでは,コアレスアクセスになる条件やコアレスアクセスできないときの速度の落ち込みが緩和
コアレスアクセスはGPUのプログラムで 重要
GPUの処理能力と比較するとデータ供給が不足しがち
極力データ供給不足が生じないようプログラムを作成
2016/01/13GPGPU講習会170
コアレスアクセスになる条件(Tesla世代)
データのサイズ
32bit, 64bit, 128bit(4byte, 8byte, 16byte)
アドレスの隣接
16スレッドがアクセスするアドレスがスレッド番号順に隣接
スレッド番号順にデータサイズ分ずつアドレスが増加
アクセスする 初のアドレス
16スレッドがアクセスするアドレスの先頭が,64byteまたは128byteの倍数
2016/01/13GPGPU講習会171
コアレスアクセスの例*
(Tesla世代)
データ型が32bit=4byte
各スレッドが連続して隣接アドレスにアクセス
先頭アドレスが128バイト境界
16スレッド
データ型が32bit=4byte
各スレッドが連続して隣接アドレスにアクセス
実際にデータを取得するかは無関係
先頭アドレスが128バイト境界
T15
T14
T13
T12
T11
T10
T9
T8
T7
T6
T5
T4
T3
T2
A188
A184
A180
A176
A172
A168
A164
A160
A156
A152
A148
A144
A140
A136
T1 A132
T0 A128
T15
T14
T13
T12
T11
T10
T9
T8
T7
T6
T5
T4
T3
T2
A188
A184
A180
A176
A172
A168
A164
A160
A156
A152
A148
A144
A140
A136
T1 A132
T0 A128
2016/01/13GPGPU講習会172
*CUDA Programming Guide
メモリアドレスに対するスレッドのアクセス要求
T15
T14
T13
T12
T11
T10
T9
T8
T7
T6
T5
T4
T3
T2
A188
A184
A180
A176
A172
A168
A164
A160
A156
A152
A148
A144
A140
A136
T1 A132
T0 A128
T15
T14
T13
T12
T11
T10
T9
T8
T7
T6
T5
T4
T3
T2
A188
A184
A180
A176
A172
A168
A164
A160
A156
A152
A148
A144
A140
A136
T1 A132
T0 A128
T15
T14
T13
T12
T11
T10
T9
T8
T7
T6
T5
T4
T3
T2
A188
A184
A180
A176
A172
A168
A164
A160
A156
A152
A148
A144
A140
A136
T1 A132
T0 A128
T15
T14
T13
T12
T11
T10
T9
T8
T7
T6
T5
T4
T3
T2
A188
A184
A180
A176
A172
A168
A164
A160
A156
A152
A148
A144
A140
A136
T1 A132
T0 A128
コアレスアクセスにならない例(Tesla世代)
2016/01/13GPGPU講習会173
・・・
各スレッドが番号順にアクセス
していない
先頭が128バイト境界ではない
アドレスが連続していない
データが32bit, 64bit, 128bit
ではない
コアレスアクセスにならない例(Tesla世代)
2016/01/13GPGPU講習会174
128バイト境界からわずかにずれている場合
Tesla世代以降は64バイトブロックと32バイトブロックに分けて読込
メモリアクセス要求は2回
コアレスアクセスの半分程度の性能は得られる
A190
64バイトブロック
でデータ読込
32バイトブロック
でデータ読込
T15
T14
T13
T12
T11
T10
T9
T8
T7
T6
T5
T4
T3
T2
A188
A184
A180
A176
A172
A168
A164
A160
A156
A152
A148
A144
A140
A136
T1 A132
T0 A128
グローバルメモリへのアクセス(Fermi世代)
2016/01/13GPGPU講習会175
Tesla世代のGPU グローバルメモリへのアクセスに強い制約があった
以前のGPUよりは改善
Fermi世代以降のGPU Tesla世代のGPUから大幅に改善
効率のよいアクセスの条件
コアレスアクセス+アラインアクセス
L1キャッシュの利用状況によっても変化
グローバルメモリからの読込(Fermi世代)
2016/01/13GPGPU講習会176
メモリ操作の命令はWarpごとに発行
1 Warp内の32スレッドが協調
各スレッドのメモリアクセス要求を一つに集約
メモリアクセス要求の処理
128バイトもしくは32バイト単位
すべてL2キャッシュを通過
アーキテクチャによってはL1キャッシュも通過
L1キャッシュの使用はコンパイルオプションで設定可能
Fermi世代は標準でL1キャッシュが有効化
Kepler世代は標準でL1キャッシュが無効化
グローバルメモリからの読込(Fermi世代)
2016/01/13GPGPU講習会177
コアレスメモリアクセス(coalesce access) メモリアドレスの連続性に着目
1 Warp内の32スレッドが隣り合ったメモリにアクセス
データサイズが4バイトの時,スレッド1がアクセスするメモリアドレスはスレッド0がアクセスするメモリアドレス+4
アラインメモリアクセス(align access) メモリの配置に着目
Warpがアクセスするデータの先頭アドレスがキャッシュ粒度の倍数
L2キャッシュのみを使う場合は32バイトの倍数
L1キャッシュも使う場合は128バイトの倍数
メモリ読込の例
2016/01/13GPGPU講習会178
アライン/コアレスアクセス
ミスアライン/コアレスアクセス
0 16
32
48
64
80
96
112
128
144
160
176
192
208
224
240
256
272
288
304
320
336
352
358
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
012345678910111213141516171819202122232425262728293031
メモリアドレスに対するスレッドのアクセス要求
Warp内でのスレッドID(カーネル内でのスレッド番号とは異なる)
メモリアドレス
メモリ読込の例
2016/01/13GPGPU講習会179
アライン/アンコアレスアクセス
ミスアライン/アンコアレスアクセス
0 16
32
48
64
80
96
112
128
144
160
176
192
208
224
240
256
272
288
304
320
336
352
358
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
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
012345678910111213141516171819202122232425262728293031
メモリアドレスに対するスレッドのアクセス要求
キャッシュされる読込
2016/01/13GPGPU講習会180
L1キャッシュとL2キャッシュを通過
読込は128バイト単位で実行
L1キャッシュのキャッシュラインのサイズで実行
読込の評価に利用する用語
メモリトランザクション
メモリのアクセス要求に対して排他的にメモリにアクセスして行う処理の単位
バスの利用率
必要なデータサイズ/読込完了に必要な読込データサイズ
アライン/コアレスアクセス
Warp内の全スレッドが要求するメモリアドレスが128バイトの範囲内
全スレッドが隣り合ったメモリにアクセス
先頭データのメモリアドレスが128バイトの倍数
読込に必要な128バイトのトランザクションは一つ
読み込んだデータ全てを利用
バスの利用率は128/128=100%
0 16
32
48
64
80
96
112
キャッシュされる読込の例
2016/01/13GPGPU講習会181
128
144
160
176
192
208
224
240
012345678910111213141516171819202122232425262728293031
256
272
288
304
320
336
352
358
Warp内でのスレッドID(カーネル内でのスレッド番号とは異なる)
メモリアドレス
メモリアドレスに対するスレッドのアクセス要求
読込に必要な128バイトトランザクション
128バイトのキャッシュライン読み込むデータ
キャッシュされる読込の例
2016/01/13GPGPU講習会182
アライン/アンコアレスアクセス
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
キャッシュされる読込の例
2016/01/13GPGPU講習会183
ミスアライン/コアレスアクセス
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
キャッシュされる読込の例
2016/01/13GPGPU講習会184
ミスアライン/コアレスアクセス
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
キャッシュされる読込の例
2016/01/13GPGPU講習会185
ミスアライン/コアレスアクセス
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
キャッシュされない読込
2016/01/13GPGPU講習会186
L1キャッシュを無効化
L2キャッシュのみを通過
読込は32バイト単位で実行
メモリセグメントのサイズで実行
細かい単位で実行されるため,ミスアライン・アンコアレスメモリアクセスのパフォーマンスが改善される可能性がある
セグメント
メモリの管理方式の一つ
まとまった大きさで管理されたメモリ空間
アライン/コアレスアクセス
Warp内の全スレッドが要求するメモリアドレスが128バイト(四つのセグメントに収まる)
全スレッドが隣り合ったメモリにアクセス
先頭データのメモリアドレスが32バイトの倍数
読込に必要な32バイトのトランザクションは四つ
読み込んだデータ全てを利用
バスの利用率は128/(32×4)=100%
キャッシュされない読込の例
2016/01/13GPGPU講習会187
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バイトのメモリセグメント読み込むデータ
キャッシュされない読込の例
2016/01/13GPGPU講習会188
アライン/アンコアレスアクセス
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
キャッシュされない読込の例
2016/01/13GPGPU講習会189
ミスアライン/コアレスアクセス
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
キャッシュされない読込の例
2016/01/13GPGPU講習会190
ミスアライン/アンコアレスアクセス
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
キャッシュされない読込の例
2016/01/13GPGPU講習会191
ミスアライン/アンコアレスアクセス
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
メモリの種類
オンチップメモリ(GPUのチップ内部に置かれたメモリ)
高速アクセス,小容量
CPUからはアクセス不可
L1キャッシュと共有メモリは一定サイズを共用
GPGPU講習会192
L1キャッシュ/共有(シェアード)メモリ
レジスタ
容量 小 小
速度 高速 高速
GPUからの読み書き
読み書き可ブロック内の全スレッドが同じアドレスにアクセス(データを共有する)ことが
可能*
読み書き可各スレッドが異なるレジスタ
にアクセス
CPUからのアクセス
読み書き不可 読み書き不可
*スレッドごとに
異なるアドレスにアクセスすることも可能
2016/01/13
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倍
2016/01/13GPGPU講習会193
Fermi世代以前のGPUでマネージドキャッシュとして利用
1ブロックあたり16,32*,48kB
*Kepler世代から
ホストメモリ
共有(シェアード)メモリの宣言
カーネル内でshared属性を付けて宣言
配列として宣言
配列要素数を静的(コンパイル時)に決定する場合
型,shared 変数名(要素数) 多次元配列も宣言可能
配列要素数を動的(カーネル実行時)に決定する場合
型,shared 変数名(:) サイズはカーネル呼出時のパラメータで指定
<<<ブロック数,スレッド数,共有メモリのバイト数>>>
GPGPU講習会194 2016/01/13
=要素数*共有メモリの型のサイズ
ブロック内でのスレッドの同期
GPGPU講習会
syncthreads() カーネル実行中にスレッドの同期を取る
syncthreads()が書かれた行にスレッドが到達すると,同一ブロック内の他の全てのスレッドがその行に達するまで待機
異なるブロック間での同期は不可能
ifの中に記述するとカーネルが終了しないことがある
195 2016/01/13
if(条件)thencall syncthreads();//条件が真にならないスレッドはifの中に入らないため,//カーネルが永久に終わらない
end if
共有(シェアード)メモリ容量の選択
2016/01/13GPGPU講習会196
共有メモリとL1キャッシュは64kBを共用
どちらを多く利用するかを決定する関数が用意されている
64kB全ての利用は不可能
L1キャッシュ48kB, 共有メモリ16kB cudaDeviceSetCacheConfig(cudaFuncCachePreferL1)
L1キャッシュ16kB, 共有メモリ48kB cudaDeviceSetCacheConfig(cudaFuncCachePreferShared)
L1キャッシュ32kB/共有メモリ32kB* cudaDeviceSetCacheConfig(cudaFuncCachePreferEqual)
*Kepler世代から
共有(シェアード)メモリへのアクセス(Tesla世代)
高速にアクセスするための制約が緩い
16スレッド(Half Warp)単位でアクセス
16個のバンクから構成 32bit=4バイトが1バンク
一つのバンクにアクセスできるのはHalf Warp内の1スレッドのみ 複数のスレッドが一つのバンクに同時にアクセスすると バンクコンフリクト(バンク衝突)が発生
共有メモリへのアクセスが逐次化される
2016/01/13GPGPU講習会197
バンクコンフリクトにならない例(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
2016/01/13GPGPU講習会198
メモリアドレスに対するスレッドのアクセス要求 Half Warp内でのスレッドID
バンク番号
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
2016/01/13GPGPU講習会199
メモリアドレスに対するスレッドのアクセス要求
メモリアドレス
0
23
5
1
6
8
14
4
7
9
15
10111213
バンク番号
バンクコンフリクトする例(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
2016/01/13GPGPU講習会200
メモリアドレスに対するスレッドのアクセス要求
0
23
5
1
6
8
14
4
7
9
15
10111213
バンクコンフリクト
バンクコンフリクト
バンクコンフリクト
バンクコンフリクト
バンクコンフリクト
バンクコンフリクト
バンクコンフリクト
バンクコンフリクト
バンク番号
バンクコンフリクトする例(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
2016/01/13GPGPU講習会201
メモリアドレスに対するスレッドのアクセス要求
0
23
5
1
6
8
14
4
7
9
15
10111213
バンクコンフリクト
バンクコンフリクト
バンク番号
バンクコンフリクトしない例(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
2016/01/13GPGPU講習会202
メモリアドレスに対するスレッドのアクセス要求
0
23
5
1
6
8
14
4
7
9
15
10111213
バンク番号
共有(シェアード)メモリへのアクセス(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バイト
2016/01/13GPGPU講習会203
128
バンクコンフリクトにならないアクセス(Fermi世代)
2016/01/13GPGPU講習会204
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
バンクコンフリクトにならないアクセス(Fermi世代)
2016/01/13GPGPU講習会205
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バンク番号
バンクコンフリクトにならないアクセス(Fermi世代)
2016/01/13GPGPU講習会206
複数のスレッドが一つのバンクの同一アドレスにアクセス
バンクコンフリクトは発生しない
メモリトランザクションが一つ実行され,アクセスした複数のスレッドに値がブロードキャストされる
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バンク番号
バンクコンフリクトになるアクセス(Fermi世代)
2016/01/13GPGPU講習会207
複数のスレッドが一つのバンクの異なるアドレスにアクセス
バンクコンフリクトが発生(下の例では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バンク番号
バンクコンフリクト
バンクコンフリクト
バンクコンフリクト
メモリの種類
オフチップメモリ(GPUのチップ外部に置かれたメモリ)
低速アクセス,大容量
CPUから直接アクセス可能
ローカルメモリだけはアクセス不可
GPGPU講習会208
グローバルメモリ ローカルメモリ テクスチャメモリ コンスタントメモリ
容量 大 小 大 小
速度 低速 低速 高速* 高速*
GPUからの読み書き
読み書き可全てのスレッドが同じメモリにアクセス
読み書き可各スレッドが異なるメモリにアクセス
読み込み可全てのスレッドが同じメモリにアクセス
読み込み可全てのスレッドが同じメモリにアクセス
CPUからのアクセス
読み書き可 読み書き不可 書き込み可 書き込み可
2016/01/13*キャッシュが効く場合
コンスタントメモリ
GPU全体で同じメモリにアクセス
メモリを読み取り専用とすることで値をキャッシュし,一度読んだ値を再利用
2016/01/13GPGPU講習会
GPU全体で64kB
209
L2キャッシュ
コンスタントメモリ
テクスチャメモリ
GPUChip
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
L1キャッシュ
共有メモリ
SM
レジスタ
レジスタ
レジスタ
レジスタ
CUDA Core
CUDA Core
CUDA Core
CUDA Core
L1キャッシュ
共有メモリ
SM
グローバルメモリ
ホストメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
ローカルメモリ
・・・
・・・
コンスタントメモリの宣言
グローバル領域でconstant属性を付けて宣言
配列サイズは静的に決定
型,constant 変数名
型,constant 変数名(要素数) 配列としても宣言可能
サイズはコンパイル時に確定している必要がある
allocate/deallocateは不要
グローバル変数として宣言し,複数のカーネルからアクセスすることが多い
読込専用なので許される
書込可能なメモリでは厳禁
2016/01/13GPGPU講習会210
コンスタントメモリの利用
メモリは読込専用
CPUからは変更可能
グローバルメモリと同様,代入演算子を用いてコピー
CUDA Fortranでは,コンスタントメモリをparameterと同じ感覚で利用できる
あるmodule内で変数を定義
moduleをuseしたカーネル内で読込
2016/01/13GPGPU講習会211
CUDA Fortranの利点の一つ
コンスタントメモリへのアクセス(Tesla世代)
コンスタントメモリへ高速にアクセスできる要因
1. ブロードキャストによるデータの分配
16スレッド(Half Warp)単位でアクセスし,1回の読込を他のスレッドにブロードキャストできる
16スレッドが同じアドレスにアクセスすると も効率がよい
2. コンスタントメモリキャッシュ
SMごとに存在する独自のオンチップキャッシュ
他のHalf Warpがキャッシュされたデータへアクセスしても,コンスタントメモリからの読込が発生しない
2016/01/13GPGPU講習会212
コンスタントメモリへのアクセス(Tesla世代)
オフチップメモリ(DRAM)からの読込量を抑制
オフチップメモリ(DRAM)からの読込による実行速度低下を回避
コンスタントメモリへのアクセスの制約
Half Warp内のスレッド全てが異なるコンスタントメモリのアドレスを参照すると,読込が逐次化
読込命令の処理に 悪で16倍の時間を要する
2016/01/13GPGPU講習会213
コンスタントメモリへのアクセス(Tesla世代)
Half Warp内のスレッド全てが同じメモリアドレスにアクセス
1スレッドの読込をブロードキャストによって残りのスレッドが共有
他のHalf Warpも同じメモリアドレスにアクセス
データがキャッシュされているため,キャッシュから高速に読み出し
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0 0
2016/01/13GPGPU講習会214
Half Warp内でのスレッドID
メモリアドレス
コンスタントメモリへのアクセス(Tesla世代)
Half Warp内のスレッド全てが異なるメモリアドレスにアクセス
読込が逐次化
読込処理の時間は,Half Warpがアクセ
スするコンスタントメモリアドレスの数に比例
悪で処理に16倍の時間がかかる
おそらくグローバルメモリアクセスよりも遅くなる
2016/01/13GPGPU講習会
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
215
コンスタントメモリへのアクセス(Fermi世代)
コンスタントメモリへ高速にアクセスできる要因
1. ブロードキャストによるデータの分配
32スレッド(Warp)単位でアクセスし,1回の読込を他のスレッドにブロードキャストできる
32スレッドが同じアドレスにアクセスすると も効率がよい
2. コンスタントメモリキャッシュ
SMごとに存在する独自のオンチップキャッシュ
他のWarpがキャッシュされたデータへアクセスしても,コンスタントメモリからの読込が発生しない
2016/01/13GPGPU講習会216
コンスタントメモリへのアクセス(Fermi世代)
オフチップメモリ(DRAM)からの読込量を抑制
オフチップメモリ(DRAM)からの読込による実行速度低下を回避
コンスタントメモリへのアクセスの制約
Warp内のスレッド全てが異なるコンスタントメモリのアドレスを参照すると,読込が逐次化
読込命令の処理に 悪で32倍の時間を要する
2016/01/13GPGPU講習会217
0 16 32 48 64 80 96 112
コンスタントメモリへのアクセス(Fermi世代)
Warp内のスレッド全てが同じコンスタントメモリアドレスにアクセス
1スレッドの読込をブロードキャストによって残りのスレッドが共有
他のWarpも同じメモリアドレスにアクセス
データがキャッシュされているため,キャッシュから高速に読み出し
2016/01/13GPGPU講習会218
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 16 32 48 64 80 96 112
コンスタントメモリへのアクセス(Fermi世代)
Warp内のスレッド全てが異なるコンスタントメモリアドレスにアクセス
読込が逐次化
読込処理の時間は,Warpがアクセスするコンスタントメモリアドレスの数に比例
悪で処理に32倍の時間がかかる
おそらくグローバルメモリアクセスよりも遅くなる
2016/01/13GPGPU講習会219
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
Recommended