長岡技術科学大学 電気電子情報工学専攻 出川智啓
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 SFU
16 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
GPC
Raster Engine
GPC
Raster Engine
SM
Raster Engine
GPC
Raster Engine
GPC
Memory ControllerMemory Controller
Memory ControllerMemory ControllerMemory Controller
詳細はhttp://www.nvidia.co.jp/docs/IO/
81860/NVIDIA_Fermi_Architecture_Whitep
aper_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‐ar
chitecture‐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 ControllerMemory Controller
Memory ControllerMemory ControllerMemory 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/cont
ent/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 Engine
GPC
Raster Engine
GPC
L2 Cache
GigaThread Engine
PCI Express 3.0 Host Interface
Memory Controller
Raster Engine
GPC
Raster Engine
GPC
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/desk
top‐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.8
2 Titan (U.S.A.) NVIDIA K20x 17.6/27.1 8.20
3 Sequoia (U.S.A.) − 17.2/20.1 7.90
4 K computer (Japan) − 10.5/11.3 12.7
5 Mira (U.S.A.) − 8.59/10.1 3.95
6 Trinity (U.S.A.) − 8.10/11.1
7 Piz Daint (Switzerland) NVIDIA K20x 6.27/7.79 2.33
8 Hazel Hen (Germany) ‐ 5.64/7.40
9 Shaheen II(Saudi Arabia) ‐ 5.54/7.24 2.83
10 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講習会30
http://www.green500.org/より引用
2016/01/13
計算機名称 アクセラレータ GFLOPS/W 消費電力[kW]
1 Shoubu PEZY‐SC 7.03 50.32
2 TSUBAME‐KFC NVIDIA Tesla K80 5.33 51.13
3 ASUS ESC4000  AMD FirePro S9150 5.27 57.15
4 Sugon Cluster  NVIDIA Tesla K80 4.78 65.00
5 Xstream NVIDIA Tesla K80 4.11 190.0
6 Inspur TS10000 NVIDIA Tesla K40 3.86 58.00
7 Inspur TS10000 NVIDIA Tesla K40 3.78 110.0
8 Inspur TS10000 NVIDIA Tesla K40 3.78 110.0
9 Inspur TS10000 NVIDIA Tesla K40 3.78 110.0
10 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講習会
処理結果出力
tesla16
45
実行イメージ
grouse処理結果出力
キー入力,マウス入力
$ ssh␣tesla16
$ pgf90 ??.cuf
$ ./a.out
キー入力
処理結果
ハード
ディスク
a.out
実行
2016/01/13GPGPU講習会
tesla16
46
実行イメージ
grouse
キー入力,マウス入力
$ ssh␣tesla16
$ pgf90 ??.cuf
$ ./a.out
キー入力
ハード
ディスク
a.out
実行
2016/01/13GPGPU講習会
tesla16
GPU0
GPU1
GPU2
GPU3
処理結果出力
処理結果
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
統合アカウントの
ユーザ名とパスワード
login
2016/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 main
use 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
GPC
Raster Engine
GPC
Raster Engine
SM
Raster Engine
GPC
Raster Engine
GPC
Memory ControllerMemory Controller
Memory ControllerMemory ControllerMemory Controller
詳細はhttp://www.nvidia.co.jp/docs/IO/
81860/NVIDIA_Fermi_Architecture_Whitep
aper_FINAL_J.pdfを参照のこと
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
Streaming 
Multiprocessor
GPUの模式図
2016/01/13GPGPU講習会60
GPU
Streaming 
Multiprocessor
L2キャッシュ
コンスタントメモリ
テクスチャメモリ
GPU
Chip
グローバルメモリ
SM SM SM SM・・・
・・・SM SM SM SM・・・ レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
L1キャッ
シュ
共有
メモリ
Streaming
Multiprocessor
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 texture
glBindTexture(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 main
implicit none
print *,"hello world"
end program main
GPGPU講習会68 2016/01/13
helloworld.f90
CUDA FortranでHello World
 何を確認するか
 最小構成のプログラムの作り方
 ファイル命名規則(拡張子は.cuf)
 コンパイルの方法(pgf90を使用)
program main
implicit none
print *,"hello world"
end program main
GPGPU講習会69
program main
implicit 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_kernel
implicit none
contains
attributes(global) subroutine kernel()
end subroutine kernel
end module cuf_kernel
program main
use cudafor
use cuf_kernel
implicit 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 kernel
implicit none
contains
subroutine hello()
print *,"Hello Thread"
end subroutine hello
end module kernel
program main
use kernel
implicit none
call hello()
end program main
画面表示・・・
サブルーチン実行・・・
hellothread.f90
Hello Thread(Fermi世代以降)
 GPUの各スレッドが画面表示
2016/01/13GPGPU講習会74
module cuf_kernel
implicit none
contains
attributes(global) subroutine hello()
print *,"Hello Thread"
end subroutine hello
end module cuf_kernel
program main
use cudafor
use cuf_kernel
implicit none
integer :: stat
call 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 none
contains
attributes(global) subroutine hello()
print *,"Hello Thread"
end subroutine hello
end module cuf_kernel
program main
use cudafor
use cuf_kernel
implicit none
integer :: stat
call 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_kernel
implicit none
contains
attributes(global) subroutine hello()
print *,"gridDim'%'x",gridDim%x,"blockIdx'%'x",blockIdx%x,&
"blockDim'%'x",blockDim%x,"threadIdx'%'x",threadIdx%x
end subroutine hello
end module cuf_kernel
program main
use cudafor
use cuf_kernel
implicit none
integer :: stat
call 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:                 0
Device Name:                   Tesla M2050
Device Revision Number:        2.0
Global Memory Size:            2817982464
Number of Multiprocessors:     14
Number of Cores:               448
Concurrent Copy and Execution: Yes
Total Constant Memory:         65536
Total Shared Memory per Block: 49152
Registers per Block:           32768
Warp Size:                     32
Maximum Threads per Block:     1024
Maximum Block Dimensions:      1024, 1024, 64
Maximum Grid Dimensions:       65535 x 65535 x 65535
Maximum Memory Pitch:          2147483647B
Texture Alignment:             512B
Clock Rate:                    1147 MHz
Initialization time:           4222411 microseconds
Current free memory:           2746736640
Upload 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_kernel
implicit none
integer,parameter :: N=2**20
contains
subroutine add(a, b, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
integer :: i
do i=1,N
c(i) = a(i) + b(i)
end do
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
a=1.0
b=2.0
c=0.0
call add(a,b,c)
end program main
CPUプログラム(メモリの静的確保)
GPGPU講習会95 2016/01/13
vectoradd.f90
module vectoradd_kernel
implicit none
integer,parameter :: N=2**20
contains
subroutine add(a, b, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
integer :: i
do i=1,N
c(i) = a(i) + b(i)
end do
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
implicit none
real,allocatable :: a(:)
real,allocatable :: b(:)
real,allocatable :: c(:)
allocate(a(N)); a=1.0
allocate(b(N)); b=2.0
allocate(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_alloca
te.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,N
print *,a(i),b(i),c(i);
end do
a
b
c
attributes(global) 
subroutine add()
do i=1,N
c(i) = a(i)+b(i)
end do
end subroutine add
2016/01/13
attributes(global) 
subroutine add()
do i=1,N
c(i) = a(i)+b(i)
end do
end subroutine add
GPUへの移植(メモリの取り扱い)
GPGPU講習会100
 ベクトルa,b,cを確保し,a,bの値を読んでcに書き込む
 ホスト(CPU)にはプロセッサとメモリが存在
 デバイス(GPU)にもプロセッサとメモリが存在
 デバイスからホストのメモリは(原則)直接読み書きできない
 GPUのメモリを確保し,カーネルから利用
do i=1,N
print *,a(i),b(i),c(i);
end do
a
b
c
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_kernel
implicit none
integer,parameter :: N=2**20
contains
subroutine add(a, b, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
integer :: i
do i=1,N
c(i) = a(i) + b(i)
end do
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
implicit none
real,allocatable :: a(:)
real,allocatable :: b(:)
real,allocatable :: c(:)
allocate(a(N)); a=1.0
allocate(b(N)); b=2.0
allocate(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_alloca
te.f90
module vectoradd_kernel
implicit none
integer,parameter :: N=2**20
contains
attributes(global)&
subroutine add(a, b, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
integer :: i
do i=1,N
c(i) = a(i) + b(i)
end do
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
use cudafor
implicit none
real,allocatable,device :: a(:)
real,allocatable,device :: b(:)
real,allocatable,device :: c(:)
allocate(a(N)); a=1.0
allocate(b(N)); b=2.0
allocate(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_1threa
d.cuf
module vectoradd_kernel
implicit none
integer,parameter :: N=2**20
contains
attributes(global)&
subroutine add(a, b, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
integer :: i
do i=1,N
c(i) = a(i) + b(i)
end do
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
use cudafor
implicit none
real,allocatable,device :: a(:)
real,allocatable,device :: b(:)
real,allocatable,device :: c(:)
allocate(a(N)); a=1.0
allocate(b(N)); b=2.0
allocate(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_1threa
d.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 fffff5f0d8759ef8
method,gputime,cputime,occupancy
method=[ __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_kernel
implicit none
integer,parameter :: N=2**20
contains
attributes(global) &
subroutine add(a, x, b, y, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
real,value :: x,y !値渡し
integer :: i
do i=1,N
c(i) = x*a(i) + y*b(i)
end do
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
use cudafor
implicit none
real,allocatable,device :: a(:)
real,allocatable,device :: b(:)
real,allocatable,device :: c(:)
real,allocatable :: host_c(:)
allocate(a(N)); a=1.0
allocate(b(N)); b=2.0
allocate(c(N)); c=0.0
allocate(host_c(N))
call add<<<1,1>>>(a,1.0,b,2.0,c)
host_c = c
print *,sum(host_c)/N
deallocate(a)
deallocate(b)
deallocate(c)
deallocate(host_c)
end program main
GPUプログラム(双方向コピー)
GPGPU講習会
vectoradd_1thread_copy.cuf
112 2016/01/13
CUDAでカーネルを作成するときの制限
GPGPU講習会113
 x,yはCPU側のメモリに存在
 値渡し
 CPU→GPUへ値がコピーされる
 Fortranはポインタ渡し
 値渡しにする場合はvalue
属性を付ける
attributes(global) &
subroutine add(a, x, b, y, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
real,value :: x,y !値渡し
integer :: i
do 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=1
c(i) = a(i) + b(i)スレッド1
c(i)
a(i)
b(i)
+ + + +
スレッド
1
スレッド
3
スレッド
2
スレッド
4
i=2
c(i) = a(i) + b(i)スレッド2
i=3
c(i) = a(i) + b(i)スレッド3
i=4
c(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 :: i
i = ...
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 :: i
i = 1
c(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_kernel
implicit none
contains
attributes(global) subroutine hello()
print *,"gridDim'%'x",gridDim%x,"blockIdx'%'x",blockIdx%x,&
"blockDim'%'x",blockDim%x,"threadIdx'%'x",threadIdx%x
end subroutine hello
end module cuf_kernel
program main
use cudafor
use cuf_kernel
implicit none
integer :: stat
call 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= 1
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4
gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 1
gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 2
gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 3
gridDim'%'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 :: i
i = (blockIdx%x‐1)*blockDim%x + threadIdx%x
c(i) = a(i) + b(i)
end subroutine add
GPGPU講習会128 2016/01/13
module vectoradd_kernel
implicit none
integer,parameter :: N=2**20
contains
attributes(global)&
subroutine add(a, b, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
integer :: i
i = (blockIdx%x‐1)*blockDim%x&
+ threadIdx%x
c(i) = a(i) + b(i)
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
use cudafor
implicit none
real,allocatable,device :: a(:)
real,allocatable,device :: b(:)
real,allocatable,device :: c(:)
allocate(a(N)); a=1.0
allocate(b(N)); b=2.0
allocate(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:                 0
Device Name:                   Tesla M2050
Device Revision Number:        2.0
Global Memory Size:            2817982464
Number of Multiprocessors:     14
Number of Cores:               448
Concurrent Copy and Execution: Yes
Total Constant Memory:         65536
Total Shared Memory per Block: 49152
Registers per Block:           32768
Warp Size:                     32
Maximum Threads per Block:     1024
Maximum Block Dimensions:      1024, 1024, 64
Maximum Grid Dimensions:       65535 x 65535 x 65535
Maximum Memory Pitch:          2147483647B
Texture Alignment:             512B
Clock Rate:                    1147 MHz
Initialization time:           4222411 microseconds
Current free memory:           2746736640
Upload 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 none
integer,parameter :: N=2**20
integer,parameter :: NT=256
integer,parameter :: NB=(N/NT)
contains
attributes(global) &
subroutine add(a, b, c)
implicit none
real :: a(N)
real :: b(N)
real :: c(N)
integer :: i
i = (blockIdx%x‐1)*blockDim%x &
+ threadIdx%x
c(i) = a(i) + b(i)
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
use cudafor
implicit none
real,allocatable,device :: a(:)
real,allocatable,device :: b(:)
real,allocatable,device :: c(:)
allocate(a(N)); a=1.0
allocate(b(N)); b=2.0
allocate(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.280
64 0.169 0.170
128 0.128 0.130
256 0.119 0.116
512 0.120 0.117
1024 0.151 0.146
ベクトル和C=A+B(2次元版)
2016/01/13GPGPU講習会136
 1次元のベクトル和とほぼ同じ
 並列化が容易
 do文の書く順番で実行速度が変化
c(:,:) a(:,:) b(:,:)
module vectoradd_kernel
implicit none
integer,parameter :: Nx=2**10
integer,parameter :: Ny=2**10
contains
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,Ny
do i=1,Nx
c(i,j) = a(i,j) + b(i,j)
end do
end do
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
implicit none
real :: a(Nx,Ny)
real :: b(Nx,Ny)
real :: c(Nx,Ny)
a=1.0
b=2.0
c=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
i
1次元目が連続
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_kernel
implicit none
contains
attributes(global) subroutine hello()
print *,"gridDim'%'x=", gridDim%x, "blockIdx'%'x=",  blockIdx%x,&
"blockDim'%'x=",blockDim%x,"threadIdx'%'x=", threadIdx%x
print *,"gridDim'%'y=", gridDim%y, "blockIdx'%'y=",  blockIdx%y,&
"blockDim'%'y=",blockDim%y,"threadIdx'%'y=", threadIdx%y
end subroutine hello
end module cuf_kernel
program main
use cudafor
use cuf_kernel
implicit none
integer :: stat
call hello<<<?,?>>>()
stat = cudaThreadSynchronize()
end program main
hellothreads2d.cu
Hello Threads(2次元版)
 1次元と同様<<<2,4>>>等として実行
 実行結果(画面出力)
2016/01/13GPGPU講習会142
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 1
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4
gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 1
gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 2
gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 3
gridDim'%'x= 2 blockIdx'%'x= 2 blockDim'%'x= 4 threadIdx'%'x= 4
gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
gridDim'%'y= 1 blockIdx'%'y= 1 blockDim'%'y= 1 threadIdx'%'y= 1
gridDim'%'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= 1
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 1
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 2
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 3
gridDim'%'x= 2 blockIdx'%'x= 1 blockDim'%'x= 4 threadIdx'%'x= 4
:(中略)
gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1
gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1
gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1
gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 1
gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 2
gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 2
gridDim'%'y= 4 blockIdx'%'y= 3 blockDim'%'y= 2 threadIdx'%'y= 2
gridDim'%'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  8
j=12  34  567  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=1blockIdx%y=2
gridDim%x=2
gridDim.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  8
j=12  34  567  8
module vectoradd_kernel
implicit none
integer,parameter :: Nx=2**10
integer,parameter :: Ny=2**10
integer,parameter :: NTx=16
integer,parameter :: NTy=16
integer,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,j
i=(blockIdx%x‐1)*blockDim%x+threadIdx%x
j=(blockIdx%y‐1)*blockDim%y+threadIdx%y
c(i,j) = a(i,j) + b(i,j)
end subroutine add
end module vectoradd_kernel
program main
use vectoradd_kernel
use cudafor
implicit none
real,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.0
allocate(b(Nx,Ny)); b=2.0
allocate(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 fffff5f14d408b28
method,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 fffff5f0d1572620
method,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 1136
2×128 601
4× 64 341
8× 32 213
16× 16 155
32× 8 119
64× 4 135
128× 2 121
256× 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 i
i=blockIdx%x*blockDim%x + threadIdx%x
b(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 i
i=blockIdx%x*blockDim%x + threadIdx%x
b(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
オフチップメモリ
オンチップメモリ
ホスト
メモリ
コンスタントメモリ
テクスチャメモリ
GPU
Chip
レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
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キャッシュ
コンスタントメモリ
テクスチャメモリ
GPU
Chip
レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
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
レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
Thre
ad 0
Thre
ad 1
Thre
ad 2
Thre
ad 3
L1キャッ
シュ
共有
メモリ
Block(0,0,0)
レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
Thre
ad 0
Thre
ad 1
Thre
ad 2
Thre
ad 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 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
メモリアドレスに対する
スレッドのアクセス要求
Warp内でのスレッドID
(カーネル内でのスレッド番号とは異なる)
メモリアドレス
メモリ読込の例
2016/01/13GPGPU講習会179
 アライン/アンコアレスアクセス
 ミスアライン/アンコアレスアクセス
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
0 1 2 3 4 56 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
0 1 2 3 4 56 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
メモリアドレスに対する
スレッドのアクセス要求
キャッシュされる読込
2016/01/13GPGPU講習会180
 L1キャッシュとL2キャッシュを通過
 読込は128バイト単位で実行
 L1キャッシュのキャッシュラインのサイズで実行
 読込の評価に利用する用語
 メモリトランザクション
 メモリのアクセス要求に対して排他的にメモリにアクセスして行う処理
の単位
 バスの利用率
 必要なデータサイズ/読込完了に必要な読込データサイズ
 アライン/コアレスアクセス
 Warp内の全スレッドが要求するメモリアドレスが128バイトの範
囲内
 全スレッドが隣り合ったメモリにアクセス
 先頭データのメモリアドレスが128バイトの倍数
 読込に必要な128バイトのトランザクションは一つ
 読み込んだデータ全てを利用
 バスの利用率は128/128=100%
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
キャッシュされる読込の例
2016/01/13GPGPU講習会181
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
Warp内でのスレッドID
(カーネル内でのスレッド番号とは異なる)
メモリアドレス
メモリアドレスに対するスレッドのアクセス要求
読込に必要な128バイトトランザクション
128バイトのキャッシュライン
読み込むデータ
キャッシュされる読込の例
2016/01/13GPGPU講習会182
 アライン/アンコアレスアクセス
 Warp内の全スレッドが要求するメモリアドレスが128バイトの
範囲内(一つのキャッシュラインに収まる)
 各スレッドがアクセスするメモリアドレスが不連続
 先頭データのメモリアドレスが128バイトの倍数
 読込に必要な128バイトのトランザクションは一つ
 読み込んだデータ全てを利用
 バスの利用率は128/128=100%
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
キャッシュされる読込の例
2016/01/13GPGPU講習会183
 ミスアライン/コアレスアクセス
 Warpがアクセスするデータの先頭アドレスが128の倍数では
ない(一つのキャッシュラインに収まらない)
 全スレッドが隣り合ったメモリにアクセス
 先頭データのメモリアドレスが128バイトの倍数ではない
 読込に必要な128バイトのトランザクションは二つ
 読み込んだデータの半分だけを利用
 バスの利用率は128/(128×2)=50%
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
キャッシュされる読込の例
2016/01/13GPGPU講習会184
 ミスアライン/コアレスアクセス
 Warp内の全スレッドが同じアドレスにアクセス要求
 一つのキャッシュラインに収まる
 読込に必要な128バイトのトランザクションは一つ
 読み込んだ128バイトのうち利用されるのは4バイトのみ
 バスの利用率は4/128=3.125%
0 1 2 3 4 56 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
キャッシュされる読込の例
2016/01/13GPGPU講習会185
 ミスアライン/コアレスアクセス
 Warp内の各スレッドが広範囲に点在するデータにアクセス
 複数のキャッシュラインにまたがる(上の例では3個)
 読込に必要な128バイトのトランザクションは最悪で32個
 読み込んだデータのうち128バイトのみを利用
 バスの利用率は最悪で128/(128×32)=3.125%
 上の例では128/(128×3)=33.3%
 何度も読み込むための待ちが発生
0 1 2 3 4 56 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
キャッシュされない読込
2016/01/13GPGPU講習会186
 L1キャッシュを無効化
 L2キャッシュのみを通過
 読込は32バイト単位で実行
 メモリセグメントのサイズで実行
 細かい単位で実行されるため,ミスアライン・アンコアレスメモ
リアクセスのパフォーマンスが改善される可能性がある
 セグメント
 メモリの管理方式の一つ
 まとまった大きさで管理されたメモリ空間
 アライン/コアレスアクセス
 Warp内の全スレッドが要求するメモリアドレスが128バイト(四
つのセグメントに収まる)
 全スレッドが隣り合ったメモリにアクセス
 先頭データのメモリアドレスが32バイトの倍数
 読込に必要な32バイトのトランザクションは四つ
 読み込んだデータ全てを利用
 バスの利用率は128/(32×4)=100%
キャッシュされない読込の例
2016/01/13GPGPU講習会187
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
Warp内でのスレッドID
(カーネル内でのスレッド番号とは異なる)
メモリアドレス
メモリアドレスに対するスレッドのアクセス要求
読込に必要な32バイトトランザクション
32バイトのメモリセグメント
読み込むデータ
キャッシュされない読込の例
2016/01/13GPGPU講習会188
 アライン/アンコアレスアクセス
 Warp内の全スレッドが要求するメモリアドレスが128バイト(四
つのセグメントに収まる)
 各スレッドがアクセスするメモリアドレスが不連続
 先頭データのメモリアドレスが32バイトの倍数
 読込に必要な32バイトのトランザクションは四つ
 読み込んだデータ全てを利用
 バスの利用率は128/(32×4)=100%
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
キャッシュされない読込の例
2016/01/13GPGPU講習会189
 ミスアライン/コアレスアクセス
 Warpがアクセスするデータの先頭アドレスが128の倍数では
ない(五つのセグメントにまたがる)
 全スレッドが隣り合ったメモリにアクセス
 先頭データのメモリアドレスが32バイトの倍数ではない
 読込に必要な32バイトのトランザクションは五つ
 読み込んだデータの8割は利用
 バスの利用率は128/(32×5)=80% 改善!
0 1 2 3 4 5 6 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
キャッシュされない読込の例
2016/01/13GPGPU講習会190
 ミスアライン/アンコアレスアクセス
 Warp内の全スレッドが同じアドレスにアクセス要求
 一つのセグメントに収まる
 読込に必要な32バイトのトランザクションは一つ
 読み込んだ32バイトのうち利用されるのは4バイトのみ
 バスの利用率は4/32=12.5% 改善!
0 1 2 3 4 56 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
キャッシュされない読込の例
2016/01/13GPGPU講習会191
 ミスアライン/アンコアレスアクセス
 Warp内の各スレッドが広範囲に点在するデータにアクセス
 複数のセグメントにまたがる(上の例では10個)
 読込に必要な32バイトのトランザクションは最悪で32個
 最悪でも32バイトのセグメント32個に分散
 バスの利用率は最悪で128/(32×32)=12.5% 改善!
 上の例では128/(32×10)=40% 改善!
 何度も読み込むための待ちは依然として発生
0 1 2 3 4 56 7 8 9 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
0 1
6
3
2
4
8
6
4
8
0
9
6
1
1
2
1
2
8
1
4
4
1
6
0
1
7
6
1
9
2
2
0
8
2
2
4
2
4
0
2
5
6
2
7
2
2
8
8
3
0
4
3
2
0
3
3
6
3
5
2
3
5
8
メモリの種類
 オンチップメモリ(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(条件)then
call 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
2
3
5
1
6
8
14
4
7
9
15
10
11
12
13
バンク番号
バンクコンフリクトする例
(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
2
3
5
1
6
8
14
4
7
9
15
10
11
12
13
バンク
コンフリクト
バンク
コンフリクト
バンク
コンフリクト
バンク
コンフリクト
バンク
コンフリクト
バンク
コンフリクト
バンク
コンフリクト
バンク
コンフリクト
バンク番号
バンクコンフリクトする例
(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
2
3
5
1
6
8
14
4
7
9
15
10
11
12
13
バンク
コンフリクト
バンク
コンフリクト
バンク番号
バンクコンフリクトしない例
(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
2
3
5
1
6
8
14
4
7
9
15
10
11
12
13
バンク番号
共有(シェアード)メモリへのアクセス
(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
12
8
バンクコンフリクトにならないアクセス
(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
14
4
4 5 6 7
16
0
8 9 10 11
17
6
12 13 14 15
19
2
16 17 18 19
20
8
20 21 22 23
22
4
24 25 26 27
24
0
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
12
8
0 1 2 3
14
4
4 5 6 7
16
0
8 9 10 11
17
6
12 13 14 15
19
2
16 17 18 19
20
8
20 21 22 23
22
4
24 25 26 27
24
0
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
12
8
0 1 2 3
14
4
4 5 6 7
16
0
8 9 10 11
17
6
12 13 14 15
19
2
16 17 18 19
20
8
20 21 22 23
22
4
24 25 26 27
24
0
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
12
8
25
6
38
4
0 1 2 3
16
14
4
27
2
40
0
4 5 6 7
32
16
0
28
8
41
6
8 9 10 11
48
17
6
30
4
43
2
12 13 14 15
64
19
2
32
0
44
8
16 17 18 19
80
20
8
33
6
46
4
20 21 22 23
96
22
4
35
2
48
0
24 25 26 27
11
2
24
0
35
8
49
6
28 29 30 31バンク番号
バンク
コンフリクト
バンク
コンフリクト
バンク
コンフリクト
メモリの種類
 オフチップメモリ(GPUのチップ外部に置かれたメモリ)
 低速アクセス,大容量
 CPUから直接アクセス可能
 ローカルメモリだけはアクセス不可
GPGPU講習会208
グローバルメモリ ローカルメモリ テクスチャメモリ コンスタントメモリ
容量 大 小 大 小
速度 低速 低速 高速* 高速*
GPUからの
読み書き
読み書き可
全てのスレッドが同
じメモリにアクセス
読み書き可
各スレッドが異なる
メモリにアクセス
読み込み可
全てのスレッドが同
じメモリにアクセス
読み込み可
全てのスレッドが同
じメモリにアクセス
CPUからの
アクセス
読み書き可 読み書き不可 書き込み可 書き込み可
2016/01/13
*キャッシュが効く場合
コンスタントメモリ
 GPU全体で同じメモリにアク
セス
 メモリを読み取り専用とする
ことで値をキャッシュし,一
度読んだ値を再利用
2016/01/13GPGPU講習会
 GPU全体で64kB
209
L2キャッシュ
コンスタントメモリ
テクスチャメモリ
GPU
Chip
レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
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 11
2
コンスタントメモリへのアクセス
(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 11
2
コンスタントメモリへのアクセス
(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

GPGPU Seminar (GPGPU and CUDA Fortran)