0
マルチコアのプログラミング技法
-- OpenCLとWebCL	

maruyama097
丸山不二夫
Scalable algorithms and libraries
can be the best legacy we can
leave behind from this era
-- Sanjay J. Patel
Agenda	
o  マルチコア、メニコアの時代へ
o  メニコア・チップの2方向への進化と異種混合環
境 -- Intel Xeon Phi と NVIDIA Tesla
o  メニコアとパラレル・プログラミング
o  Xeon Ph...
マルチコア、メニコアの時代へ
拡大を続けるICTの世界 2001-2013	
携帯	

スマートフォン	

固定電話	

インターネット	

”ICT Facts and Figures 2013”
2005年から2010年までの
世界のトランジスター数の変化	

IDF2011 Keynote
より 2011/9/13
2010年から2015年までの

世界のトランジスター数の予想	

IDF2011 Keynote
より 2011/9/13
チップ上のトランジス
ター数の増大は、や
むことなく進んでいる	

ムーアの法則
トランジスター数の増大を
チップのパワーにどう生かすか?	
o  トランジスター数の増大は、自動的にチップのパ
ワーを増大させる訳ではない。そこには、いくつか
の選択肢がある。
l  コアの処理能力を高める
l  パイプライン処理の強化
...
チップのクロックは、
頭打ちの状態
チップのクロックの問題	
o  チップの性能をあげる、最もストレートな方法は、
クロックの周波数を上げることである。しかし、そ
こには、いくつかの大きな問題がある。
o  消費電力の増大/発熱の問題
o  高い周波数の為には、高い電圧が必...
コアの増大は、2005年
あたりから顕著に
メニコア・チップの2方向への進化と
異種混合環境	
Intel Xeon Phi と NVIDIA Tesla
2013 June Top 500	
http://www.top500.org/list/2013/06/
Top 500 のパフォーマンスの伸び
Ra Site	
nk	

System	

Cores	

1	

National
University of
Defense
Technology
China	

Tianhe-2
3120000	
 33862.7	
 54902.4	...
Titan
Cray XK7 Compute Node
e
PCIe G

XK7 Compute Node
Characteristics
AMD Series 6200
(Interlagos)

n2

HT3
HT3

NVIDIA K...
Site	

System	

Cores	

Rmax	

Rpeak	

6	

Texas
Advanced
Computing
Center/Univ.
of Texas
United
States	

Stampede PowerEd...
Site	
21	

System	

Cores	

GSIC Center,
Tokyo
Institute of
Technology
Japan	

TSUBAME 2.0 - HP 73278	
ProLiant SL390s G7
...
Intel Xeon Phi
Xeon Phiのアーキテクチャー	
o  60個のコアは、高速の双方向リングネットワーク
で結合されている。
o  コアは、1GHzあるいはそれ以上のクロックで稼
働する。
o  キャッシュは、すべてのコプロッセサーで、コヒー
レントに...
http://www.intel.com/content/www/us/en/processors/xeon/
xeon-phi-coprocessor-block-diagram.html
From “Intel Xeon Phi Coprocessor Architecture and Tools”
64-bit x86に追加された命令	
o  狭いMMXの代わりに、SIMDの能力を持った広
い512bit長のベクター演算
o  インテルのSSE, AVX 演算
o  乗除、平方根、べき等の高速演算サポート
o  メモリーの高速な利...
From “Intel Xeon Phi Coprocessor High Performance Programming”
Transforming and Tuning
OffloadモデルとNativeモデル 	
o  Offloadモデル: プログラムはプロセッサーの
上で走り、プログラムの一部が、コプロセッサー上
にoffloadされ実行される、プロセッサー中心のモ
デル。
o  Nativeモデル:...
NVIDIA Tesla
Kepler
Tesla K20
KEY FEATURES	
o  GPU
n  Number of processor cores:

2496

n  Processor core clock: 706 MHz

o  Board„
n  PCI Express ...
GK110 Kepler アーキテクチャ	
o  フル実装の Kepler GK110 には、SMX ユニッ
トが 15 個と 64 ビットのメモリー・コントローラが
6 個用意される
o  Kepler GK110 の SMX ユニットに...
PCI Express 3.0 Interface	

	

L2 キャッシュ	

SMX x 15, Memory Controller x 6	

Memory Controller

Memory Controller

SMX x 15
Instruction Cache
Warp Scheduler
Dispatch Unit	

Core	

SFU x 32
Load/Store x 32
DP Unit x 64
Core x 192	

各SMXの構成	

Inter...
2021年には、CPUと
GPUの性能は、100
倍にまで拡大すると
いう予想
メニコア・チップの2方向への進化と
異種混合環境
CPUとGPUのアーキテクチャーの違い	

CPUとGPUは、基本的には、異なるデザイン思想に基づいてている。
CPU: 遅延を意識した設計
o  大きなキャッシュ
n  メモリーアクセスの長い遅
延をキャッシュで短かな遅
延に変える

ALU
ALU

o  強力な演算機能
n  演算の遅延を軽減する

ALU

Control

CPU

o...
GPU: スループットを意識した設計
o  小さなキャッシュ
n  メモリーのスループットを高める

o  単純な制御

GPU

n  分岐予測なし
n  データの先読みなし

o  エネルギー効率のいい演算
機能
o  遅延に...
CPUとGPUを両方使うメリット
o  遅延が問題となる、
o  スループットが重要と
シーケンシャルな実行
なるパラレルな実行の
の部分ではCPUを使う
部分では、GPUを使う
o  シーケンシャルなコー
ドでは、CPUはGPUの
10...
異種混合環境としての
デバイスのハードウェアの進化
動画のフレームレートで見る
モバイル・デバイスのパワー	
解像度	

1990~	
 176 x 144	

フレームレート	
 タイプ	

15 fps	

2010	

1920 x 1080	
 30 fps	

2013	

3840 ...
Apple iPhone 5s A7
	

