Expression Templateを使った ベクトル演算のCUDAによる 実装と評価

Slides:



Advertisements
Similar presentations
1 広島大学 理学研究科 尾崎 裕介 石川 健一. 1. Graphic Processing Unit (GPU) とは? 2. Nvidia CUDA programming model 3. GPU の高速化 4. QCD with CUDA 5. 結果 6. まとめ 2.
Advertisements

Item 1:View C++ as a federation of languages. C++ はただの ”C のクラスがあるバージョン ” ではない → 例外安全 (29 項 ) 、テンプレート (41 項 ) 、オーバーロード等の導入によりデザインや目指すコードが 変化している プログラミング言語はあくまで言語.
2.5 プログラムの構成要素 (1)文字セット ① ASCII ( American Standard Code for Interchange ) JIS コードと同じ ② EBCDIC ( Extended Binary Coded Decimal for Information Code ) 1.
プログラミング実習 1 ・ 2 ク ラス 第 2 週目 担当教員 : 渡邊 直樹. 課題 2 ● 2 × 2型行列の固有値, 固有ベクトルを求め る EigMatrix.java というプログラムを作成せ よ。 ● 行列の各要素はコマンド・プロンプトから入力 ● 計算した結果もコマンド・プロンプトに表示.
配列の宣言 配列要素の初期値 配列の上限 メモリ領域 多次元配列 配列の応用
CPUとGPUの 性能比較 -行列計算およびN体問題を用いて-
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
LMNtalからC言語への変換の設計と実装
コンパイラ 第9回 コード生成 ― スタックマシン ―
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
はじめてのCUDA 〜CUDA事始め〜 はるにゃん Lv1くまー.
C言語講座 第4回 ポインタ.
プログラミング実習 1・2 クラス 第 1 週目 担当教員:  渡邊 直樹.
IT入門B2 ー 連立一次方程式 ー.
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
正方行列向け特異値分解の CUDAによる高速化
岩村雅一 知能情報工学演習I 第8回(後半第2回) 岩村雅一
文献名 “Performance Tuning of a CFD Code on the Earth Simulator”
ステンシル計算を対象とした 大規模GPUクラスタ向け 自動並列化フレームワーク
細かい粒度でコードの再利用を可能とするメソッド内メソッドのJava言語への導入
JAVA入門.
高速剰余算アルゴリズムとそのハードウェア実装についての研究
格子QCDにおけるGPU計算 広大理 尾崎裕介 共同研究者 石川健一.
情報工学演習I 第12回 C++の演習4(インライン展開).
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
AMR法フレームワークの様々なアーキテクチャへ向けた発展 研究背景と研究目的 Xeon Phi対応に向けた拡張
関数と配列とポインタ 1次元配列 2次元配列 配列を使って結果を返す 演習問題
最適化の方法 中田育男著 コンパイラの構成と最適化 朝倉書店, 1999年 第11章.
ローカル変数とグローバル変数 ローカル変数  定義された関数内だけで使用できる変数 グローバル変数 プログラム全体で使用できる変数.
はじめてのCUDA 〜CUDA事始め〜 はるにゃん Lv1くまー.
東京海洋大産学官連携研究員/技術コンサルタント 高須 知二 Tomoji TAKASU
プログラミング演習I 2003年5月7日(第4回) 木村巌.
岩村雅一 知能情報工学演習I 第8回(C言語第2回) 岩村雅一
実行時情報に基づく OSカーネルのコンフィグ最小化
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
アルゴリズムとデータ構造 補足資料5-1 「メモリとポインタ」
トーリックイデアルの グレブナ基底を求める アルゴリズム – F4およびF5 –
デジタル画像とC言語.
AdaPrec (提案手法) の初回の通信精度選択
先進的計算基盤システムシンポジウム SACSIS2007併設企画 マルチコアプログラミングコンテスト 「Cellスピードチャレンジ2007」
一時的な型 長谷川啓
GPUを用いた疎行列の格納形式による行列ベクトル積の評価
フロントエンドとバックエンドのインターフェース
C言語を用いたマシン非依存な JITコンパイラ作成フレームワーク
C言語ファミリー C# 高級言語(抽象的) Java オブジェクト指向 C++ C 機械語(原始的)
参照されないリテラル 長谷川啓
地域情報学 C言語プログラミング 第2回 変数・配列、型変換、入力 2017年10月20日
情報基礎Ⅱ (第1回) 月曜4限 担当:北川 晃.
高精細計算を実現するAMR法フレームワークの高度化 研究背景と研究目的 複数GPU間での袖領域の交換と効率化
アルゴリズムとプログラミング (Algorithms and Programming)
「マイグレーションを支援する分散集合オブジェクト」
アルゴリズムとデータ構造1 2009年6月15日
言語プロセッサ 第12日目 平成20年1月9日.
オブジェクト指向言語論 第二回 知能情報学部 新田直也.
情報実習I (第1回) 木曜4・5限 担当:北川 晃.
コンパイラ 2012年10月11日
プログラミング 4 文字列.
岩村雅一 知能情報工学演習I 第8回(後半第2回) 岩村雅一
岩村雅一 知能情報工学演習I 第8回(C言語第2回) 岩村雅一
アルゴリズムとデータ構造 2010年6月17日
フレンド関数とフレンド演算子.
演算子のオーバーロード.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
情報処理Ⅱ 2005年11月25日(金).
並列処理プロセッサへの 実数演算機構の開発
プログラミング演習II 2004年11月 2日(第3回) 理学部数学科・木村巌.
プログラミング入門2 第5回 配列 変数宣言、初期化について
C言語講座 四則演算  if ,  switch 制御文.
プログラミング 3 ポインタ(1).
Presentation transcript:

Expression Templateを使った ベクトル演算のCUDAによる 実装と評価 みずほ情報総研 二田晴彦 GPUシンポジウム 2010 2010年10月19日

発表内容 背景と目的 CUDA概要 Expression Templateによるベクトル演 算ライブラリの実装 評価 まとめ Copyright© 2010 Mizuho Information & Research Institute, Inc.

CUDAでプログラミングする際、ホス トコードとデバイスコードが分離して いる 1-1. 背景と問題点 CUDAでプログラミングする際、ホス トコードとデバイスコードが分離して いる 「プログラミングのハードルが高い」 ベクトル計算に関して、ホストコード のみの記述でGPU上でのベクトル演算 が可能なCUBLASがあるが・・・ 「記述が直観的でない」 「計算内容によっては、メモリ転送の無 駄が生じる」 Copyright© 2010 Mizuho Information & Research Institute, Inc.

一回目の加算の結果x+yが一時的に GPUのグローバルメモリにおかれる 1-2. CUBLASの記述例 ベクトル v = x + y + z 一回目の加算の結果x+yが一時的に GPUのグローバルメモリにおかれる int main() { // CPUメモリ確保(値のセット) float* x = (float*)malloc(N * sizef(float)); … // ベクトルをGPUにコピー cublasSetVector(N, sizeof(float), x, 1, xd, 1); // GPUで計算 cublasSaxpy(N, 1.0f, yd, 1, xd, 1); // x += y cublasSaxpy(N, 1.0f, zd, 1, xd, 1); // x += z // 結果をCPUに cublasGetVector(N, sizeof(float), xd, 1, v, 1); } Copyright© 2010 Mizuho Information & Research Institute, Inc.

ホストコードだけのプログラミングで メモリ転送に無駄のない演算が可能な ベクトル演算フレームワークを実装し 速度面での評価を行う 手段 1-3. 目的 ホストコードだけのプログラミングで メモリ転送に無駄のない演算が可能な ベクトル演算フレームワークを実装し 速度面での評価を行う 手段 Expression Template(式テンプレート)を使用 する 「式の構造をテンプレートで保持し、必要になった際に、計算する手法」 Copyright© 2010 Mizuho Information & Research Institute, Inc.

ベクトル計算(ホストコード) 1-4. 実装したフレームワーク デバイスコードは書く必要なし 計算部分(1.2f * xGPU + yGPU)は、手で書いたデ バイスコードと同等のものがコンパイル時に生 成される(特殊なツール不要 nvccを使うだけ) int main() {  // CPUメモリ確保(値のセット) float* x = (float*)malloc(N * sizef(float)); … // GPUにコピー GPU::Vector<N> xGPU = x; yGPU = y; vGPU = v; // GPUで計算(v = 1.2f * x + y) vGPU = 1.2f * xGPU + yGPU; // CPUに持ってくる vGPU.CopyToHost(v); Copyright© 2010 Mizuho Information & Research Institute, Inc.

ベクトル計算(ホストコード) この実現のためにC++の機能を多用 1-4. 実装したフレームワーク デバイスコードは書く必要なし 計算部分(1.2f * xGPU + yGPU)は、手で書いたデ バイスコードと同等のものがコンパイル時に生 成される(特殊なツール不要 nvccを使うだけ) int main() {  // CPUメモリ確保(値のセット) float* x = (float*)malloc(N * sizef(float)); … // GPUにコピー GPU::Vector<N> xGPU = x; yGPU = y; vGPU = v; // GPUで計算(v = 1.2f * x + y) vGPU = 1.2f * xGPU + yGPU; // CPUに持ってくる vGPU.CopyToHost(v); __global__ Kernel(float* v, float* x, float* y) { unsigned int i = threadIdx.x; v[i] = 1.2f * x[i] + y[i]; } この実現のためにC++の機能を多用 Copyright© 2010 Mizuho Information & Research Institute, Inc.

クラスの実体を渡す 2-1. CUDAがサポートするC++ 二つは同じ計算をす るコード 出力されるPTXも同じ になる class Mul { public: __device__ float operator[](size_t i) { return 2.0f * b[i];} float* b; }; template <class O> __global__ void kernel( float* a, O op) { int idx = threadIdx.x; a[idx] = op[idx]; } // ホストコード Mul mul; mul.b = b; kernel<<<1, 64>>>(a, mul); __global__ void kernel( float* a ,float* b) { int idx = threadIdx.x; a[idx] = 2.0f * b[idx]; } // ホストコード kernel<<<1, 64>>>(a, b); 二つは同じ計算をす るコード 出力されるPTXも同じ になる ver. 3.2RCで確認 Copyright© 2010 Mizuho Information & Research Institute, Inc.

2-2. 二つのコードの違い 「クラスの実体」をkernelに渡すやり方 は、kernelは1つだけあらかじめ書いてお き、ホストコードの書き方次第で様々な 計算が可能になる →ホストの記述で様々なデバイスコード class Sub {…}; // a = b – 2; template <class O> __global__ void kernel( float* a, O op) { int idx = threadIdx.x; a[idx] = op[idx]; } // ホストコード Mul mul; mul.b = b; kernel<<<1, 64>>>(a, mul); Sub sub; sub.b = b; kernel<<<1, 64>>>(a, sub); Copyright© 2010 Mizuho Information & Research Institute, Inc.

ソースコードに書いたkernelは一つでも実 際には、2つのPTXのエントリーができる (それぞれ乗算、減算に最適なコード) 以下のようなコードを書いた場合・・・ ソースコードに書いたkernelは一つでも実 際には、2つのPTXのエントリーができる (それぞれ乗算、減算に最適なコード) // ホストコード Mul mul; mul.b = b; kernel<<<1, 64>>>(a, mul); Sub sub; sub.b = b; kernel<<<1, 64>>>(a, sub); .entry _Z6kernelI5MulEvPfT_ ( .param .u32 __cudaparm__Z6kernelI5MulEvPfT__a, .param .align 4 .b8 __cudaparm__Z6kernelI5MulEvPfT__op[4]) .entry _Z6kernelI5SubEvPfT_ ( .param .u32 __cudaparm__Z6kernelI5SubEvPfT__a, .param .align 4 .b8 __cudaparm__Z6kernelI5SubEvPfT__op[4]) Copyright© 2010 Mizuho Information & Research Institute, Inc.

3-1. Expression Template前段階 書いたkernelは1つでもホスト側のコード によりGPU上で様々な計算が可能 例1:ベクトル v = x + y template <class L, class R> class Plus { public: Plus(const L& a, const R& b) : a_(a), b_(b) {} __device__ float operator[](size_t i) const { return a_[i] + b_[i]; } private: const L a_; const R b_; }; Kernel<<<1, 16>>>(v, Plus<float*, float*>(x, y)); Copyright© 2010 Mizuho Information & Research Institute, Inc.

3-2. Expression Template前段階 例2:ベクトル v = x + y + z ツリー構造で式を表現 ホストコードから任意の加算が可 能になるが、記述がすごく面倒く さい Kernel<<<1, 16>>>(v, Plus<Plus<float*, float*>, float*>( Plus<float*, float*>( x, y ), z ) ); v z x y Copyright© 2010 Mizuho Information & Research Institute, Inc.

GPUグローバルメモリにあるベクトル を表すGPU::Vectorクラスを生成 3-3. Expression Template 簡単な記述を可能にするために・・・ GPUグローバルメモリにあるベクトル を表すGPU::Vectorクラスを生成 +演算子をオーバーロードして、その 中では計算を行わずに、Plusオブジェ クトを返却 式の構造を保持することに GPU::Vectorに代入が行われる際に、 kernelに式構造を渡し、式を展開 →直観的な記述が可能に Copyright© 2010 Mizuho Information & Research Institute, Inc.

→ Expression Templateにより、ホスト コードからデバイスコードが生成され る 3-4. 今回実装した演算 ベクトル 基本的な演算 加算、スカラー倍 リダクション ノルム ステンシル計算 3ポイントのステンシル → Expression Templateにより、ホスト コードからデバイスコードが生成され る Copyright© 2010 Mizuho Information & Research Institute, Inc.

評価方法 実験諸元 4-1. 性能評価 種々の演算に対して、CUBLASとの速度比 較や出力されるPTXを確認する OS: Windows XP Pro (32bit) GPU: GeForce GTX 260 CUDA Toolkit: 3.2 RC コンパイラ: Visual Studio 2005 Pro 計算精度:単精度浮動小数点数 Copyright© 2010 Mizuho Information & Research Institute, Inc.

計算式 4-2. 2項のベクトル計算 v = a * x + y CUBLASホストコード 作成したフレームワークでの(ET)ホストコード float a = 2.0f; cublasAlloc(N, sizeof(float), (void**)&xd); cublasAlloc(N, sizeof(float), (void**)&yd); cublasSetVector(N, sizeof(float), x,1, xd, 1); cublasSetVector(N, sizeof(float), y,1, yd, 1); cublasSaxpy(N, a, xd, 1, yd, 1); float a = 2.0f; GPU::Vector<N> xd = x, yd = y, vd = v; vd = a * xd + yd; Copyright© 2010 Mizuho Information & Research Institute, Inc.

速度比較(CPU <-> GPUメモリ転送除) 4-3. 2項のベクトル計算の速度 速度比較(CPU <-> GPUメモリ転送除) ETとCUBLASが同等の速度 高速 Copyright© 2010 Mizuho Information & Research Institute, Inc.

計算式 4-4. 3項のベクトル計算 v = a * x + b * y + z CUBLASホストコード 作成したフレームワークでの(ET)ホストコード float a = 2.0f, b = 3.0f; // メモリ確保と転送 … cublasSaxpy(N, a, xd, 1, zd, 1); // zd += a * xd cublasSaxpy(N, b, yd, 1, zd, 1); // zd += b * yd float a = 2.0f, b = 3.0f; GPU::Vector<N> xd = x, yd = y, zd = z, vd = v; vd = a * xd + b * yd + zd; Copyright© 2010 Mizuho Information & Research Institute, Inc.

速度比較(CPU <-> GPUメモリ転送除) 4-5. 3項のベクトル計算の速度 速度比較(CPU <-> GPUメモリ転送除) ETがCUBLASよりも高速 メモリ転送の無駄が少ないため 高速 Copyright© 2010 Mizuho Information & Research Institute, Inc.

ホストコードに書かれたvd = a * xd + b * yd + zd;から生成されたPTX ld.param.u32 %r5, [paramop+24]; add.u32 %r6, %r5, %r4; ld.global.f32 %f1, [%r6+0]; // z[idx]をグローバルから ld.param.u32 %r7, [paramop+16]; add.u32 %r8, %r7, %r4; ld.global.f32 %f2, [%r8+0]; // y[idx]をグローバルから ld.param.f32 %f3, [paramop+12]; // bのロード mul.f32 %f4, %f2, %f3; // t1 = b * y[idx]の計算 ld.param.u32 %r9, [paramop+4]; add.u32 %r10, %r9, %r4; ld.global.f32 %f5, [%r10+0]; // x[idx]をグローバルから ld.param.f32 %f6, [paramop+0]; // aのロード mad.f32 %f7, %f5, %f6, %f4; // t2 = a * x[idx] + t1 add.f32 %f8, %f1, %f7; // v = t2 + z[idx] ld.param.u32 %r11, [a]; add.u32 %r12, %r11, %r4; st.global.f32 [%r12+0], %f8; // 結果をグローバルへストア 手で書いたkernelと同等のコードが生成 Copyright© 2010 Mizuho Information & Research Institute, Inc.

計算式 4-7. ベクトルのノルム計算 v = Norm(a * x + y) CUBLASホストコード 作成したフレームワークでの(ET)ホストコード // メモリ確保と転送 … cublasSaxpy(N, a, xd, 1, yd, 1); // yd += a * xd float r = cublasSnrm2(N, yd, 1); // r = Norm(yd) GPU::Vector<N> xd = x, yd = y; CPU::Scalar r; r = CalcNorm(a * xd + yd); Copyright© 2010 Mizuho Information & Research Institute, Inc.

速度比較(CPU <-> GPUメモリ転送除) 4-8.ベクトルのノルム計算の速度 速度比較(CPU <-> GPUメモリ転送除) ETがCUBLASよりも高速 メモリ転送の無駄が少ないため 高速 Copyright© 2010 Mizuho Information & Research Institute, Inc.

ラプラス方程式 差分化した計算式(反復計算) 4-9. ラプラス方程式(1次元) 作成したフレームワークでの(ET)ホストコード // GPUのグローバルメモリの準備(uはCPU上のメモリ) GPU::Vector<DIM> uNew = u, uCur = u; GPU::Vector<DIM> uTmp; // 計算ループ(反復計算) for (int i = 0; i < 100; ++i) { uNew = GPU::StencilOf3<F(0.5), 0, F(0.5)>(uCur); // ポインタスワップ uTmp = uNew; uNew = uCur; uCur = uTmp; } Copyright© 2010 Mizuho Information & Research Institute, Inc.

uNew = GPU::StencilOf3<F(0.5), 0, F(0.5)>(uCur)から生成されたPTX // globalメモリからシェアードメモリに読み込み … ld.shared.f32 %f5, [%r6+8]; // uCur[i+1]をsharedからロード mov.f32 %f6, 0f3f000000; // 定数0.5 mul.f32 %f7, %f5, %f6; // t1 = 0.5 * uCur[i+1] ld.shared.f32 %f8, [%r6+0]; // uCur[i-1]をsharedからロード mov.f32 %f9, 0f3f000000; // 定数0.5 mad.f32 %f2, %f8, %f9, %f7; // t2 = 0.5 * uCur[i-1] + t1 ld.param.u32 %r20, [a]; add.u32 %r21, %r20, %r7; st.global.f32 [%r21+0], %f2; // 結果をglobalメモリへ 手で書いたkernelと同等のコードが生成 Copyright© 2010 Mizuho Information & Research Institute, Inc.

波動方程式 差分化した計算式(反復計算) 4-11. 波動方程式(1次元) 作成したフレームワークでの(ET)ホストコード // GPUのベクトルの準備 GPU::Vector<N> uOld = u[0], uCur = u[1], uNew = u[2]; GPU::Vector<N> uTmpGpu; // 計算ループ(反復計算) for (int i = 2; i < M; ++i) { uNew = (2.0f * uCur) + (-1.0f * uOld) + alpha * GPU::StencilOf3<F(1), F(-2), F(1)>(uCur); uTmp = uOld; uOld = uCur; // ポインタ入れ替え uCur = uNew; uNew = uTmp; } Copyright© 2010 Mizuho Information & Research Institute, Inc.

まとめ 今後の課題 5. まとめ ベクトル演算のフレームワークを実装 ホストコードの直観的な記述のみで様々 なベクトルの計算がGPU上で可能に CUDAを使ったほかのアプリケーションでもExpression Templateを使うことで、簡単な記述も可能? 今後の課題 行列計算への対応 複数GPUの計算の対応 Copyright© 2010 Mizuho Information & Research Institute, Inc.

本発表に関する問い合わせ先 みずほ情報総研 情報・コミュニケーション部 二田 晴彦(ふただ はるひこ) 本発表以外のGPU最適化等に関する相談も受け付けております Copyright© 2010 Mizuho Information & Research Institute, Inc.