http://www.appbank.net/2013/09/20/iphone-news/671017.php
Samsung Exynos 5 Octa
(Exynos 5420)	
o  CPU: ARM Cortex-A15 x4コア + CortexA7 x4コア のbig.LITTLEオクタコア構成
o  GPU: Mali-T628 (8...
Qualcomm Snapdragon 800	
o  Quad core Krait 400 CPU at up to
2.3GHz per core, 28nm HPm
o  Adreno 330 GPU
o  USB 3.0対応
Intel Atom Merrifield	
o  CPU: Tangier (Silvermort x 2) 22nm

http://pc.watch.impress.co.jp/docs/column/ubiq/20130507_598...
NVIDIA Tegra 4	
o  CPUコア: 4 + 1
o  CPUアーキテクチャ: ARM Cortex-A15
o  最大クロック速度: 1.9GHz
o  カスタムGPUコア: 72
Tegra 4のGPU
Tegra 4の後継機 Logan	
o  「Loganは(Tegraファミリで)初めて最新のGPU
を搭載する。CUDAを使うことができる最初のモ
バイルプロセッサとなる。Loganは、Kepler
GPUを搭載し、CUDA 5にフル対応し...
メニコアとパラレル・プログラミング	
メニコアのパワーを引き出す為には、パラレ
ル・プログラミングが必須となる。いくつかのア
プローチと実装が存在している。
並列と分散	
p  並列処理と分散処理の違いを、ネットワークをま
たいで処理を行うか否かという視点で考えること
が出来る。ただ、計算単位間の結合の疎密は、
基本的には、次のような単位間の通信に要する
時間で規定されている。
l  L1: 3...
並列と分散	
p  この必要な通信時間の差は、確かに量的なもの
ではあるが、L1, L2, RAMとDISKとNETWORK
の間に、質的な差はあると考えるに十分なもので
ある。
l  L1: 3 cycles
l  L2: 14 cyc...
大規模分散システムと
スーパーコンピューター	
o  Google、Facebook等の大規模分散システムと、
天河-2、Titan等の大規模並列クラスターとの違
いを述べるのは、意外と簡単ではない。
o  もちろん、違いを見つけるのは容易...
将来の変化	
o  こうしたことは、おそらく、現在のシステムが、進化
のprimitiveな段階にあることを示しているように
思う。
o  進化の方向は、明らかに、DISKとNETWORKの
高速化にある。メモリーとディスクが一体化し、
ネ...
タスク・パラレルとデータ・パラレル	
o  パラレル・プログラミングの基本的なモデルは、相
互に依存しない独立したタスクを並行して実行す
るタスク・パラレルと、個々の要素の独立した処理
を許すデータに対するデータ・パラレルの二つで
ある。両者...
データ・パラレルと関数型言語	
o  パラレル・コンピューティングにおける関数型言語
のメリットは、データ・パラレル・モデルと結びつい
ている。
o  そこでは、要素要素をループをまわして一つづつ
処理する形ではなく、データ構造全体に作用す...
パラレル・プログラミング言語と
そのモデル	
主要なコンピュータ・ベンダーによってサポー
トされ、標準的なプログラミング・インター
フェースになったものでも多くのパラレル・プロ
グラミング言語とモデルがある。ここでは、
MPI、OpenMP、O...
Parallel Programming
Languages and Models	
o  最も広く使われてきたのは、スケーラブルなクラス
ター・コンピューティングの為のMPI(Message
Passing Interface)と、共有メモ...
MPI(Message Passing Interface)	
o  MPIは、スケーラブルなクラスター・コンピューティ
ングの為に設計された。
o  クラスター上のコンピューター・ノードが、メモリー
を共有しない場合のモデルである。すべて...
OpenMP	
o  OpenMPは、共有メモリーを持つマルチプロセッ
サーの実行の為にデザインされたものである。
o  OpenMP の実装は、コンパイラとランタイムから
構成される。プログラマは、ループについて
OpenMPのコンパイラ...
OpenACC	
o  OpenACCは、異機種混在のコンピュータシステ
ムのプログラミングの為に提案されたものである。
o  OpenACCの主要な利点は、コンパイルの自動
化と、抽象化によってプログラマからパラレル・コ
ンピューティング...
CUDA	
o  CUDAは、GPUを活用したパラレル・プログラミン
グの為に提案されたものである。
o  CUDAは、プログラマにパラレル・プログラミング
の細部の明示的なコントロールを与えるので、そ
れは、OpenMPやOpenACCを...
OpenCL	
o  2009年に、Apple, Intel, AMD, NVIDIAを含
む、産業界の主要なプレーヤ達は、Open
Compute Language(OpenCL)と呼ばれる標
準化されたプログラミング・モデルを、共同で開発...
CUDAとMPIの結合	
o  今日では、多くのHPCクラスターは、均一ではな
いノードを利用している。
o  一方、CUDAは、それぞれのノードについては効
率的なインターフェースであるのだが、大部分の
アプリケーションの開発者は、クラス...
MPIの問題	
o  アプリケーションをMPIに移植するのに必要な作業の量
は、コンピューティング・ノード間の共有メモリーが欠けて
いることによって、極めて大きなものになる。
o  プログラマは、入力データと出力データをクラスター・ノー
ド...
CUDAの問題	
o  CUDAでは、CPUとGPU間のコミュニケーション
については、以前は、非常に限られた共有メモ
リーの能力しか提供していなかった。
o  プログラマは、”一方向”のメッセージ・パッシング
に似たような方法で、CPUと...
データ転送の最適化とGMAC	
o  GMAC, CUDA, OpenCLの下では、プログラ
マーは、CPUとGPUの間で共有されるデータ構造
を、Cの変数として定義出来る。
o  GMACのランタイムは、必要に応じてだが、プロ
グラマーの...
OpenCLの問題	
o  OpenCLは、OpenCLで開発されたアプリケー
ションが、OpenCLの言語拡張とAPIをサポート
するすべてのプロセッサー上で修正なしに正しく
走るような標準化されたプログラミング・モデルで
ある。
o  ...
Parallel Programming
Languages and Models	
o  OpenCLとCUDAの両方をよく知っているひとは、
OpenCLのコンセプトと諸特徴と、CUDAのそれ
らとのあいだには、顕著な類似点があることを知...
Xeon Phiのプログラミング
OpenMP	
“Intel Xeon Phi Co-processor
High Performance Programming”
omp_set_num_threads(2);
kmp_set_defaults("KMP_AFFINITY=compact");
#pragma omp parallel
#pragma omp master
numthreads = omp...
// scale the calculation across threads requested
// need to set environment variables
// OMP_NUM_THREADS and KMP_AFFINITY...
% export OMP_NUM_THREADS=122
% export KMP_AFFINITY=scatter
#pragma offload target (mic)
#pragma omp parallel
#pragma omp master
numthreads = omp_get_num_threads();
printf("Initializ...
% export OMP_NUM_THREADS=2
% ./hellomem
Initializing
Starting BW Test on 2 threads
Gbytes = 1024.000, Secs = 104.381, GByt...
Teslaのプログラミング CUDA
GPU コンピューティングの歴史	
1.  グラフィック・パイプラインの進化
2.  GPGPU:中間段階
3.  GPUコンピューティング
グラフィック・パイプラインの進化	
o  機能が固定したグラフィック・パイプラインの時代
n  1980年代の初期から1990年代の終わり。
n  DirectXの最初の7世代	

o  プログラム可能な、リアルタイム・グラフィックスの...
GPGPU(General Purpose
GPU):中間段階	
o  DirectX 9対応のGPUの時代、研究者の一部は、
GPUの演算能力の伸びに注目して、それをHPC
に利用することを考え始めた。
o  長崎大工学部濱田剛助教(当時...
「高性能の計算機は重要
だ」としながらも、巨費を投
じた従来の開発方針につ
いて「素直にいいとは言え
ない。方向性が逆」と述べ、
低価格化が可能との見方
を示した。
GPGPU(General Purpose
GPU):中間段階	
o  ただ、DirectX 9 GPUは、グラフィックAPI専用
にデザインされていたので、GPUの計算能力にア
クセスする為には、問題をグラフィック演算ー例え
ば、pixel...
GPUコンピューティング	
o  DirectX 10の世代のGPUは、高機能の浮動小
数点演算をサポートするようになった。
o  Tesla GPUのアーキテクチャーの設計では、
NVIDIAは、GPUをグラフィック専用のチップとし
てで...
Teslaのアークテクチャー	
o  こうした変更に必要なハードウェアの追加は、命
令キャッシュや命令制御ロジックの回路を共有す
ることで軽減された。
o  NVIDIAは、Cのプログラムが要求する、メモリー
へのランダム・アクセスを可能と...
CUDA	
o  NVIDIAは、プログラマーが容易にデータ・パラレ
ル型の新しいコンピューティング・モデルを利用出
来るように、CUDAコンパイラーと、そのライブラ
リー、ランタイムを開発した。
o  プログラマーは、GPUのパワーを使っ...
CPU/GPUのマルチコア化と
疎粒度/細粒度のパラレル処理	
o  マルチコア化というのは、ムーアの法則による
チップ上に実装可能なトランジスター数の増大を、
一つのコアのパフォーマンスをあげる為に使うの
ではなく、同じパフォーマンスのコア...
CUDAのプログラミング
タスク・パラレルとデータ・パラレル	
o  大規模なアプリケーションでは、通常は、多くの独
立したタスクがある。それ故、多くのタスクのパラ
レル実行が可能である。
o  一般的には、データ・パラレルがパラレル・プログ
ラムのスケーラビリティ...
データ・パラレルの例
ベクトルの加算	

ベクトルの加算は、要素ごとに、独立に計算可能である。
CUDAのプログラムの構造	
o  CUDAのプログラムの構造は、一つのホスト
(CPU)と一つ以上のデバイス(GPU)が、コン
ピュータ上で共存していることを反映している。
o  CUDAのソースファイルには、ホストとデバイスの
コードの...
CUDAプログラムのkernel	
o  デバイス(GPU)側の、データ・パラレル関数とそ
れに関連したデータ構造のラベルとして、
kernel というCUDAキーワードが利用される。
o  NVCC(NVIDIAのCUDA用Cコンパイラ)...
CUDAプログラムのコンパイル
CUDAプログラムの実行とgrid	
o  CUDAプログラムの実行は、host(CPU)のプロ
グラムの実行から始まる。
o  kernel関数が呼び出されると、沢山のスレッドが
デバイス上で走る。kernelの呼び出しで、まとめ
て生成...
CUDAプログラムの実行の例
gridとblockとthread	
o  ホスト側のコードで、kernelが起動されると、CUDA
のランタイムによって、gridのスレッドが生成される。
o  gridは、二段階の階層で組織されている。それぞれ
のgridは、スレッドの...
GridとBlockとThread	
Grid 0	

grid中の全てのスレッドは、同じkernel コードを実行する。
CUDAのkernel関数の定義
ベクトルの加算 – 通常のCコード
// Compute vector sum C = A+B
void vecAdd(float* A, float* B, float* C, int n)
{
for (i = 0, i < n, i++)...
forループは、どこへいったのか?	
o  このkernelコードには、forループは含まれてい
ない。このコードは、grid内の全てのスレッドで独
立に実行される。
o  n回のループは、n個のスレッドとして実行される。	
// Comp...
GridとBlockとThread	
Grid 0	

grid中の全てのスレッドは、同じkernel コードを実行する。
ベクトルの加算	

ベクトルの加算は、要素ごとに、独立に計算可能である。
__global__ キーワード	
o  __global__ は、宣言された関数が、CUDAの
kernel関数であることを表す。
o  この関数は、host側で呼び出され、デバイス上で
実行される。	
// Compute vector...
CUDAの関数宣言のキーワード
int i = threadIdx.x +
blockDim.x * blockIdx.x;
o  この式で計算される数字 i は、何を表しているの
であろうか? 
o  threadIdxは、ブロック内のスレッドの番号、
blockIdx...
GridとBlockとThread	
Grid 0	

grid中の全てのスレッドは、同じkernel コードを実行する。
int i = threadIdx.x +
blockDim.x * blockIdx.x;
o  この式で計算される数字 i は、何を表しているの
であろうか? 	
o  先の図をみれば、このi は、グリッド内のスレッド
の番号をユニーク...
int i = threadIdx.x +
blockDim.x * blockIdx.x;
o  この式にでてくる、*Idx.x の .xは何を表してい
るのだろうか? 実は、 *Idx.xだけではなく、
*Idx.yも*Idx.zも、CU...
int i = threadIdx.x +
blockDim.x * blockIdx.x;
o  この式にでてくる、*Idx.x の .xは何を表してい
るのだろうか? 実は、 *Idx.xだけではなく、
*Idx.yも*Idx.zも、CU...
if(i<n)
C_d[i] = A_d[i] + B_d[i];
o  この式にでてくる、 条件式 if (i<n) は何を表しているの
だろうか? 実は、ブロックの大きさは32の倍数と決めら
れていて、32の倍数のスレッドが自動的に生成さ...
CUDAのkernel関数の呼び出し
ベクトルの加算の呼び出し – 通常のCコード
int main()
{
// Memory allocation for A_h, B_h, and C_h
// I/O to read A_h and B_h, N elements 省略
v...
vecAddKernel
<<<ceil(n/256),256>>>(...)	
o  この<<<と>>>の記号は何だろうか? CUDA
では、この引数がgridの設定に使われている。
o  第一の引数に、grid内のblockの数を、
第...
<<< , >>>の引数について	
o  先には、簡単に、
第一の引数に、grid内のblockの数、
第二の引数に、block内のthreadの数を
指定する。 としたが、正確に言うと正しくない。
o  一般的には、gridは、block...
dim3 タイプ	
o  dim3 は、Cの構造体で、符号なし整数のx, y, z
の三つのフィールドを持つ。このdim3 を使って、
kernel関数へのパラメータ渡しは、次のように行
われる。3D以下のgrid, blockについては、使...
2次元grid, 3次元blockの例	

dim3 dimGrid(2,2,1);
dim3 dimBlock(4,2,2);
kernelFunction
<<< dimGrid .
dimBlock >>>
( ... )
CUDAプログラム サンプル
ベクトルの加算 – CUDAのCコード
#include <cuda.h>
void vecAdd(float* A, float* B, float* C, int n)‫‏‬

{
int size = n* sizeof(float);
...
void vecAdd(float* A, float* B, float* C, int n)!
{!
int size = n * sizeof(float); !
float* A_d, B_d, C_d;!
!

1.  // A,Bをデバイスの...
CUDAのメモリーの概略
o  デバイスは次のことが可能である
n  スレッド毎のregisterの読み/書き
n  grid毎のglobal memoryの読み/
書き
o  ホストは次のことが可能である
n  grid毎のglob...
CUDAデバイスのメモリー管理API
o  cudaMalloc()

Grid!

n  デバイスのglobal memory
にオブジェクトを割り当てる

Block (0, 0)!

Block (1, 0)!

Registers!...
ホスト-デバイス間データ転送API
o  cudaMemcpy()

(Device) Grid!

n  メモリーデータ転送
n  4つの引数
o 
o 
o 
o 

Block (0, 0)!

Registers!

コピ...
ベクトルの加算 CUDA kernel コード
// Compute vector sum C = A+B
// Each thread performs one pair-wise addition
__global__
void vecAd...
ベクトルの加算 CUDA host コード
int vecAdd(float* A, float* B, float* C, int n)
{
// allocations and copies omitted
// Run ceil(n/25...
CUDAとOpenCL
OpenCLの背景	
o  OpenCL は、C言語上の、標準化された、クロ
ス・プラットフォームのパラレル・コンピューティン
グのAPIである。それは、異種混合のコンピュー
ティング・デバイスからなるシステムで、ポータブ
ルなパラレル・アプ...
OpenCLの背景	
o  OpenCLは、特に、異種混合のパラレル・コン
ピューティング・システムの以前のプログラミング・
モデルの、アプリケーションの移植性の限界に、
大きな関心を向けている。
o  OpenCLの開発は、Appleによって開始され、
OpenGL標準を管理しているKhronosグループ
によって管理されていた。
o  一方で、それは、異種混合のパラレル・コンピュー
ティングでの単一コードベースのサポート、デー
タ...
o  他方で、OpenCLは、マルチ・プラットフォームと
マルチ・ベンダーのポータビリティのサポートに
よって、より複雑なプラットフォームとデバイスの
モデルを持っている。
o  OpenCLは、X86だけでなく、AMD/ATI、
NVID...
o  OpenCLのプログラムは、ハードウェアのより大
きな多様性を取り扱うように準備する必要があり、
もっと複雑なものになっていくだろう。
o  同時に、OpenCLの特徴の多くは、オプショナル
なもので、全てのデバイスでサポートされる必...
o  しかし、こうしたオプショナルな特徴のあるものは、
それをサポートしているデバイスにとっては、重要
なパフォーマンスの向上をアプリにもたらすことが
ある。結果として、ポータブルなOpenCLのコード
は、どんなデバイスの上でもパフォーマン...
Data Parallelism Model	
o  OpenCLは、データ・パラレル実行モデルを利用
している。この点では、CUDAと直接に対応して
いる。
o  OpenCLのプログラムは、二つの部分からなる。
一つは、OpenCLのデ...
OpenCLとCUDAの対応	
OpenCL	
o  Kernel
o  Host Program
o  NDRange
(Index Space)
o  Work Item
o  Work Group	

CUDA	
o  Ker...
OpenCLの最も基本的なアイデアと
4つのモデル	
OpenCLの最も基本的なアイデアを記述する
為に、次の4つの階層的なモデルを用いる。
p  Platform Model
p  Memory Model
p  Execution M...
Platform Model
Memory Model
Execution Model
Platform Model
Platform Model
Platform Model 	
o  このモデルは、一つ以上のOpenCLデバイスと
接続したhostからなる。
o  OpenCLデバイスは、一つ以上のcompute
unit(CU)に分割され、それらはさらに、 一つ以
上の proc...
Work Item
Memory Model
Memory Model
OpenCL Address Space	
o  __private
(CUDA local)
o  __local
(CUDA shared)
o  __constant
(CUDA constant)
o  __global
(CU...
Memory Model
Execution Model
KernelとHost program	
o  OpenCLの実行モデルは、OpenCLデバイス上
で実行されるkernelと、ホスト上で実行されるホ
スト・プログラムという、二つの異なった実行単位
で定義される。
o  kernelは、あ...
Context	
kernelの実行は、hostによって管理されたcontext
上で行われる。contextは、kernelの実行環境を定
義する。contextの中には、次のリソースが含まれる
1.  Devices: OpenCLのデバイ...
Command Queue	
o  hostとデバイスは、command-queueを通じ
て相互作用する。一つのcommand-queueは、
一つのデバイスに関連付けられている。
command-queueに置かれた命令は、次の三
つのタ...
Commandの
State	
commandは、Event Object
を通じて、Stateを知らせる。
Work item, Work group,
NDRange	
o  kernel関数が起動されると、そのコードはwork
item で実行される。これは、CUDAのthreadに
対応する。
o  work itemは、work grou...
OpenCLとCUDAの対応	
OpenCL	
o  Kernel
o  Host Program
o  NDRange
(Index Space)
o  Work Item
o  Work Group	

CUDA	
o  Ker...
OpenCLとCUDAのKernel関数	
__kernel void addVec (__global const float *a,
__global const float *b,
__global float *result)
{
in...
Overview of the OpenCL parallel execution
model.
OpenCL Execution Model
Work Item	

Work Group
Work Item	

Work Group
OpenCLとCUDAのインデックス	
OpenCL	
get_globa1_id(0)	

意味	
x次元のworkitemのGlobal
index	

CUDAでの対応	
blockIdx.x *
blockDim.x
+ threadI...
Work Item Identifier
Programming Model
OpenCLプログラムの流れ	
o  OpenCLのプログラムは、基本的には、次のよう
な流れになる
1.  OpenCLのプラットフォームを選択して、contextを生
成する
2.  デバイスを選んで、command-queueを生成する...
Contextが、OpenCLデバイスの実行環境を与える
OpenCLの
コンポーネント
OpenCL Program Sample
初期化	
デバイスを指定して、計算が実行されるcontextを作る	
cl_int err;
cl_context context;
cl_device_id devices;
cl_command_queue cmd_queue;
err =...
Discovering Devices
clGetDeviceIDs
Device Property

clGetDeviceInfo
メモリーの割り当て	
デバイスで利用されるリソースを割り当てる	
cl_mem ax_mem = clCreateBuffer(context,
CL_MEM_READ_ONLY,
atom_buffer_size, NULL, NULL);
...
Memory Buffer

clCreateBuffer
Memory Buffer
clEnqueueWriteBuffer
kernel/プログラムの生成	
プログラムを読み込んで、カーネルを生成する。	
cl_program program[1];
cl_kernel kernel[1];
program[0] = clCreateProgramWithSourc...
Building Programs
clBuildProgram
実行	
カーネルに値を渡し、実行する。	
size_t global_work_size[2], local_work_size[2];
global_work_size[0] = nx; global_work_size[1] = ny;
l...
終了処理	
計算結果をホストに返し、リソースを解放する。	
err = clEnqueueReadBuffer(cmd_queue, val_mem,
CL_TRUE, 0, grid_buffer_size, val, 0, NULL, NU...
Execution / Read
OpenCL Design and Programming
Guide for the Intel Xeon Phi
Coprocessor	

http://software.intel.com/en-us/articles/
opencl-...
WebCL
http://www2012.wwwconference.org/proceedings/nocompanion/
DevTrack_Slides/008_WebCL_for_hardware_accelerated_web_applicati...
WebCLの目的	
o  Webアプリで、GPU/マルチコアの高パフォーマ
ンスのパラレル処理を可能にする。
n  異種混合のマルチコア・デバイスへのポータブルで効
率的なアクセス
n  プラットフォームに依存しない、標準準拠のソリュー
...
WebCLのデザイン・ゴール	
o  異種混合の処理要素上で、次のようなデザイン・
フィロソフィーの下で、一般的な目的のパラレル・
プログラミングを可能にすること。
n  デスクトップとモバイルをまたぐ、単一で均一な標準
n  一般的な目...
WebCLのアプローチ	
o  OpenCL標準と密に連携する
n  開発者の親近感を保ち、受容を容易にする
n  開発者が、OpenCLについての知識をWeb環境に移
すことを可能にする
n  OpenCLとWebCLの進化とともに、...
Nokia’s WebCL Prototype	
o  Nokia open sourced their prototype in May
2011 (LGPL).
o  Web-based interactive photo editor...
Samsung WebCL Prototype	
o  Samsung open sourced their prototype WebCL
implementation for WebKit in July 2011 (BSD
licens...
WebCL Working Draft	
2013/10/23
https://cvs.khronos.org/svn/repos/
registry/trunk/public/webcl/spec/
latest/index.html
interface WebCL {
// Functions
sequence<WebCLPlatform> getPlatforms();
WebCLContext? createContext(
optional WebCLContextP...
dictionary WebCLContextProperties {
sequence<WebCLDevice>? devices = null;
 // Default: let the implementation decide
WebC...
interface WebCLPlatform {
any getInfo(CLenum name);
sequence<WebCLDevice> getDevices(
optional CLenum deviceType);
sequenc...
interface WebCLContext {
WebCLBuffer createBuffer(
CLenum memFlags, CLuint sizeInBytes,
optional ArrayBufferView hostPtr);...
interface WebCLCommandQueue {
//////////////////////////////////////////////////////////
//
// Copying: Buffer <-> Buffer,...
// interface WebCLCommandQueue
/////////////////////////////////////////////////////////
//
// Reading: Buffer -> Host, Im...
// interface WebCLCommandQueue
////////////////////////////////////////////////////
//
// Writing: Host -> Buffer, Host ->...
// interface WebCLCommandQueue
///////////////////////////////////////////////////////////
//
// Executing kernels
//
void...
// interface WebCLCommandQueue
/////////////////////////////////////////////////////////
//
// Synchronization
//
void enq...
// interface WebCLCommandQueue
////////////////////////////////////////////////////////////
//
// Querying command queue i...
interface WebCLMemoryObject {
any getInfo(CLenum name);
void release();
};
interface WebCLBuffer : WebCLMemoryObject {
WebCLBuffer createSubBuffer(
CLenum memFlags,
CLuint origin, CLuint sizeInByte...
interface WebCLProgram {
any getInfo(CLenum name);
any getBuildInfo(
WebCLDevice device, CLenum name);
void build(optional...
interface WebCLKernel {
any getInfo(CLenum name);
any getWorkGroupInfo(WebCLDevice device,
CLenum name);
void setArg(CLuin...
[Constructor]
interface WebCLEvent {
readonly attribute CLenum status;
readonly attribute WebCLMemoryObject buffer;
any ge...
WebCL Hardware-Accelerated
Web Application	
http://download.tizen.org/misc/media/
conference2012/tuesday/ballroom-b/
2012-...
WebCL: Initialization 	
<script>
var platforms = WebCL.getPlatforms();
var devices = platforms[0].
getDevices(WebCL.DEVICE...
WebCL: Create Kernel 	
<script id="squareProgram" type="x-kernel">
__kernel square(
__global float* input,
__global float*...
WebCL: Create Kernel 	
<script>
var programSource =
getProgramSource("squareProgram");
// JavaScript function using DOM AP...
WebCL: Run Kernel 1 	
<script>
…
var inputBuf =
context.createBuffer(WebCL.MEM_READ_ONLY,
Float32Array.BYTES_PER_ELEMENT *...
WebCL: Run Kernel 2 	
kernel.setKernelArg(0, inputBuf);
kernel.setKernelArg(1, outputBuf);
kernel.setKernelArg(2, count,
W...
WebCL: Run Kernel 3 	
queue.finish();
// this API blocks
queue.enqueueReadBuffer(outputBuf,
data, true);
// last arg indic...
WebCL: Image Object Creation 	
o  From Uint8Array()	
<script>
var bpp = 4; // bytes per pixel
var pixels = new Uint8Array...
WebCL: Image Object Creation 	
o  From <img> or <canvas> or <video>	
<script>
var canvas =
document.getElementById("aCanv...
WebCL:
Vertex Buffer Initialization	

<script>
WebGL	
var points = new Float32Array(NPOINTS * 3);
var glVertexBuffer = gl....
WebCL:
Vertex Buffer Update and Draw	
<script>
WebCL	
function DrawLoop() {
queue.enqueueAcquireGLObjects([clVertexBuffer]...
Texture Initialization	
<script>
var glTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, glTexture);
gl.texImage...
Texture Update and Draw	
<script>
function DrawLoop() {
queue.enqueueAcquireGLObjects([clTexture]);
queue.enqueueNDRangeKe...
WebCL: Initialization (draft)	
<script>
var platforms = WebCL.getPlatforms();
var devices = platforms[0].
getDevices(WebCL...
WebCL: Initialization (draft)	
<script>
var platforms = WebCL.getPlatforms();
var devices = platforms[0].
getDevices(WebCL...
参考資料
OpenCL Design and Programming
Guide for the Intel Xeon Phi
Coprocessor	

http://software.intel.com/en-us/articles/
opencl-...
Why is this paper needed?	
o  While OpenCL is a portable programming
model, the performance portability is not
guaranteed...
o  Another example: while some traditional GPUs
are based on HW scheduling of many tiny
threads, Intel Xeon Phi coprocess...
Will I need to have different OpenCL
optimizations for different devices?	
o  Not necessarily. Will you add a small #ifde...
o  We really encourage developers to explore the
performance potential of the Intel Xeon Phi
coprocessor, using the guide...
o  An Intel Xeon Phi coprocessor contains many
cores, each with a 512-bit vector arithmetic
unit, capable of executing SI...
o  This simultaneous multi-threading helps hide
instruction and memory latencies. OpenCL
hides most of these details from...
Key Intel Xeon Phi Coprocessor
Performance Aspects	
o  Multi-threading parallelism
o  Intel Xeon Phi coprocessor HW incl...
o  In Core Vectorization
o  The vector size in the Intel Xeon Phi
coprocessor is 512 bit wide SIMD. Typically,
this vect...
o  PCI Express* (PCIe) Bus Interface
o  The Intel Xeon Phi coprocessor resides on the
PCIe bus. Transferring data over t...
o  Memory subsystem
o  The Intel Xeon Phi coprocessor includes three
levels of memory (GDDR, L2 cache, and L1
cache). Th...
o  Since the Intel Xeon Phi coprocessor is an inorder machine, the latency of memory
accesses has significant impact on s...
Data Access Pattern	
o  Accessing memory consecutively is the fastest
way to access memory on the Intel Xeon Phi
coproces...
Mapping the OpenCL constructs
to Intel Xeon Phi coprocessor	
o  Understanding how the key OpenCL constructs
are implement...
o  Conceptually, at initialization time, the OpenCL
driver creates 240 SW threads and pins them
to the HW threads (for a ...
o  The OpenCL compiler creates an optimized
routine that executes a WG. This routine is
built from up to three nested loo...
o  Note that the innermost loop is used for
dimension zero of the NDRange. This directly
impacts the access pattern of yo...
o  The OpenCL compiler implicitly vectorizes the
WG routine based on dimension zero loop, i.e.,
the dimension zero loop i...
o  The vector size of Intel Xeon Phi coprocessor is
16, regardless of the data types used in the
kernel. However, in the ...
Exposing algorithm parallelism	
o  While the OpenCL specification provides
various ways to express parallelism and
concur...
Multi-threading	
o  To get good utilization of the 240 HW threads,
it’s best to have more than 1000 WGs per
NDRange. Havi...
o  Single WG execution duration also impacts the
threading efficiency. Lightweight WGs are also
not recommended, as these...
Vectorization	
o  OpenCL on Intel Xeon Phi coprocessor includes
an implicit vectorization module. The OpenCL
compiler aut...
o  However, the vectorized kernel is only used if
the local size of dimension zero is greater than
or equal to 16. Otherw...
o  Recommendation 1: Don’t manually vectorize
kernels, as the OpenCL compiler is going to
scalarize your code to prepare ...
Work-Item-ID nonuniform
control flow	
o  In this section, we explain the difference
between uniform and nonuniform contro...
Uniform branch example:	
o  A branch is uniform if it is statically guaranteed
that all work items within a WG execute th...
Nonuniform branch example:
	

1: Int LID = get_local_id(0);
2: If (LID == 0)
3:
Res = -1;

Another uniform branch example:...
o  While vectorizing, the compiler has to linearize
(flatten) any code dominated by nonuniform
control flow via predicati...
// Assuming the following original kernel code:
1: Int gid = get_global_id(0);
2: If(gid % 32 == 0)
3:
Res = HandleEdgeCas...
Data Alignment	
o  For various reasons, memory access that is
vector-size-aligned is faster than unaligned
memory access....
o  Calling EnqueueNDRange with local size NULL,
lets the OpenCL driver choose the best WG size
for you. The driver should...
o  Recommendation 1: Don’t use NDrange
offset. If you have to use an offset, then make
it a multiple of 32, or at least a...
Design your algorithm to benefit from
the Intel Xeon Phi coprocessor
memory subsystem	
o  Since Intel Xeon Phi coprocesso...
Intra WG data reuse	
o  Designing your application to maximize the
amount of data reuse from the caches is the
first memo...
o  To benefit from data reuse, you need to take
into account the WG implicit loop(s), as
described earlier in this docume...
Cross WG data reuse	
o  Cross-group data reuse is a greater challenge.
Currently, OpenCL on Intel Xeon Phi
coprocessor do...
Data access pattern	
o  Consecutive data access usually allows the best
memory system performance. When one
considers con...
The following code accesses the 2D buffers
consecutively in memory (recommended):
	
1: __kernel ABC(…){
2: int ID1 = get_g...
o  The second code example scans the 2D buffers
“column major.” With vectorization, it results in
double faults, namely: ...
Simple one dimension example (recommended):
Consecutive access:
1: Int id = get_global_id(0);
2: A[id]= B[id];
Non-Consecu...
o  If your kernel includes an explicit loop, then
you should remember that the implicit
vectorization is still based on t...
Data layout	
o  Pure SOA (Structure-of-Arrays) data layout
results in simple and efficient vector loads and
stores. Howev...
o  Please remember that random access of SOA
data layout creates gather and scatter
instructions too.
o  The third optio...
o  AOSOA allows efficient vectorization using
simple vector loads, while not overloading the
TLB, nor spreading the acces...
Data prefetching	
o  With the Intel Xeon Phi coprocessor being an
in-order machine, data prefetching is an
essential way ...
o  A cache miss means a thread stall plus a few
cycles penalty to reissue the instruction. The
Intel Xeon Phi coprocessor...
o  Automatic SW prefetches to the L1 and L2 are
inserted by the OpenCL compiler for data
accessed in future iterations, w...
o  Manual prefetching can be inserted by the
programmer into the OpenCL kernel, via the
prefetch built-in. Currently, man...
Local memory and Barriers	
o  While traditional GPUs include Shared Local
Memory (SLM), which requires manual
management,...
o  Recommendation: Avoid using Shared Local
Memory on the Intel Xeon Phi coprocessor.
o  The Intel Xeon Phi coprocessor ...
Summary	
o  While designing your OpenCL application for
Intel Xeon Phi coprocessor, you should pay
careful attention to t...
5.  Prefer consecutive data access.
6.  Data layout preferences: AOS for sparse
random access; pure SOA or AOSOA(32)
other...
End of World
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
マルチコアのプログラミング技法 -- OpenCLとWebCL
Upcoming SlideShare
Loading in...5
×

マルチコアのプログラミング技法 -- OpenCLとWebCL

3,755

Published on

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,755
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
42
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Transcript of "マルチコアのプログラミング技法 -- OpenCLとWebCL"

  1. 1. マルチコアのプログラミング技法 -- OpenCLとWebCL maruyama097 丸山不二夫
  2. 2. Scalable algorithms and libraries can be the best legacy we can leave behind from this era -- Sanjay J. Patel
  3. 3. Agenda o  マルチコア、メニコアの時代へ o  メニコア・チップの2方向への進化と異種混合環 境 -- Intel Xeon Phi と NVIDIA Tesla o  メニコアとパラレル・プログラミング o  Xeon Phiのプログラミング OpenMP o  NVIDIAのプログラミング CUDA o  OpenCL o  WebCL
  4. 4. マルチコア、メニコアの時代へ
  5. 5. 拡大を続けるICTの世界 2001-2013 携帯 スマートフォン 固定電話 インターネット ”ICT Facts and Figures 2013”
  6. 6. 2005年から2010年までの 世界のトランジスター数の変化 IDF2011 Keynote より 2011/9/13
  7. 7. 2010年から2015年までの
 世界のトランジスター数の予想 IDF2011 Keynote より 2011/9/13
  8. 8. チップ上のトランジス ター数の増大は、や むことなく進んでいる ムーアの法則
  9. 9. トランジスター数の増大を チップのパワーにどう生かすか? o  トランジスター数の増大は、自動的にチップのパ ワーを増大させる訳ではない。そこには、いくつか の選択肢がある。 l  コアの処理能力を高める l  パイプライン処理の強化 l  vector演算等新しい命令の追加 l  .... l  キャッシュを拡大する l  コアの数を増やす l  ....
  10. 10. チップのクロックは、 頭打ちの状態
  11. 11. チップのクロックの問題 o  チップの性能をあげる、最もストレートな方法は、 クロックの周波数を上げることである。しかし、そ こには、いくつかの大きな問題がある。 o  消費電力の増大/発熱の問題 o  高い周波数の為には、高い電圧が必要になるが、 リーク電流も増大し、性能が低下する o  光のスピードでしか情報は伝わらないので、原理 的には、チップの大きさが限界を与える。
  12. 12. コアの増大は、2005年 あたりから顕著に
  13. 13. メニコア・チップの2方向への進化と 異種混合環境 Intel Xeon Phi と NVIDIA Tesla
  14. 14. 2013 June Top 500 http://www.top500.org/list/2013/06/
  15. 15. Top 500 のパフォーマンスの伸び
  16. 16. Ra Site nk System Cores 1 National University of Defense Technology China Tianhe-2 3120000 33862.7 54902.4 (MilkyWay-2) TH-IVB-FEP Cluster, Intel Xeon E5-2692 12C 2.200GHz, TH Express-2, Intel Xeon Phi 31S1P NUDT 2 DOE/SC/Oak Ridge National Laboratory United States Titan - Cray XK7 , Opteron 6274 16C 2.200GHz, Cray Gemini interconnect, NVIDIA K20x Cray Inc. 560640 Rmax Rpeak 17590.0 27112.5
  17. 17. Titan Cray XK7 Compute Node e PCIe G XK7 Compute Node Characteristics AMD Series 6200 (Interlagos) n2 HT3 HT3 NVIDIA Kepler Host Memory 32GB 1600 MT/s DDR3 NVIDIA Tesla X2090 Memory 6GB GDDR5 capacity Z   Y   X   Gemini High Speed Interconnect Keplers in final installation http://en.wikipedia.org/wiki/Titan_(supercomputer) 21
  18. 18. Site System Cores Rmax Rpeak 6 Texas Advanced Computing Center/Univ. of Texas United States Stampede PowerEdge C8220, Xeon E5-2680 8C 2.700GHz, Infiniband FDR, Intel Xeon Phi SE10P Dell 462462 5168.1 8520.1 10 National Supercompu ting Center in Tianjin China Tianhe-1A - NUDT YH MPP, Xeon X5670 6C 2.93 GHz, NVIDIA 2050 NUDT 186368 2566.0 4701.0 16 National Supercompu ting Centre in Shenzhen (NSCS) China Nebulae Dawning TC3600 Blade System, Xeon X5650 6C 2.66GHz, Infiniband QDR, NVIDIA 2050 Dawning 120640 1271.0 2984.3
  19. 19. Site 21 System Cores GSIC Center, Tokyo Institute of Technology Japan TSUBAME 2.0 - HP 73278 ProLiant SL390s G7 Xeon 6C X5670, Nvidia GPU, Linux/Windows NEC/HP Rmax Rpeak 1192.0 2287.6
  20. 20. Intel Xeon Phi
  21. 21. Xeon Phiのアーキテクチャー o  60個のコアは、高速の双方向リングネットワーク で結合されている。 o  コアは、1GHzあるいはそれ以上のクロックで稼 働する。 o  キャッシュは、すべてのコプロッセサーで、コヒー レントに保たれる o  それぞれのコアは、ローカルに512KBのL2 キャッシュを持つ。L2キャッシュは、相互に高速に アクセス出来る。(チップ上のL2キャッシュの総量 は、25MB以上になる)
  22. 22. http://www.intel.com/content/www/us/en/processors/xeon/ xeon-phi-coprocessor-block-diagram.html
  23. 23. From “Intel Xeon Phi Coprocessor Architecture and Tools”
  24. 24. 64-bit x86に追加された命令 o  狭いMMXの代わりに、SIMDの能力を持った広 い512bit長のベクター演算 o  インテルのSSE, AVX 演算 o  乗除、平方根、べき等の高速演算サポート o  メモリーの高速な利用を可能にする、Scatter/ gatherとストリーミング・ストアのサポート
  25. 25. From “Intel Xeon Phi Coprocessor High Performance Programming”
  26. 26. Transforming and Tuning
  27. 27. OffloadモデルとNativeモデル o  Offloadモデル: プログラムはプロセッサーの 上で走り、プログラムの一部が、コプロセッサー上 にoffloadされ実行される、プロセッサー中心のモ デル。 o  Nativeモデル: プログラムは、プロセッサーと コプロセッサー上で走り、様々の方法で、相互に 通信を行うモデル。
  28. 28. NVIDIA Tesla
  29. 29. Kepler Tesla K20
  30. 30. KEY FEATURES o  GPU n  Number of processor cores: 2496 n  Processor core clock: 706 MHz o  Board„ n  PCI Express Gen2 ×16 system interface o  Memory n  n  n  n  n  Memory clock: 2.6 GHz Memory bandwidth: 208 GB/sec„ Interface: 320-bit Total board memory: 5 GB 20 pieces of 64M × 16 GDDR5, SDRAM
  31. 31. GK110 Kepler アーキテクチャ o  フル実装の Kepler GK110 には、SMX ユニッ トが 15 個と 64 ビットのメモリー・コントローラが 6 個用意される o  Kepler GK110 の SMX ユニットには、単精度 CUDA コアが 192 個搭載されていて、各コアに は完全パイプライン化された浮動小数点演算ユ ニットと整数演算ユニットが設けられている o  各SMXには、倍精度ユニット64個、特殊関数ユ ニット(SFU)32個、ロード/ストア・ユニット(LD/ ST)32個が用意されている。
  32. 32. PCI Express 3.0 Interface L2 キャッシュ SMX x 15, Memory Controller x 6 Memory Controller Memory Controller SMX x 15
  33. 33. Instruction Cache Warp Scheduler Dispatch Unit Core SFU x 32 Load/Store x 32 DP Unit x 64 Core x 192 各SMXの構成 InterConnect Shared Memory/L1 ReadOnly Cache Tex
  34. 34. 2021年には、CPUと GPUの性能は、100 倍にまで拡大すると いう予想
  35. 35. メニコア・チップの2方向への進化と 異種混合環境
  36. 36. CPUとGPUのアーキテクチャーの違い CPUとGPUは、基本的には、異なるデザイン思想に基づいてている。
  37. 37. CPU: 遅延を意識した設計 o  大きなキャッシュ n  メモリーアクセスの長い遅 延をキャッシュで短かな遅 延に変える ALU ALU o  強力な演算機能 n  演算の遅延を軽減する ALU Control CPU o  高度な制御 n  分岐遅延を軽減する為の 分岐予測・投機的実行 n  データ遅延を軽減する為の データ先読み ALU Cache DRAM
  38. 38. GPU: スループットを意識した設計 o  小さなキャッシュ n  メモリーのスループットを高める o  単純な制御 GPU n  分岐予測なし n  データの先読みなし o  エネルギー効率のいい演算 機能 o  遅延に打ち勝つために大量 スレッドを必要とする DRAM
  39. 39. CPUとGPUを両方使うメリット o  遅延が問題となる、 o  スループットが重要と シーケンシャルな実行 なるパラレルな実行の の部分ではCPUを使う 部分では、GPUを使う o  シーケンシャルなコー ドでは、CPUはGPUの 10倍以上早い o  パラレルなコードでは、 GPUはCPUの10倍以 上早い 異種混合環境の登場
  40. 40. 異種混合環境としての デバイスのハードウェアの進化
  41. 41. 動画のフレームレートで見る モバイル・デバイスのパワー 解像度 1990~ 176 x 144 フレームレート タイプ 15 fps 2010 1920 x 1080 30 fps 2013 3840 x 2160 60 fps 2015 7680 x 4320 120 fps フルHD “4K” “8K”
  42. 42. Apple iPhone 5s A7 http://www.appbank.net/2013/09/20/iphone-news/671017.php
  43. 43. Samsung Exynos 5 Octa (Exynos 5420) o  CPU: ARM Cortex-A15 x4コア + CortexA7 x4コア のbig.LITTLEオクタコア構成 o  GPU: Mali-T628 (8コア) o  新モデル: 8コアが同時に 動く、「Heterogeneous Multi-Processing (HMP) 」機能 2013年9月発表 
  44. 44. Qualcomm Snapdragon 800 o  Quad core Krait 400 CPU at up to 2.3GHz per core, 28nm HPm o  Adreno 330 GPU o  USB 3.0対応
  45. 45. Intel Atom Merrifield o  CPU: Tangier (Silvermort x 2) 22nm http://pc.watch.impress.co.jp/docs/column/ubiq/20130507_598283.html
  46. 46. NVIDIA Tegra 4 o  CPUコア: 4 + 1 o  CPUアーキテクチャ: ARM Cortex-A15 o  最大クロック速度: 1.9GHz o  カスタムGPUコア: 72
  47. 47. Tegra 4のGPU
  48. 48. Tegra 4の後継機 Logan o  「Loganは(Tegraファミリで)初めて最新のGPU を搭載する。CUDAを使うことができる最初のモ バイルプロセッサとなる。Loganは、Kepler GPUを搭載し、CUDA 5にフル対応し、OpenGL 4.3もサポートする。Loganは来年(2014年)頭 には、容易に製造に入ることができるだろう」
  49. 49. メニコアとパラレル・プログラミング メニコアのパワーを引き出す為には、パラレ ル・プログラミングが必須となる。いくつかのア プローチと実装が存在している。
  50. 50. 並列と分散 p  並列処理と分散処理の違いを、ネットワークをま たいで処理を行うか否かという視点で考えること が出来る。ただ、計算単位間の結合の疎密は、 基本的には、次のような単位間の通信に要する 時間で規定されている。 l  L1: 3 cycles l  L2: 14 cycles l  RAM: 250 cycles l  DISK: 41,000,000 cycles l  NETWORK: 240,000,000 cycles
  51. 51. 並列と分散 p  この必要な通信時間の差は、確かに量的なもの ではあるが、L1, L2, RAMとDISKとNETWORK の間に、質的な差はあると考えるに十分なもので ある。 l  L1: 3 cycles l  L2: 14 cycles l  RAM: 250 cycles l  DISK: 41,000,000 cycles l  NETWORK: 240,000,000 cycles
  52. 52. 大規模分散システムと スーパーコンピューター o  Google、Facebook等の大規模分散システムと、 天河-2、Titan等の大規模並列クラスターとの違 いを述べるのは、意外と簡単ではない。 o  もちろん、違いを見つけるのは容易でもある。た だ、GoogleとFacebookのシステムの違いは大 きいし、天河-2とTitanのアーキテクチャの違いも 大きい。 o  同じように、これらの共通性を求めることも、比較 的簡単に出来る。
  53. 53. 将来の変化 o  こうしたことは、おそらく、現在のシステムが、進化 のprimitiveな段階にあることを示しているように 思う。 o  進化の方向は、明らかに、DISKとNETWORKの 高速化にある。メモリーとディスクが一体化し、 ネットワークが内部バスより高速になれば、シス テムのアーキテクチャーは、変わる。   「Gilderの予想」、「量子光通信」、.... 新しい素子技術、....
  54. 54. タスク・パラレルとデータ・パラレル o  パラレル・プログラミングの基本的なモデルは、相 互に依存しない独立したタスクを並行して実行す るタスク・パラレルと、個々の要素の独立した処理 を許すデータに対するデータ・パラレルの二つで ある。両者の組み合わせも可能である。 o  タスク・パラレルは、比較的荒い粒度でのパラレ ル処理で、マルチコアのCPUに向いており、デー タ・パラレルは、細粒度のマッシブ・パラレル処理 で、メニコアのGPUに向いている。
  55. 55. データ・パラレルと関数型言語 o  パラレル・コンピューティングにおける関数型言語 のメリットは、データ・パラレル・モデルと結びつい ている。 o  そこでは、要素要素をループをまわして一つづつ 処理する形ではなく、データ構造全体に作用する 副作用のない関数(個別の処理を担う関数を引 数に取る)を利用することで、データ・パラレルを 実現する。 o  ただ、残念ながら、大規模なシステムでは、こうし たアプローチはまだ利用されていないように思う。
  56. 56. パラレル・プログラミング言語と そのモデル 主要なコンピュータ・ベンダーによってサポー トされ、標準的なプログラミング・インター フェースになったものでも多くのパラレル・プロ グラミング言語とモデルがある。ここでは、 MPI、OpenMP、OpenACC、CUDA、 OpenCLについて、その概要を述べる。 “Programming Massive Parallel Processor”
  57. 57. Parallel Programming Languages and Models o  最も広く使われてきたのは、スケーラブルなクラス ター・コンピューティングの為のMPI(Message Passing Interface)と、共有メモリーのマルチプ ロセッサーの為のOpenMPである。 o  両者とも、主要なコンピュータ・ベンダーによって サポートさえ、標準的なプログラミング・インター フェースになった。
  58. 58. MPI(Message Passing Interface) o  MPIは、スケーラブルなクラスター・コンピューティ ングの為に設計された。 o  クラスター上のコンピューター・ノードが、メモリー を共有しない場合のモデルである。すべてのデー タの共有と相互作用は、明示的なメッセージ・パッ シングを通じて行われなければならない。 o  MPIは、ハイ・パフォーマンス・コンピューティング (HPC)で成功を収めてきた。MPIで書かれたアプ リケーションは、10万ノード以上のクラスター・コ ンピューティング・システムで、成功裏に稼働して いる。
  59. 59. OpenMP o  OpenMPは、共有メモリーを持つマルチプロセッ サーの実行の為にデザインされたものである。 o  OpenMP の実装は、コンパイラとランタイムから 構成される。プログラマは、ループについて OpenMPのコンパイラに対して、ディレクティブ(コ マンド)とプラグマ(ヒント)を指定する。 o  これらのディレクティブとプラグマを用いて、 OpenMPのコンパイラはパラレルなコードを生成 する。ランタイム・システムは、パラレルなスレッド とリソースを管理することで、パラレル・コードの実 行をサポートする。
  60. 60. OpenACC o  OpenACCは、異機種混在のコンピュータシステ ムのプログラミングの為に提案されたものである。 o  OpenACCの主要な利点は、コンパイルの自動 化と、抽象化によってプログラマからパラレル・コ ンピューティングの為の多くの細かな決まり事か ら解放する、ランタイムのサポートを提供すること である。 o  ただ、OpenACCで効率的なプログラムを行う為 には、やはり、パラレル・プログラミングに必要な、 すべての細部を理解していることが必要になる。
  61. 61. CUDA o  CUDAは、GPUを活用したパラレル・プログラミン グの為に提案されたものである。 o  CUDAは、プログラマにパラレル・プログラミング の細部の明示的なコントロールを与えるので、そ れは、OpenMPやOpenACCを第一のプログラ ム・インターフェースとして使いたいと思っている ひとにとっても、優れた学習用の練習台になる。
  62. 62. OpenCL o  2009年に、Apple, Intel, AMD, NVIDIAを含 む、産業界の主要なプレーヤ達は、Open Compute Language(OpenCL)と呼ばれる標 準化されたプログラミング・モデルを、共同で開発 した。 o  CUDAと同様に、OpenCLのプログラミング・モデ ルは、プログラマが、マッシブ・パラレル・プロセッ サーで、パラレル実行とデータは配送を管理する ことを可能にする、言語拡張とランタイムAPIを定 義している。
  63. 63. CUDAとMPIの結合 o  今日では、多くのHPCクラスターは、均一ではな いノードを利用している。 o  一方、CUDAは、それぞれのノードについては効 率的なインターフェースであるのだが、大部分の アプリケーションの開発者は、クラスター・レベル では、MPIを利用する必要がある。 o  それ故、HPCのパラレル・プログラマーには、MPI とCUDAをどのように結合するかを理解すること が重要になる。
  64. 64. MPIの問題 o  アプリケーションをMPIに移植するのに必要な作業の量 は、コンピューティング・ノード間の共有メモリーが欠けて いることによって、極めて大きなものになる。 o  プログラマは、入力データと出力データをクラスター・ノー ドに分割する、ドメインの分割を実行する必要がある。こ のドメインの分割に基づいて、プログラマは、また、 ノード 間のデータの交換を管理する、メッセージの送信と受信を 行う関数を呼び出す必要がある。 o  CUDAは、それに対して、こうした困難に対して、CPUの 内部でパラレル実行の為の共有メモリーを提供する。
  65. 65. CUDAの問題 o  CUDAでは、CPUとGPU間のコミュニケーション については、以前は、非常に限られた共有メモ リーの能力しか提供していなかった。 o  プログラマは、”一方向”のメッセージ・パッシング に似たような方法で、CPUとGPU間のデータ転送 を管理する必要があった。 o  均一ではないコンピューティング・システムにおけ る、グローバル・アドレス空間と自動データ転送の 新しいサポートは、GMACとCUDA 4.0では、今 では、利用可能である。
  66. 66. データ転送の最適化とGMAC o  GMAC, CUDA, OpenCLの下では、プログラ マーは、CPUとGPUの間で共有されるデータ構造 を、Cの変数として定義出来る。 o  GMACのランタイムは、必要に応じてだが、プロ グラマーの為に、データ転送操作の最適化を自 動的に行い、データの整合性を維持する。こうし たサポートは、計算とI/O動作が重なりあってい るようなデータ転送を含む、CUDAとOpenCLの プログラミングの複雑さを大幅に軽減する。
  67. 67. OpenCLの問題 o  OpenCLは、OpenCLで開発されたアプリケー ションが、OpenCLの言語拡張とAPIをサポート するすべてのプロセッサー上で修正なしに正しく 走るような標準化されたプログラミング・モデルで ある。 o  しかしながら、新しいプロセッサーで、高いパ フォーマンスを達成しようとすれば、すすんでアプ リケーションを修正する必要はあるだろう。
  68. 68. Parallel Programming Languages and Models o  OpenCLとCUDAの両方をよく知っているひとは、 OpenCLのコンセプトと諸特徴と、CUDAのそれ らとのあいだには、顕著な類似点があることを知 るだろう。すなわち、CUDAのプログラマは、 OpenCLのプログラミングを、最小の努力で学習 出来る。より重要なことは、仮想的には、CUDAを 使って学ぶことの出来るテクニックのすべては、 OpenCLのプログラミングに応用出来るだろう。
  69. 69. Xeon Phiのプログラミング OpenMP “Intel Xeon Phi Co-processor High Performance Programming”
  70. 70. omp_set_num_threads(2); kmp_set_defaults("KMP_AFFINITY=compact"); #pragma omp parallel #pragma omp master numthreads = omp_get_num_threads(); printf("Initializingrn"); #pragma omp parallel for for(i=0; i<FLOPS_ARRAY_SIZE; i++) { fa[i] = (float)i + 0.1; fb[i] = (float)i + 0.2; } printf("Starting Compute on %d threadsrn",numthreads); tstart = dtime();
  71. 71. // scale the calculation across threads requested // need to set environment variables // OMP_NUM_THREADS and KMP_AFFINITY #pragma omp parallel for private(j,k) for (i=0; i<numthreads; i++) { // each thread will work it's own array section // calc offset into the right section int offset = i*LOOP_COUNT; // loop many times to get lots of calculations for(j=0; j<MAXFLOPS_ITERS; j++) { // scale 1st array and add in the 2nd array for(k=0; k<LOOP_COUNT; k++) { fa[k+offset] = a * fa[k+offset] + fb[k+offset]; } } }
  72. 72. % export OMP_NUM_THREADS=122 % export KMP_AFFINITY=scatter
  73. 73. #pragma offload target (mic) #pragma omp parallel #pragma omp master numthreads = omp_get_num_threads(); printf("Initializingrn"); #pragma omp parallel for for(i=0; i<FLOPS_ARRAY_SIZE; i++) { fa[i] = (float)i + 0.1; fb[i] = (float)i + 0.2; } printf("Starting Compute on %d threadsrn",numthreads); tstart = dtime(); #pragma offload target (mic) #pragma omp parallel for private(j,k) for (i=0; i<numthreads; i++) { .......
  74. 74. % export OMP_NUM_THREADS=2 % ./hellomem Initializing Starting BW Test on 2 threads Gbytes = 1024.000, Secs = 104.381, GBytes per sec = 9.810 % export OMP_NUM_THREADS=10 % ./hellomem Initializing Starting BW Test on 10 threads Gbytes = 1024.000, Secs = 21.991, GBytes per sec 46.565 % export OMP_NUM_THREADS=20 % ./hellomem Initializing Starting BW Test on 20 threads Gbytes = 1024.000, Secs = 13.198, GBytes per sec = 77.585 .... .... % export OMP_NUM_THREADS=61 % ./hellomem Initializing Starting BW Test on 61 threads Gbytes = 1024.000, Secs = 7.386, GBytes per sec = 138.637 Coreの数を増やす
  75. 75. Teslaのプログラミング CUDA
  76. 76. GPU コンピューティングの歴史 1.  グラフィック・パイプラインの進化 2.  GPGPU:中間段階 3.  GPUコンピューティング
  77. 77. グラフィック・パイプラインの進化 o  機能が固定したグラフィック・パイプラインの時代 n  1980年代の初期から1990年代の終わり。 n  DirectXの最初の7世代 o  プログラム可能な、リアルタイム・グラフィックスの進 化 n  2001年 GeForce 3 / 2002年 ATI Radeon 9700 n  2005年 Xbox 360 o  グラフィックとコンピューティング・プロセッサの統合 n  2006年 GeForce 8800
  78. 78. GPGPU(General Purpose GPU):中間段階 o  DirectX 9対応のGPUの時代、研究者の一部は、 GPUの演算能力の伸びに注目して、それをHPC に利用することを考え始めた。 o  長崎大工学部濱田剛助教(当時)は、3800万円 の予算で、NVIDIA GeForceを380基使って、 158TFlopの性能を達成し、2009年ゴードン・ベ ル賞を受賞した。 o  これは、2002年の地球シミュレーター(600億 円)の41TFlop、2009年の地球シミュレーター 2(158億円で改修)の122TFlopを上回るもので あった。
  79. 79. 「高性能の計算機は重要 だ」としながらも、巨費を投 じた従来の開発方針につ いて「素直にいいとは言え ない。方向性が逆」と述べ、 低価格化が可能との見方 を示した。
  80. 80. GPGPU(General Purpose GPU):中間段階 o  ただ、DirectX 9 GPUは、グラフィックAPI専用 にデザインされていたので、GPUの計算能力にア クセスする為には、問題をグラフィック演算ー例え ば、pixel shader演算ーに置き換える作業が必 要だった。 o  入力データは、テキスチャー・イメージとしてGPU に送られ、出力は、ピクセルの集合として返ってく る。
  81. 81. GPUコンピューティング o  DirectX 10の世代のGPUは、高機能の浮動小 数点演算をサポートするようになった。 o  Tesla GPUのアーキテクチャーの設計では、 NVIDIAは、GPUをグラフィック専用のチップとし てではなく、データ・パラレルの処理の役割を担う、 プログラマーがプログラム可能なプロセッサーに することの重要性に気づき、その道に踏み出した。 o  Teslaでは、かつてのshaderプロセッサーは、命 令用のメモリーとキャッシュ、命令の制御ロジック を備えた、完全にプログラム可能なプロセッサー になった。
  82. 82. Teslaのアークテクチャー o  こうした変更に必要なハードウェアの追加は、命 令キャッシュや命令制御ロジックの回路を共有す ることで軽減された。 o  NVIDIAは、Cのプログラムが要求する、メモリー へのランダム・アクセスを可能とする、メモリー Load/Store命令を追加した。 o  Teslaは、階層化されたパラレル・スレッドのプロ グラミング・モデル、バリア同期、パラレル処理の ディスパッチと管理の機能を導入した。
  83. 83. CUDA o  NVIDIAは、プログラマーが容易にデータ・パラレ ル型の新しいコンピューティング・モデルを利用出 来るように、CUDAコンパイラーと、そのライブラ リー、ランタイムを開発した。 o  プログラマーは、GPUのパワーを使ってパラレル 計算を実行するのに、GPGPUのようにグラフィッ クAPIを使う必要は、もはや無くなった。
  84. 84. CPU/GPUのマルチコア化と 疎粒度/細粒度のパラレル処理 o  マルチコア化というのは、ムーアの法則による チップ上に実装可能なトランジスター数の増大を、 一つのコアのパフォーマンスをあげる為に使うの ではなく、同じパフォーマンスのコアの数を増やす 為に利用しようということ。それは、CPUでもGPU でも同じ。 o  CPU処理のマルチコアによるパラレル化は粒度 が荒く、コア数の増大によって処理を書き直さな ければいけないことが起こる。一方、GPUのマル チコアによるパラレル化は、粒度が細かく、コアの 数に応じてスケールする。
  85. 85. CUDAのプログラミング
  86. 86. タスク・パラレルとデータ・パラレル o  大規模なアプリケーションでは、通常は、多くの独 立したタスクがある。それ故、多くのタスクのパラ レル実行が可能である。 o  一般的には、データ・パラレルがパラレル・プログ ラムのスケーラビリティの源になる。 o  大規模なデータに対して、大量のパラレル・プロ セッサーが利用可能な、非常に多くのデータのパ ラレル処理を見つけることが出来る。こうして、 ハードウェアの世代につれ、アプリケーションのパ フォーマンスが向上することが可能になる。
  87. 87. データ・パラレルの例 ベクトルの加算 ベクトルの加算は、要素ごとに、独立に計算可能である。
  88. 88. CUDAのプログラムの構造 o  CUDAのプログラムの構造は、一つのホスト (CPU)と一つ以上のデバイス(GPU)が、コン ピュータ上で共存していることを反映している。 o  CUDAのソースファイルには、ホストとデバイスの コードの両方が含まれる。 o  普通のCプログラムは、ホスト側のコードだけを含 んだCUDAプログラムである。 o  デバイスの為のコードは、データや関数の宣言に CUDAのキーワードを加えることで明確に区別さ れる。こうしたCUDAキーワードを含むコードは、 普通のCコンパイラーでは、コンパイル出来ない。
  89. 89. CUDAプログラムのkernel o  デバイス(GPU)側の、データ・パラレル関数とそ れに関連したデータ構造のラベルとして、 kernel というCUDAキーワードが利用される。 o  NVCC(NVIDIAのCUDA用Cコンパイラ)は、 CUDAのキーワードを利用して、プログラムをホ スト側とデバイス側に分離する。 o  デバイス・コードは、NVCCのランタイムによって、 コンパイルされ、GPU上で実行される。
  90. 90. CUDAプログラムのコンパイル
  91. 91. CUDAプログラムの実行とgrid o  CUDAプログラムの実行は、host(CPU)のプロ グラムの実行から始まる。 o  kernel関数が呼び出されると、沢山のスレッドが デバイス上で走る。kernelの呼び出しで、まとめ て生成される全てのスレッドは、gridと呼ばれる。 o  kernelのスレッドの実行が全て終わると、それに 対応したgridは終了する。 o  こうして、制御は、次のkernelが呼ぶ出されるま で、host側に移る。
  92. 92. CUDAプログラムの実行の例
  93. 93. gridとblockとthread o  ホスト側のコードで、kernelが起動されると、CUDA のランタイムによって、gridのスレッドが生成される。 o  gridは、二段階の階層で組織されている。それぞれ のgridは、スレッドの配列であるblockからなる。 grid内のblockは、ユニークなblockIdxを持つ。 o  一つのgridのblockは、全て同じサイズで、1024 個までのスレッドを含むことが出来る。blockのス レッド数は、kernelの起動時にhost側で指定する。 blockのスレッド数は、blockDimで参照出来る。 o  block中のそれぞれのスレッドは、ユニークな threadIdxを持つ。
  94. 94. GridとBlockとThread Grid 0 grid中の全てのスレッドは、同じkernel コードを実行する。
  95. 95. CUDAのkernel関数の定義
  96. 96. ベクトルの加算 – 通常のCコード // Compute vector sum C = A+B void vecAdd(float* A, float* B, float* C, int n) { for (i = 0, i < n, i++) C[i] = A[i] + B[i]; } ベクトルの加算 – CUDAのkernel Cコード // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  97. 97. forループは、どこへいったのか? o  このkernelコードには、forループは含まれてい ない。このコードは、grid内の全てのスレッドで独 立に実行される。 o  n回のループは、n個のスレッドとして実行される。 // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  98. 98. GridとBlockとThread Grid 0 grid中の全てのスレッドは、同じkernel コードを実行する。
  99. 99. ベクトルの加算 ベクトルの加算は、要素ごとに、独立に計算可能である。
  100. 100. __global__ キーワード o  __global__ は、宣言された関数が、CUDAの kernel関数であることを表す。 o  この関数は、host側で呼び出され、デバイス上で 実行される。 // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  101. 101. CUDAの関数宣言のキーワード
  102. 102. int i = threadIdx.x + blockDim.x * blockIdx.x; o  この式で計算される数字 i は、何を表しているの であろうか?  o  threadIdxは、ブロック内のスレッドの番号、 blockIdxは、グリッド内のブロックの番号である。 // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  103. 103. GridとBlockとThread Grid 0 grid中の全てのスレッドは、同じkernel コードを実行する。
  104. 104. int i = threadIdx.x + blockDim.x * blockIdx.x; o  この式で計算される数字 i は、何を表しているの であろうか?  o  先の図をみれば、このi は、グリッド内のスレッド の番号をユニークに表していることが分かる。 // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  105. 105. int i = threadIdx.x + blockDim.x * blockIdx.x; o  この式にでてくる、*Idx.x の .xは何を表してい るのだろうか? 実は、 *Idx.xだけではなく、 *Idx.yも*Idx.zも、CUDAには存在する。 o  それは、*Idxのx成分であることを表している // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  106. 106. int i = threadIdx.x + blockDim.x * blockIdx.x; o  この式にでてくる、*Idx.x の .xは何を表してい るのだろうか? 実は、 *Idx.xだけではなく、 *Idx.yも*Idx.zも、CUDAには存在する。 o  それは、*Idxのx成分であることを表している // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  107. 107. if(i<n) C_d[i] = A_d[i] + B_d[i]; o  この式にでてくる、 条件式 if (i<n) は何を表しているの だろうか? 実は、ブロックの大きさは32の倍数と決めら れていて、32の倍数のスレッドが自動的に生成される。 o  この条件は、あまったスレッドに仕事をさせない為のもの である。これで正確にn個のスレッドが仕事をする。 // Compute vector sum C = A+B __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  108. 108. CUDAのkernel関数の呼び出し
  109. 109. ベクトルの加算の呼び出し – 通常のCコード int main() { // Memory allocation for A_h, B_h, and C_h // I/O to read A_h and B_h, N elements 省略 vecAdd(A_h, B_h, C_h, N); } ベクトルの加算の呼び出し – CUDAのhost Cコード int main() { // Memory allocation for A_h, B_h, and C_h // I/O to read A_h and B_h, N elements 省略     vecAddKernel<<<ceil(n/256), 256>>>(A_d, B_d,    C_d, n); }
  110. 110. vecAddKernel <<<ceil(n/256),256>>>(...) o  この<<<と>>>の記号は何だろうか? CUDA では、この引数がgridの設定に使われている。 o  第一の引数に、grid内のblockの数を、 第二の引数に、block内のthreadの数を 指定する。 int main() { // Memory allocation for A_h, B_h, and C_h // I/O to read A_h and B_h, N elements 省略     vecAddKernel<<<ceil(n/256), 256>>>(A_d, B_d,    C_d, n); }
  111. 111. <<< , >>>の引数について o  先には、簡単に、 第一の引数に、grid内のblockの数、 第二の引数に、block内のthreadの数を 指定する。 としたが、正確に言うと正しくない。 o  一般的には、gridは、blockの3次元配列で、同様 に、blockは、threadの3次元配列である。 o  それ故、一般的には、次が正しい。 第一の引数に、grid内のblockの3次元配列を、 第二の引数に、block内のthreadの3次元配列を 指定する。
  112. 112. dim3 タイプ o  dim3 は、Cの構造体で、符号なし整数のx, y, z の三つのフィールドを持つ。このdim3 を使って、 kernel関数へのパラメータ渡しは、次のように行 われる。3D以下のgrid, blockについては、使わ ない次元に1を入れて宣言する。 int vecAdd(float* A, float* B, float* C, int n) { .... dim3 DimGrid(n/256, 1, 1); if (n%256) DimGrid.x++; dim3 DimBlock(256, 1, 1); vecAddKernel<<<DimGrid,DimBlock>>>(A_d, B_d, C_d, n); }
  113. 113. 2次元grid, 3次元blockの例 dim3 dimGrid(2,2,1); dim3 dimBlock(4,2,2); kernelFunction <<< dimGrid . dimBlock >>> ( ... )
  114. 114. CUDAプログラム サンプル
  115. 115. ベクトルの加算 – CUDAのCコード #include <cuda.h> void vecAdd(float* A, float* B, float* C, int n)‫‏‬ { int size = n* sizeof(float); float* A_d, B_d, C_d; … 1. // A,Bの為のメモリーをデバイスに割り当 // A,Bをデバイスのメモリーにコピー 2. // Kernel コードを走らせ、デバイスに // 実際のベクトルの和の計算をさせる 3. // デバイスのメモリーから、Cをコピーする // Free device vectors } Part 1! Host Memory! Device Memory GPU Part 2 CPU Part 3!
  116. 116. void vecAdd(float* A, float* B, float* C, int n)! {! int size = n * sizeof(float); ! float* A_d, B_d, C_d;! ! 1.  // A,Bをデバイスのメモリーにコピー! cudaMalloc((void **) &A_d, size);! cudaMemcpy(A_d, A, size, cudaMemcpyHostToDevice);! cudaMalloc((void **) &B_d, size);! cudaMemcpy(B_d, B, size, cudaMemcpyHostToDevice);! ! // Cの為のメモリーをデバイスに割り当 cudaMalloc((void **) &C_d, size);! ! 2. // Kernel invocation code – あとで見る! …! 3. }! // Cをデバイスからホストに転送する! cudaMemcpy(C, C_d, size, cudaMemcpyDeviceToHost);! // デバイス上のA, B, Cのメモリーを解放する! cudaFree(A_d); cudaFree(B_d); cudaFree (C_d);! 132
  117. 117. CUDAのメモリーの概略 o  デバイスは次のことが可能である n  スレッド毎のregisterの読み/書き n  grid毎のglobal memoryの読み/ 書き o  ホストは次のことが可能である n  grid毎のglobal memory との間 の、双方向のデータ転送 同じアプリによって呼ばれる Ho kernel間では、Global, constant, st! texture メモリーは保存されている。 133 (Device) Grid! Block (0, 0)! Registers! Registers! Thread (0, 0)! Thread (1, 0)! Global Memory! Block (1, 0)! Registers! Registers! Thread (0, 0)! Thread (1, 0)!
  118. 118. CUDAデバイスのメモリー管理API o  cudaMalloc() Grid! n  デバイスのglobal memory にオブジェクトを割り当てる Block (0, 0)! Block (1, 0)! Registers! Registers! n  二つの引数 o  割り当てられるオブジェクトへ のポインタのアドレス o  割り当てられるオブジェクトへ のサイズ(バイト数) o  cudaFree() Host! n  デバイスのglobal memory からオブジェクトを解放する n  引数は、解放されるオブジェク トへのポインタ Registers! Thread (0, 0)! Thread (1, 0)! Global Memory! Registers! Thread (0, 0)! Thread (1, 0)!
  119. 119. ホスト-デバイス間データ転送API o  cudaMemcpy() (Device) Grid! n  メモリーデータ転送 n  4つの引数 o  o  o  o  Block (0, 0)! Registers! コピー先へのポインタ コピー元へのポインタ コピーされるバイト数 転送のタイプ・方向 Block (1, 0)! Registers! Registers! Thread (0, 0)! Thread (1, 0)! Host! n  デバイスへの転送は、非 同期で行われる Registers! Thread (0, 0)! Thread (1, 0)! Global Memory!
  120. 120. ベクトルの加算 CUDA kernel コード // Compute vector sum C = A+B // Each thread performs one pair-wise addition __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) { int i = threadIdx.x + blockDim.x * blockIdx.x; if(i<n) C_d[i] = A_d[i] + B_d[i]; }
  121. 121. ベクトルの加算 CUDA host コード int vecAdd(float* A, float* B, float* C, int n) { // allocations and copies omitted // Run ceil(n/256) blocks of 256 threads each dim3 DimGrid(n/256, 1, 1); if (n%256) DimGrid.x++; dim3 DimBlock(256, 1, 1); vecAddKernel<<<DimGrid,DimBlock>>>(A_d, B_d, C_d, n); }
  122. 122. CUDAとOpenCL
  123. 123. OpenCLの背景 o  OpenCL は、C言語上の、標準化された、クロ ス・プラットフォームのパラレル・コンピューティン グのAPIである。それは、異種混合のコンピュー ティング・デバイスからなるシステムで、ポータブ ルなパラレル・アプリケーションの開発が可能とな るようにデザインされている。 o  OpenCLの開発は、急速に成長している様々の パラレル・コンピューティングのプラットフォームに 標準的で高パフォーマンスのアプリケーションの 開発プラットフォームのニーズによって動機付け られている。
  124. 124. OpenCLの背景 o  OpenCLは、特に、異種混合のパラレル・コン ピューティング・システムの以前のプログラミング・ モデルの、アプリケーションの移植性の限界に、 大きな関心を向けている。
  125. 125. o  OpenCLの開発は、Appleによって開始され、 OpenGL標準を管理しているKhronosグループ によって管理されていた。 o  一方で、それは、異種混合のパラレル・コンピュー ティングでの単一コードベースのサポート、デー タ・パラレル処理、複雑なメモリー階層といった領 域で、強くCUDAの影響を受けていた。
  126. 126. o  他方で、OpenCLは、マルチ・プラットフォームと マルチ・ベンダーのポータビリティのサポートに よって、より複雑なプラットフォームとデバイスの モデルを持っている。 o  OpenCLは、X86だけでなく、AMD/ATI、 NVIDIA GPUでの実装も存在している。原理的 には、DSPやFPGAといった別のタイプのデバイ スでの実装に拡張することも出来る。OpenCLは、 異なるベンダーのデバイス間のコードのポータビ リティをサポートするものだが、こうしたポータビリ ティは、無料ではない。
  127. 127. o  OpenCLのプログラムは、ハードウェアのより大 きな多様性を取り扱うように準備する必要があり、 もっと複雑なものになっていくだろう。 o  同時に、OpenCLの特徴の多くは、オプショナル なもので、全てのデバイスでサポートされる必要 はないかもしれない。ポータブルなOpenCLの コードは、こうしたオプショナルな特徴を使うことを 避ける必要がある。
  128. 128. o  しかし、こうしたオプショナルな特徴のあるものは、 それをサポートしているデバイスにとっては、重要 なパフォーマンスの向上をアプリにもたらすことが ある。結果として、ポータブルなOpenCLのコード は、どんなデバイスの上でもパフォーマンスの可 能性を達成出来ないことになる。
  129. 129. Data Parallelism Model o  OpenCLは、データ・パラレル実行モデルを利用 している。この点では、CUDAと直接に対応して いる。 o  OpenCLのプログラムは、二つの部分からなる。 一つは、OpenCLのデバイス上で実行される kernelの部分と、もう一つは、kernelの実行を管 理するhostプログラムの部分である。
  130. 130. OpenCLとCUDAの対応 OpenCL o  Kernel o  Host Program o  NDRange (Index Space) o  Work Item o  Work Group CUDA o  Kernel o  Host Program o  Grid o  Thread o  Block
  131. 131. OpenCLの最も基本的なアイデアと 4つのモデル OpenCLの最も基本的なアイデアを記述する 為に、次の4つの階層的なモデルを用いる。 p  Platform Model p  Memory Model p  Execution Model p  Programming Model
  132. 132. Platform Model
  133. 133. Memory Model
  134. 134. Execution Model
  135. 135. Platform Model
  136. 136. Platform Model
  137. 137. Platform Model o  このモデルは、一つ以上のOpenCLデバイスと 接続したhostからなる。 o  OpenCLデバイスは、一つ以上のcompute unit(CU)に分割され、それらはさらに、 一つ以 上の procesing element(PE)に分割され る。 o  デバイス上の計算は、processing unit上で行 われる。
  138. 138. Work Item
  139. 139. Memory Model
  140. 140. Memory Model
  141. 141. OpenCL Address Space o  __private (CUDA local) o  __local (CUDA shared) o  __constant (CUDA constant) o  __global (CUDA global)
  142. 142. Memory Model
  143. 143. Execution Model
  144. 144. KernelとHost program o  OpenCLの実行モデルは、OpenCLデバイス上 で実行されるkernelと、ホスト上で実行されるホ スト・プログラムという、二つの異なった実行単位 で定義される。 o  kernelは、ある計算に関連した”work”が行われ る場所である。この”work”は、グループ(workgroup)内で実行されるwork-itemを通じて行 われる。
  145. 145. Context kernelの実行は、hostによって管理されたcontext 上で行われる。contextは、kernelの実行環境を定 義する。contextの中には、次のリソースが含まれる 1.  Devices: OpenCLのデバイスの集まりは、hostによっ て利用される。 2.  Kernels: OpenCLのデバイスの上で走る、OpenCLの 関数 3.  Program Objects: kernelで実装されるプログラム のソース、あるいは実行可能なもの 4.  Memory Objects: hostとOpenCLデバイスに見える メモリー・オブジェクト
  146. 146. Command Queue o  hostとデバイスは、command-queueを通じ て相互作用する。一つのcommand-queueは、 一つのデバイスに関連付けられている。 command-queueに置かれた命令は、次の三 つのタイプからなる。 1.  Kernel-enqueue コマンド 2.  Memory コマンド 3.  Syncronization コマンド
  147. 147. Commandの State commandは、Event Object を通じて、Stateを知らせる。
  148. 148. Work item, Work group, NDRange o  kernel関数が起動されると、そのコードはwork item で実行される。これは、CUDAのthreadに 対応する。 o  work itemは、work groupを形成する。それ は、CUDAのthread Blockに対応する。 o  OpenCLのwork itemは、グローバルなディメン ション・インデックス・レンジ NDRangeで指定さ れる。インデックス・スペースは、work item と、 どのようにデータが work itemにマップされるか を定義する。
  149. 149. OpenCLとCUDAの対応 OpenCL o  Kernel o  Host Program o  NDRange (Index Space) o  Work Item o  Work Group CUDA o  Kernel o  Host Program o  Grid o  Thread o  Block
  150. 150. OpenCLとCUDAのKernel関数 __kernel void addVec (__global const float *a, __global const float *b, __global float *result) { int gid = get_global_id(0); result[gid] = a[gid] + b[gid]; OpenCL } __global__ void vecAddKernel( float* A_d, float* B_d, float* C_d, int n) {   int i = threadIdx.x + blockDim.x * blockIdx.x;   C_d[i] = A_d[i] + B_d[i]; CUDA }
  151. 151. Overview of the OpenCL parallel execution model.
  152. 152. OpenCL Execution Model
  153. 153. Work Item Work Group
  154. 154. Work Item Work Group
  155. 155. OpenCLとCUDAのインデックス OpenCL get_globa1_id(0) 意味 x次元のworkitemのGlobal index CUDAでの対応 blockIdx.x * blockDim.x + threadIdx.x get_local_id(0) work group内で のwork-itemの index(x次元) threadld.x get_global_size(0) NDRangeの大きさ gridDim.x * (x次元) blockDim.x get_local_size(0) work-groupの大 きさ(x次元) blockDim.x
  156. 156. Work Item Identifier
  157. 157. Programming Model
  158. 158. OpenCLプログラムの流れ o  OpenCLのプログラムは、基本的には、次のよう な流れになる 1.  OpenCLのプラットフォームを選択して、contextを生 成する 2.  デバイスを選んで、command-queueを生成する 3.  program objectを生成する 4.  kernel objectを生成し、それに与える引数の memory objectを生成する 5.  kernelを実行し、その結果を読み出す 6.  エラーをチェックする
  159. 159. Contextが、OpenCLデバイスの実行環境を与える
  160. 160. OpenCLの コンポーネント
  161. 161. OpenCL Program Sample
  162. 162. 初期化 デバイスを指定して、計算が実行されるcontextを作る cl_int err; cl_context context; cl_device_id devices; cl_command_queue cmd_queue; err = clGetDeviceIDs(CL_DEVICE_TYPE_GPU, 1, &devices, NULL); context = clCreateContext(0, 1, &devices, NULL, NULL, &err); cmd_queue = clCreateCommandQueue(context, devices, 0, NULL);
  163. 163. Discovering Devices clGetDeviceIDs
  164. 164. Device Property clGetDeviceInfo
  165. 165. メモリーの割り当て デバイスで利用されるリソースを割り当てる cl_mem ax_mem = clCreateBuffer(context, CL_MEM_READ_ONLY, atom_buffer_size, NULL, NULL); err = clEnqueueWriteBuffer(cmd_queue, ax_mem, CL_TRUE, 0,         atom_buffer_size, (void*)ax, 0,NULL,NULL); clFinish(cmd_queue);
  166. 166. Memory Buffer clCreateBuffer
  167. 167. Memory Buffer clEnqueueWriteBuffer
  168. 168. kernel/プログラムの生成 プログラムを読み込んで、カーネルを生成する。 cl_program program[1]; cl_kernel kernel[1]; program[0] = clCreateProgramWithSource(context,     1, (const char**)&program_source, NULL, &err); err = clBuildProgram(program[0], 0, NULL, NULL,      NULL, NULL); kernel[0] = clCreateKernel(program[0], "mdh", &err);
  169. 169. Building Programs clBuildProgram
  170. 170. 実行 カーネルに値を渡し、実行する。 size_t global_work_size[2], local_work_size[2]; global_work_size[0] = nx; global_work_size[1] = ny; local_work_size[0] = nx/2; local_work_size[1] = ny/2; err = clSetKernelArg(kernel[0], 0, sizeof(cl_mem), &ax_mem); err = clEnqueueNDRangeKernel(cmd_queue, kernel[0], 2, NULL,&global_work_size, &local_work_size, 0, NULL, NULL);
  171. 171. 終了処理 計算結果をホストに返し、リソースを解放する。 err = clEnqueueReadBuffer(cmd_queue, val_mem, CL_TRUE, 0, grid_buffer_size, val, 0, NULL, NULL); clReleaseKernel(kernel); clReleaseProgram(program); clReleaseCommandQueue(cmd_queue); clReleaseContext(context);
  172. 172. Execution / Read
  173. 173. OpenCL Design and Programming Guide for the Intel Xeon Phi Coprocessor http://software.intel.com/en-us/articles/ opencl-design-and-programming-guide-forthe-intel-xeon-phi-coprocessor
  174. 174. WebCL
  175. 175. http://www2012.wwwconference.org/proceedings/nocompanion/ DevTrack_Slides/008_WebCL_for_hardware_accelerated_web_applications.pdf
  176. 176. WebCLの目的 o  Webアプリで、GPU/マルチコアの高パフォーマ ンスのパラレル処理を可能にする。 n  異種混合のマルチコア・デバイスへのポータブルで効 率的なアクセス n  プラットフォームに依存しない、標準準拠のソリュー ション n  JavaScript環境で、OpenCLの能力を統合する n  マルチコアのリソースを備えたモバイル・プラットフォー ムで、高い計算要求に応える、インタラクティブなWeb アプリの幅を広げる
  177. 177. WebCLのデザイン・ゴール o  異種混合の処理要素上で、次のようなデザイン・ フィロソフィーの下で、一般的な目的のパラレル・ プログラミングを可能にすること。 n  デスクトップとモバイルをまたぐ、単一で均一な標準 n  一般的な目的のパラレル・プログラミングの為の、オー プンでロイヤリティ・フリーの標準 n  公開された仕様ドラフト、メーリングリスト、フォーラム 等で、オープンさを推進する
  178. 178. WebCLのアプローチ o  OpenCL標準と密に連携する n  開発者の親近感を保ち、受容を容易にする n  開発者が、OpenCLについての知識をWeb環境に移 すことを可能にする n  OpenCLとWebCLの進化とともに、両者が同期するこ とを容易にする o  OpenCL上のインターフェースであることを志向 する o  セキュリティにフォーカスしたデザイン o  デザインに基づく移植性
  179. 179. Nokia’s WebCL Prototype o  Nokia open sourced their prototype in May 2011 (LGPL). o  Web-based interactive photo editor utilizing GPU for image processing, through WebGL & Nokia’s OpenCL bindings for JavaScript. o  YouTube Demo: http://www.youtube.com/watch? v=9BF7zzUM1kY o  Add-on for Firefox 4 on Win/Linux(Firefox 5 coming soon) o  Visit http://webcl.nokiaresearch.com for binaries, source code, demos and tutorials.
  180. 180. Samsung WebCL Prototype o  Samsung open sourced their prototype WebCL implementation for WebKit in July 2011 (BSD license). o  Allows JavaScript to run computations on GPU. o  Demos on YouTube: http://www.youtube.com/ user/SamsungSISA Demos use WebGL for 3D rendering. o  Code available at http://code.google.com/p/webcl/ o  For comparison, same computations were also done in pure JavaScript. - WebCL gave performance increases of up to 100x.
  181. 181. WebCL Working Draft 2013/10/23 https://cvs.khronos.org/svn/repos/ registry/trunk/public/webcl/spec/ latest/index.html
  182. 182. interface WebCL { // Functions sequence<WebCLPlatform> getPlatforms(); WebCLContext? createContext( optional WebCLContextProperties properties); sequence<DOMString>? getSupportedExtensions(); object? enableExtension(DOMString extensionName); void waitForEvents( sequence<WebCLEvent> eventWaitList, optional WebCLCallback whenFinished); void releaseAll();
  183. 183. dictionary WebCLContextProperties { sequence<WebCLDevice>? devices = null;  // Default: let the implementation decide WebCLPlatform? platform = null;  // Default: let the implementation decide CLenum deviceType = 0x1;   // 0x1 == WebCL.DEVICE_TYPE_DEFAULT };
  184. 184. interface WebCLPlatform { any getInfo(CLenum name); sequence<WebCLDevice> getDevices( optional CLenum deviceType); sequence<DOMString>? getSupportedExtensions(); object? enableExtension(DOMString extensionName); }; interface WebCLDevice { any getInfo(CLenum name); sequence<DOMString>? getSupportedExtensions(); object? enableExtension(DOMString extensionName); };
  185. 185. interface WebCLContext { WebCLBuffer createBuffer( CLenum memFlags, CLuint sizeInBytes, optional ArrayBufferView hostPtr); WebCLCommandQueue createCommandQueue( optional WebCLDevice? device, optional CLenum properties); WebCLImage createImage(CLenum memFlags, WebCLImageDescriptor descriptor, optional ArrayBufferView hostPtr); WebCLProgram createProgram(DOMString source); WebCLSampler createSampler( CLboolean normalizedCoords, CLenum addressingMode, CLenum filterMode); WebCLUserEvent createUserEvent(); any getInfo(CLenum name); ...
  186. 186. interface WebCLCommandQueue { ////////////////////////////////////////////////////////// // // Copying: Buffer <-> Buffer, Image <-> Image, // Buffer <-> Image // void enqueueCopyBuffer( WebCLBuffer srcBuffer, WebCLBuffer dstBuffer, CLuint srcOffset, CLuint dstOffset, CLuint numBytes, optional sequence<WebCLEvent>? eventWaitList, optional WebCLEvent? event);
  187. 187. // interface WebCLCommandQueue ///////////////////////////////////////////////////////// // // Reading: Buffer -> Host, Image -> Host // void enqueueReadBuffer( WebCLBuffer buffer, CLboolean blockingRead, CLuint bufferOffset, CLuint numBytes, ArrayBufferView hostPtr, otional sequence<WebCLEvent>? eventWaitList, optional WebCLEvent? event);
  188. 188. // interface WebCLCommandQueue //////////////////////////////////////////////////// // // Writing: Host -> Buffer, Host -> Image // void enqueueWriteBuffer( WebCLBuffer buffer, CLboolean blockingWrite, CLuint bufferOffset, CLuint numBytes, ArrayBufferView hostPtr, optional sequence<WebCLEvent>? eventWaitList, optional WebCLEvent? event);
  189. 189. // interface WebCLCommandQueue /////////////////////////////////////////////////////////// // // Executing kernels // void enqueueNDRangeKernel( WebCLKernel kernel, CLuint workDim, sequence<CLuint>? globalWorkOffset, sequence<CLuint> globalWorkSize, sequence<CLuint>? localWorkSize, optional sequence<WebCLEvent>? eventWaitList, optional WebCLEvent? event);
  190. 190. // interface WebCLCommandQueue ///////////////////////////////////////////////////////// // // Synchronization // void enqueueMarker(WebCLEvent event); void enqueueBarrier(); void enqueueWaitForEvents ( sequence<WebCLEvent> eventWaitList); void finish(); void flush();
  191. 191. // interface WebCLCommandQueue //////////////////////////////////////////////////////////// // // Querying command queue information // any getInfo(CLenum name); void release(); };
  192. 192. interface WebCLMemoryObject { any getInfo(CLenum name); void release(); };
  193. 193. interface WebCLBuffer : WebCLMemoryObject { WebCLBuffer createSubBuffer( CLenum memFlags, CLuint origin, CLuint sizeInBytes); }; interface WebCLImage : WebCLMemoryObject { WebCLImageDescriptor getInfo(); }; interface WebCLSampler { any getInfo(CLenum name); void release(); };
  194. 194. interface WebCLProgram { any getInfo(CLenum name); any getBuildInfo( WebCLDevice device, CLenum name); void build(optional WebCLDevice>? devices, optional DOMString? options, optional WebCLCallback whenFinished); WebCLKernel createKernel(DOMString kernelName); sequence<WebCLKernel> createKernelsInProgram(); void release(); };
  195. 195. interface WebCLKernel { any getInfo(CLenum name); any getWorkGroupInfo(WebCLDevice device, CLenum name); void setArg(CLuint index, WebCLMemoryObject value); void setArg(CLuint index, WebCLSampler value); void setArg(CLuint index, ArrayBufferView value); void release(); };
  196. 196. [Constructor] interface WebCLEvent { readonly attribute CLenum status; readonly attribute WebCLMemoryObject buffer; any getInfo(CLenum name); any getProfilingInfo(CLenum name); void setCallback(CLenum commandExecCallbackType, WebCLCallback notify); void release(); };
  197. 197. WebCL Hardware-Accelerated Web Application http://download.tizen.org/misc/media/ conference2012/tuesday/ballroom-b/ 2012-05-08-1415-1455-webcl_for_hardwareaccelerated_web_applications.pdf
  198. 198. WebCL: Initialization <script> var platforms = WebCL.getPlatforms(); var devices = platforms[0]. getDevices(WebCL.DEVICE_TYPE_GPU); var context = WebCL.createContext( { WebCLDevice: devices[0] } ); var queue = context.createCommandQueue(); </script>
  199. 199. WebCL: Create Kernel <script id="squareProgram" type="x-kernel"> __kernel square( __global float* input, __global float* output, const unsigned int count) { int i = get_global_id(0); if(i < count) output[i] = input[i] * input[i]; } </script>
  200. 200. WebCL: Create Kernel <script> var programSource = getProgramSource("squareProgram"); // JavaScript function using DOM APIs var program = context.createProgram(programSource); program.build(); var kernel = program.createKernel("square"); </script>
  201. 201. WebCL: Run Kernel 1 <script> … var inputBuf = context.createBuffer(WebCL.MEM_READ_ONLY, Float32Array.BYTES_PER_ELEMENT * count); var outputBuf = context.createBuffer(WebCL.MEM_WRITE_ONLY, Float32Array.BYTES_PER_ELEMENT * count); var data = new Float32Array(count); // populate data … queue.enqueueWriteBuffer(inputBuf, data, true); // last arg indicates API is blocking
  202. 202. WebCL: Run Kernel 2 kernel.setKernelArg(0, inputBuf); kernel.setKernelArg(1, outputBuf); kernel.setKernelArg(2, count, WebCL.KERNEL_ARG_INT); var workGroupSize = kernel.getWorkGroupInfo(devices[0], WebCL.KERNEL_WORK_GROUP_SIZE); queue.enqueueNDRangeKernel(kernel, [count], [workGroupSize]);
  203. 203. WebCL: Run Kernel 3 queue.finish(); // this API blocks queue.enqueueReadBuffer(outputBuf, data, true); // last arg indicates API is blocking </script>
  204. 204. WebCL: Image Object Creation o  From Uint8Array() <script> var bpp = 4; // bytes per pixel var pixels = new Uint8Array(width * height * bpp); var pitch = width * bpp; var clImage = context.createImage(WebCL.MEM_READ_ONLY, { channelOrder:WebCL.RGBA, channelType:WebCL.UNORM_INT8, size:[width, height], pitch:pitch } ); </script>
  205. 205. WebCL: Image Object Creation o  From <img> or <canvas> or <video> <script> var canvas = document.getElementById("aCanvas"); var clImage = context.createImage(WebCL.MEM_READ_ONLY, canvas); // format, size from element </script>
  206. 206. WebCL: Vertex Buffer Initialization <script> WebGL var points = new Float32Array(NPOINTS * 3); var glVertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, points, gl.DYNAMIC_DRAW); var clVertexBuffer = context.createFromGLBuffer( WebCL.MEM_READ_WRITE, glVertexBuffer); kernel.setKernelArg(0, NPOINTS, WebCL WebCL.KERNEL_ARG_INT); kernel.setKernelArg(1, clVertexBuffer); </script>
  207. 207. WebCL: Vertex Buffer Update and Draw <script> WebCL function DrawLoop() { queue.enqueueAcquireGLObjects([clVertexBuffer]); queue.enqueueNDRangeKernel(kernel, [NPOINTS], [workGroupSize]); queue.enqueueReleaseGLObjects([clVertexBuffer]); gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer); gl.clear(gl.COLOR_BUFFER_BIT); gl.drawArrays(gl.POINTS, 0, NPOINTS); gl.flush(); WebGL } </script>
  208. 208. Texture Initialization <script> var glTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, glTexture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); var clTexture = context.createFromGLTexture2D( WebCL.MEM_READ_WRITE, gl.TEXTURE_2D, glTexture); kernel.setKernelArg(0, NWIDTH, WebCL.KERNEL_ARG_INT); kernel.setKernelArg(1, NHEIGHT, WebCL.KERNEL_ARG_INT); kernel.setKernelArg(2, clTexture);
  209. 209. Texture Update and Draw <script> function DrawLoop() { queue.enqueueAcquireGLObjects([clTexture]); queue.enqueueNDRangeKernel(kernel, [NWIDTH, NHEIGHT], [tileWidth, tileHeight]); queue.enqueueReleaseGLObjects([clTexture]); gl.clear(gl.COLOR_BUFFER_BIT); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, glTexture); gl.flush(); } </script>
  210. 210. WebCL: Initialization (draft) <script> var platforms = WebCL.getPlatforms(); var devices = platforms[0]. getDevices(WebCL.DEVICE_TYPE_GPU); var context = WebCL.createContext( { WebCLDevice: devices[0] } ); var queue = context.createCommandQueue(); </script>
  211. 211. WebCL: Initialization (draft) <script> var platforms = WebCL.getPlatforms(); var devices = platforms[0]. getDevices(WebCL.DEVICE_TYPE_GPU); var context = WebCL.createContext( { WebCLDevice: devices[0] } ); var queue = context.createCommandQueue(); </script>
  212. 212. 参考資料
  213. 213. OpenCL Design and Programming Guide for the Intel Xeon Phi Coprocessor http://software.intel.com/en-us/articles/ opencl-design-and-programming-guide-forthe-intel-xeon-phi-coprocessor
  214. 214. Why is this paper needed? o  While OpenCL is a portable programming model, the performance portability is not guaranteed. Traditional GPUs and the Intel Xeon Phi coprocessor have different HW designs. Their differences are such that they benefit from different application optimizations. For example, traditional GPUs rely on the existence of fast shared local memory, which the programmer needs to program explicitly. Intel Xeon Phi coprocessor includes fully coherent cache hierarchy, similar to regular CPU caches, which automatically speed up memory accesses.
  215. 215. o  Another example: while some traditional GPUs are based on HW scheduling of many tiny threads, Intel Xeon Phi coprocessors rely on the device OS to schedule medium size threads. These and other differences suggest that applications usually benefit from tuning to the HW they’re intended to run on.
  216. 216. Will I need to have different OpenCL optimizations for different devices? o  Not necessarily. Will you add a small #ifdef in your code to run 50% faster on Intel Xeon Phi coprocessor? Will you duplicate a 1000-line file for that? Would you do it for only 10% speedup? Or, maybe you would prefer adding the optimization unconditionally and pay 10% slowdown on other devices for 50% improvement on Intel Xeon Phi coprocessor? It is totally your decision. In some cases, you will need to make the tradeoff between cross device performance and maintainability of your OpenCL application.
  217. 217. o  We really encourage developers to explore the performance potential of the Intel Xeon Phi coprocessor, using the guidelines available in this document and then decide based on the performance numbers. This document doesn’t intend to answer all the questions, but instead give you some tools to answer them yourself.
  218. 218. o  An Intel Xeon Phi coprocessor contains many cores, each with a 512-bit vector arithmetic unit, capable of executing SIMD vector instructions. An L1 cache is included in each core (32 KB data + 32 KB instructions). An L2 cache is associated with each core (512 KB combined Data and Instr, L1 D cache is inclusive). A high-speed interconnect allows data transfer between the L2 caches and the memory subsystem. Each core can execute up to four HW threads simultaneously.
  219. 219. o  This simultaneous multi-threading helps hide instruction and memory latencies. OpenCL hides most of these details from the programmer.
  220. 220. Key Intel Xeon Phi Coprocessor Performance Aspects o  Multi-threading parallelism o  Intel Xeon Phi coprocessor HW includes many cores depending on the SKU (I assume 60 in this paper). Each core is capable of running up to four HW threads. In most cases, populating the 240 threads with tasks is essential to maximize performance. The exact number of HW threads can be queried with the clGetDeviceInfor(NUM_COMPUTE_UNITS); interface.
  221. 221. o  In Core Vectorization o  The vector size in the Intel Xeon Phi coprocessor is 512 bit wide SIMD. Typically, this vector represents 8 double precision floating point numbers, or 16 single precision floating point numbers. Each Intel Xeon Phi coprocessor core can issue a single vector computation instruction per cycle.
  222. 222. o  PCI Express* (PCIe) Bus Interface o  The Intel Xeon Phi coprocessor resides on the PCIe bus. Transferring data over the PCIe bus has the highest latency and the lowest bandwidth. As you would do in any other PCIe device, you should reduce this traffic to a minimum.
  223. 223. o  Memory subsystem o  The Intel Xeon Phi coprocessor includes three levels of memory (GDDR, L2 cache, and L1 cache). The following table includes important cache information: L1 (Data + Instructions) Shared L2 Total Size 32 KB + 32 KB 512 KB Miss Latency 15-30 cycles 500-1000 cycles
  224. 224. o  Since the Intel Xeon Phi coprocessor is an inorder machine, the latency of memory accesses has significant impact on software performance. Luckily, the programmer can reduce these latencies. Prefetches are one of the tools that can help hide memory latencies. We will discuss it in more detail later.
  225. 225. Data Access Pattern o  Accessing memory consecutively is the fastest way to access memory on the Intel Xeon Phi coprocessor. It improves cache efficiency, reduces the number of TLB (Translation Lookaside Buffer) misses, and allows the HW prefetcher to kick in.
  226. 226. Mapping the OpenCL constructs to Intel Xeon Phi coprocessor o  Understanding how the key OpenCL constructs are implemented on the Intel Xeon Phi coprocessor will help you better design your application to take advantage of the coprocessor’s HW. It will also help you avoid the coprocessor’s performance pitfalls.
  227. 227. o  Conceptually, at initialization time, the OpenCL driver creates 240 SW threads and pins them to the HW threads (for a 60-core configuration). Then, following a clEnqueueNDRange() call, the driver schedules the work groups (WG) of the current NDRange on the 240 threads. A WG is the smallest task being scheduled on the threads. So calling clEnqueueNDRange() with less than 240 WGs, leaves the coprocessor underutilized.
  228. 228. o  The OpenCL compiler creates an optimized routine that executes a WG. This routine is built from up to three nested loops, as shown in the following pseudo code: 1: __Kernel ABC(…) 2: For (int i = 0; i < get_local_size(2); i++) 3: For (int j = 0; j < get_local_size(1); j++) 4: For (int k = 0; k < get_local_size(0); k++) 5: Kernel_Body;
  229. 229. o  Note that the innermost loop is used for dimension zero of the NDRange. This directly impacts the access pattern of your performance critical code. It also impacts the implicit vectorization efficiency.
  230. 230. o  The OpenCL compiler implicitly vectorizes the WG routine based on dimension zero loop, i.e., the dimension zero loop is unrolled by the vector size. So the WG code with vectorization looks like: 1: __Kernel ABC(…) 2: For (int i = 0; i < get_local_size(2); i++) 3: For (int j = 0; j < get_local_size(1); j++) 4: For (int k = 0; k < get_local_size(0); k += VECTOR_SIZE) 5: Vector_Kernel_Body;
  231. 231. o  The vector size of Intel Xeon Phi coprocessor is 16, regardless of the data types used in the kernel. However, in the future, we may increase the vectorization size to allow more instruction level parallelism.
  232. 232. Exposing algorithm parallelism o  While the OpenCL specification provides various ways to express parallelism and concurrency, some of them will not map well to Intel Xeon Phi coprocessor. We will show you how the key OpenCL constructs are mapped to the coprocessor, so you can design your application to exploit its parallelism.
  233. 233. Multi-threading o  To get good utilization of the 240 HW threads, it’s best to have more than 1000 WGs per NDRange. Having 180‒240 WGs per NDRange will provide basic threads utilization; however, the execution may suffer from poor loadbalancing and high invocation overhead. o  Recommendation: Have at least 1000 WGs per NDRange to optimally utilize the Intel Xeon Phi coprocessor HW threads. Applications with NDRange of 100 WGs or less will suffer from serious under-utilization of threads.
  234. 234. o  Single WG execution duration also impacts the threading efficiency. Lightweight WGs are also not recommended, as these may suffer from relatively high overheads.
  235. 235. Vectorization o  OpenCL on Intel Xeon Phi coprocessor includes an implicit vectorization module. The OpenCL compiler automatically vectorizes the implicit WG loop over the work items in dimension zero (see example above). The vectorization width is currently 16, regardless of the data type used in the kernel. In future implementations, we may vectorize even 32 elements. As OpenCL work items are guaranteed to be independent, the OpenCL vectorizer needs no feasibility analysis to apply vectorization.
  236. 236. o  However, the vectorized kernel is only used if the local size of dimension zero is greater than or equal to 16. Otherwise, the OpenCL runtime runs scalar kernel for each of the work items. If the WG size at dimension zero is not divisible by 16, then the end of the WG needs to be executed by scalar code. This isn’t an issue for large WGs, e.g., 1024 items at dimension zero, but is for WGs of size 31 on dimension zero.
  237. 237. o  Recommendation 1: Don’t manually vectorize kernels, as the OpenCL compiler is going to scalarize your code to prepare it for implicit vectorization. o  Recommendation 2: Avoid using a WG size that is not divisible by 32 (16 will work for now).
  238. 238. Work-Item-ID nonuniform control flow o  In this section, we explain the difference between uniform and nonuniform control flow, in the context of implicit vectorization. It is important to understand because uniform control flow may have small negative impacts on performance. But nonuniform control flow creates significant performance overhead within the innermost NDRange dimension. The uniformity with respect to the vectorized loop (dimension zero) matters.
  239. 239. Uniform branch example: o  A branch is uniform if it is statically guaranteed that all work items within a WG execute the same side of the branch. 1: //isSimple is a kernel argument 2: Int LID = get_local_id(0); 3: If (isSimple == 0) 4: Res = buff[LID];
  240. 240. Nonuniform branch example: 1: Int LID = get_local_id(0); 2: If (LID == 0) 3: Res = -1; Another uniform branch example: 1: Int LID = get_local_id(1); 2: //Uniform as the IF is based on dimension one, while vectorization on dimension on. 3: If (LID == 0) 4: Res = -1;
  241. 241. o  While vectorizing, the compiler has to linearize (flatten) any code dominated by nonuniform control flow via predication. The first and major cost of predication is the execution of both sides of the branch. Additional penalties result from the masked execution. o  Recommendation: Avoid branches, especially those that are nonuniform on dimension zero.
  242. 242. // Assuming the following original kernel code: 1: Int gid = get_global_id(0); 2: If(gid % 32 == 0) 3: Res = HandleEdgeCase(); 4: Else 5: Res = HandleCommonCase(); 6: End // After vectorization (and predication), // the code looks like: 1: int16 gid = get16_global_id(0); 2: uint mask; 3: Mask = compare16int((gid % broadcast16(32)), 0) 4: res_if = HandleEdgeCase(); 5: res_else = HandleCommonCase(); 6: Res = (res_if & mask) | (res_else & not(mask)); // Note that both the IF and the ELSE are executed // for all of the work items.
  243. 243. Data Alignment o  For various reasons, memory access that is vector-size-aligned is faster than unaligned memory access. In the Intel Xeon Phi coprocessor, OpenCL buffers are guaranteed to start on a vector-size-aligned address. However, this only guarantees that the first WG starts at an aligned address. To guarantee that all WGs start at a properly aligned location, the WG size (local size) needs to be divisible by 16, or even by 32 if you want to take advantage of potential product improvements.
  244. 244. o  Calling EnqueueNDRange with local size NULL, lets the OpenCL driver choose the best WG size for you. The driver should be smart enough to choose a WG size matching the alignment requirements. However, the programmer needs to make sure that the global size is divisible by VECTOR_SIZE and the quotient is big enough to allow the runtime efficient split to WGs. “Big enough” is 1,000,000 in cases of a small kernel and 1000 in the case of a huge kernel including a 1000 iteration loop in the kernel. Also NDRange offsetting can break the alignment.
  245. 245. o  Recommendation 1: Don’t use NDrange offset. If you have to use an offset, then make it a multiple of 32, or at least a multiple of 16. o  Recommendation 2: Use local size that is a multiple of 32, or at least of 16.
  246. 246. Design your algorithm to benefit from the Intel Xeon Phi coprocessor memory subsystem o  Since Intel Xeon Phi coprocessor is an in-order machine, it is very sensitive to memory latencies. Memory-related optimizations, at the application level, can lead to 2X-4X performance speedup.
  247. 247. Intra WG data reuse o  Designing your application to maximize the amount of data reuse from the caches is the first memory optimization to apply. However, only certain algorithms need to reuse data. For example, adding two matrices involves no opportunity to reuse any data. But multiplying two matrices (GEMM) involves significant data reuse. Therefore, it is an obvious candidate for blocking/tiling optimization. Please see more details in the Intel SDK for OpenCL Applications XE – Optimization Guide.
  248. 248. o  To benefit from data reuse, you need to take into account the WG implicit loop(s), as described earlier in this document. The programmer’s control over these loops is through the local size definition. The programmer can add additional loop(s) (explicit) in the kernel.
  249. 249. Cross WG data reuse o  Cross-group data reuse is a greater challenge. Currently, OpenCL on Intel Xeon Phi coprocessor doesn’t allow enough control over the WGs scheduling. Therefore, cross WG data reuse is almost impossible. We will keep this section as a placeholder for future development.
  250. 250. Data access pattern o  Consecutive data access usually allows the best memory system performance. When one considers consecutive memory access, understanding the structure of the WG implicit loops is crucial. The innermost implicit loop is the loop over dimension zero. If your kernel introduces no additional (explicit) loop, then you should try having most of your memory accesses consecutive with that implicit dimension zero loop in mind. For example: o  The following code accesses the 2D buffers consecutively in memory (recommended):
  251. 251. The following code accesses the 2D buffers consecutively in memory (recommended): 1: __kernel ABC(…){ 2: int ID1 = get_global_id(1); 3: int ID0 = get_global_id(0); 4: res[ID1][ID0] = param1 * buffer[ID1][ID0]; 5: } The following code doesn’t access the 2D buffers consecutively in memory (not recommended): 1: __kernel ABC(…){ 2: int ID1 = get_global_id(1); 3: int ID0 = get_global_id(0); 4: res[ID0][ID1] = param1 * buffer[ID0][ID1]; 5: }
  252. 252. o  The second code example scans the 2D buffers “column major.” With vectorization, it results in double faults, namely: 1) The input vector data need to be gathered along the column from 16 consecutive rows. The result is stored via scatter instructions to 16 different rows. Both operations perform slowly. 2) Memory access is not consecutive, iteration to iteration. Both of these increase the pressure on the TLB and prevent prefetching.
  253. 253. Simple one dimension example (recommended): Consecutive access: 1: Int id = get_global_id(0); 2: A[id]= B[id]; Non-Consecutive access (not recommended): 1: Int id = get_global_id(0); 2: A[id*4] = B[id*4] Recommendation: Use ID(0) to index memory consecutively within the row. With explicit 2D buffer: buffer[ID1][ID0]. With 2D indexing into 1D buffer: buffer[STRIDE * ID1 + ID0]
  254. 254. o  If your kernel includes an explicit loop, then you should remember that the implicit vectorization is still based on the ID(0) implicit loop. So accessing buffers through the OpenCL IDs should follow the recommendation above (buffer[ID1][ID0]). This will keep vector access consecutive and efficient. Accessing buffers through the inner loop index (idx), will be consecutive within the inner loop (buffer[ID1] [idx]) and will be uniform to the vectorized loop, which is excellent! However, mixing ID0 and idx should be avoided. For example, buffer[ID0][idx] is strided to the vectorized loop, therefore will result in gather/scatter.
  255. 255. Data layout o  Pure SOA (Structure-of-Arrays) data layout results in simple and efficient vector loads and stores. However, spatial locality is lower, the pressure on the TLB is higher, and the number of pages used simultaneously can be higher. o  With AOS (Array-of-Structures) data layout, the generated vectorized kernel needs to load and store data via gather and scatter instructions, which are less efficient than simple vector load and store. However, for random access pattern, AOS layout is often more efficient than SOA because of better spatial locality.
  256. 256. o  Please remember that random access of SOA data layout creates gather and scatter instructions too. o  The third option is AOSOA—an array of structures of small arrays. The size of the small arrays should be 32 for the Intel Xeon Phi coprocessor. This would allow vectorization of up to 32 elements vector. 1: struct Point32 { float x[32], y[32], z[32]; }; 2: __kernel void ABC(__global Point32* ptrData)
  257. 257. o  AOSOA allows efficient vectorization using simple vector loads, while not overloading the TLB, nor spreading the accesses across many pages. The problem of AOSOA is the readability of the code. Most people don’t naturally think in AOSOA terms.
  258. 258. Data prefetching o  With the Intel Xeon Phi coprocessor being an in-order machine, data prefetching is an essential way to bring data closer to the cores, in parallel with other computations. Loads and stores are executed serially, with parallelism. For example, any two load instructions are executed entirely serially. The prefetch instruction is exceptional. It is executed in parallel to other instructions, including to other prefetch instructions. Therefore, prefetch instruction that hasn’t finished on time, can still improve the performance as this memory request executed in parallel to other instruction.
  259. 259. o  A cache miss means a thread stall plus a few cycles penalty to reissue the instruction. The Intel Xeon Phi coprocessor includes a simple automatic HW prefetcher to the L2. It takes some time for the HW prefetcher to kick in, and it needs to restart on every 4 KB virtual page boundary.
  260. 260. o  Automatic SW prefetches to the L1 and L2 are inserted by the OpenCL compiler for data accessed in future iterations, whenever it figures out (through analysis) that such can be inserted and provide benefit. The beta release includes partial support for automatic SW prefetching.
  261. 261. o  Manual prefetching can be inserted by the programmer into the OpenCL kernel, via the prefetch built-in. Currently, manual prefetches are inserted exactly at the location and to the address that the programmer requested, but these are limited to L2 prefetches. In the future, the OpenCL compiler may add both L2 and L1 prefetches for the PREFETCH built-in. It may also improve the location and stride indicated by the programmer. Manual prefetches should be inserted at least 500 cycles before the data is going to be actually used. Usually only the main input and output buffers need to be prefetched.
  262. 262. Local memory and Barriers o  While traditional GPUs include Shared Local Memory (SLM), which requires manual management, Intel Xeon Phi coprocessor includes a two-level cache system (automatic), similar to most modern CPUs. Therefore, using the OpenCL SLM provides no benefit on the Intel Xeon Phi coprocessor. Furthermore, local memory in the coprocessor is allocated on the regular GDDR memory and is supported by the cache system like any other memory. Therefore, it introduces additional overhead in terms of redundant data copy and management.
  263. 263. o  Recommendation: Avoid using Shared Local Memory on the Intel Xeon Phi coprocessor. o  The Intel Xeon Phi coprocessor includes no special HW support for barriers. Therefore, barriers are emulated by OpenCL on the coprocessor. We recommend avoiding the use of barriers. Also, splitting the kernel into two separate kernels will be slower than a barrier, so we don’t recommend taking this path either. o  As of the beta release, the combination of barrier and WG size nondivisible by 16, results in execution of a scalar kernel. Please avoid this combination. Currently, we don’t see a
  264. 264. Summary o  While designing your OpenCL application for Intel Xeon Phi coprocessor, you should pay careful attention to the following aspects: 1.  Include enough work groups within each NDRange—a minimum of 1000 is recommended. 2.  Avoid lightweight work groups. Don’t hesitate using the maximum local size allowed (currently 1024). Keep the WG size a multiple of 32. 3.  Avoid ID(0) dependent control flow. This allows efficient implicit vectorization.
  265. 265. 5.  Prefer consecutive data access. 6.  Data layout preferences: AOS for sparse random access; pure SOA or AOSOA(32) otherwise. 7.  Exploit data reuse through the caches within the WG—tiling/blocking. 8.  If auto-prefetching didn’t kick in, use the PREFETCH built-in to bring the global data to the cache 500‒1000 cycles before use. 9.  Don’t use local memory. Avoid using barriers.
  266. 266. End of World
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×