Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Common Lispで
GPGPU
関東GPGPU勉強会 #4
2016-08-21
gos-k
自己紹介
●
名前 : gos-k
– gos_k : twitter, bitbucket, qiita
– gos-k : github, hatenablog
●
仕事 : 渋谷の某社でWebプログラマ
– Common LispとかRe...
発表の流れ
1) Common Lispに関する簡単な説明
2) Common LispにおけるGPGPU関連の現状
3) Common LispでOpenCL
4) Common Lispでカーネルコードのマクロ展開
今流行りのLisp方言
●
Clojure
– JVMで動くヤツ
●
Common Lisp
– Lisp方言を寄せ集めたヤツ
●
Scheme
– 関数型のヤツ
●
Emacs Lisp
– Emacsで動くヤツ
今回はCommon Lisp...
Common Lispとは
●
1980年代に数々のLispマシンやLisp方言が生まれた
●
コミュニティ分裂の懸念を解消すべく、Common Lispとし
て標準化を行う
– 既存のLispから最良の機能を集結
– ANSIから1996年に...
関連用語
●
SBCL (Steel Bank Common Lisp)
– Common Lispの処理系
– 色々あるけど非商用の処理系ならとりあえずコレ
●
Quicklisp
– Common Lispのパッケージ管理ツール
– pip...
発表の流れ
1) Common Lispに関する簡単な説明
2) Common LispにおけるGPGPU関連の現状
3) Common LispでOpenCL
4) Common Lispでカーネルコードのマクロ展開
GPGPU対応状況
●
CUDA
– takagi/cl-cuda (github)
●
OpenCL API
– 3b/cl-opencl-3b (github)
– guicho271828/eazy-opencl (github)
– g...
発表の流れ
1) Common Lispに関する簡単な説明
2) Common LispにおけるGPGPU関連の現状
3) Common LispでOpenCL
4) Common Lispでカーネルコードのマクロ展開
cl-oclapi
●
3bさんのOpenCL APIは動くけど
– Quicklisp対応してない
– 何年もメンテされてない?
●
OpenCL 1.2 APIのラッパーをスクラッチから作った
– 数年だれもやってなかったネタなのに、gui...
oclcl
●
cl-cudaからフォークして、カーネル部分取り出し
– S式からCを生成
– マクロのサポート
– シンボルマクロのサポート
●
変更点
– キーワードの置換や組込み関数の拡充
●
__global__を__kernelにした...
発表の流れ
1) Common Lispに関する簡単な説明
2) Common LispにおけるGPGPU関連の現状
3) Common LispでOpenCL
4) Common Lispでカーネルコードのマクロ展開
Common Lispで?
●
Cでカーネル書きたくない
– 不便だから
– カーネルの言語は規格上はCのみ
– その他言語はAPI対応ばかりで、カーネルまで書けるのはあまりない
●
自分で作れるか
– Common Lispなら既にcl-cu...
Common Lispで?
●
マクロで変数が使える
●
マクロで関数が使える
●
マクロで条件分岐が使える
●
マクロでループが使える
●
マクロでプリント文が使える
●
マクロを一段階展開したものが得られる
マクロで普通にプログラミング出来る
例 : unroll
(defkernelmacro unroll ((n offset) &body body)
`(progn
,@(loop for i below n
collect `(symbol-macrolet ((,offse...
例 : unroll-let
(defkernelmacro unroll-let ((n offset vars) &body body)
(let ((unrolled-vars (gensym))
(collected-vars (gen...
例 : unroll-let
(defkernel test-unroll-let (void ((input0-buffer float*)
(input1-buffer float*)
(output-buffer float*)))
(l...
例 : unroll-let
int offset = (4 * (int)(get_global_id(0)));
{
float alfa898 = 0.0f;
float alfa899 = 0.0f;
float alfa900 = 0...
例 : unroll-sphere
(defkernelmacro unroll-sphere ((r vx vy vz) &body body)
`(progn
,@(loop for z from (- r) to r
append (lo...
例 : unroll-sphere
(defkernel test-unroll-sphere (void ((input-buffer float*)
(output-buffer float*)))
(let ((gx (to-int (g...
例 : unroll-let
int gx = (int)(get_global_id(0));
int gy = (int)(get_global_id(1));
int gz = (int)(get_global_id(2));
int s...
おわりに
●
Common LispでCUDAもOpenCLも出来る
●
カーネルのチューニングにCommon Lispの
マクロ使うと便利そう
Upcoming SlideShare
Loading in …5
×

Common LispでGPGPU

631 views

Published on

Common Lispに関する簡単な説明とGPGPU対応状況およびループアンロールをLispのマクロで書く事について

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

Common LispでGPGPU

  1. 1. Common Lispで GPGPU 関東GPGPU勉強会 #4 2016-08-21 gos-k
  2. 2. 自己紹介 ● 名前 : gos-k – gos_k : twitter, bitbucket, qiita – gos-k : github, hatenablog ● 仕事 : 渋谷の某社でWebプログラマ – Common LispとかReact.jsとか – それ以前は産業用機器のソフトや3D画像処理のチューニングの仕事 ● 趣味 : パンケーキ
  3. 3. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  4. 4. 今流行りのLisp方言 ● Clojure – JVMで動くヤツ ● Common Lisp – Lisp方言を寄せ集めたヤツ ● Scheme – 関数型のヤツ ● Emacs Lisp – Emacsで動くヤツ 今回はCommon Lispを扱う
  5. 5. Common Lispとは ● 1980年代に数々のLispマシンやLisp方言が生まれた ● コミュニティ分裂の懸念を解消すべく、Common Lispとし て標準化を行う – 既存のLispから最良の機能を集結 – ANSIから1996年に標準規格リリース ● 制御構造、再帰関数呼び出し、ガベージコレクション、インク リメンタルコンパイル、オブジェクトシステム、コンディション システム等々を持つ 参考文献 : Peter, 実践 Common Lisp, 2008
  6. 6. 関連用語 ● SBCL (Steel Bank Common Lisp) – Common Lispの処理系 – 色々あるけど非商用の処理系ならとりあえずコレ ● Quicklisp – Common Lispのパッケージ管理ツール – pipとかgemとかnpmとかの仲間? ● Roswell – 処理系管理ツール? – デフォルトでSBCLとQuicklispが入って、直ぐに使い始められる
  7. 7. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  8. 8. GPGPU対応状況 ● CUDA – takagi/cl-cuda (github) ● OpenCL API – 3b/cl-opencl-3b (github) – guicho271828/eazy-opencl (github) – gos-k/cl-oclapi (github) ● OpenCL C – gos-k/oclcl (github) CUDAもOpenCLも、ホストもデバイスも、 Common Lispで書ける
  9. 9. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  10. 10. cl-oclapi ● 3bさんのOpenCL APIは動くけど – Quicklisp対応してない – 何年もメンテされてない? ● OpenCL 1.2 APIのラッパーをスクラッチから作った – 数年だれもやってなかったネタなのに、guichoさんと数週間差でネタか ぶり – しかし、その他色々なライブラリの都合により、cl-oclapiがQuicklispの GPGPU関連で一番最初に登録される
  11. 11. oclcl ● cl-cudaからフォークして、カーネル部分取り出し – S式からCを生成 – マクロのサポート – シンボルマクロのサポート ● 変更点 – キーワードの置換や組込み関数の拡充 ● __global__を__kernelにしたり__synchronizeをbarrierにしたり – スカラ型ベクタ型のサポート拡大 – テストコードのOpenCL APIライブラリをeazy-openclとcl-oclapiに – Quicklisp登録済み
  12. 12. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  13. 13. Common Lispで? ● Cでカーネル書きたくない – 不便だから – カーネルの言語は規格上はCのみ – その他言語はAPI対応ばかりで、カーネルまで書けるのはあまりない ● 自分で作れるか – Common Lispなら既にcl-cudaがある ● これをベースにすればOpenCLも出来るのでは – マクロ使えばカーネル最適化に便利そう
  14. 14. Common Lispで? ● マクロで変数が使える ● マクロで関数が使える ● マクロで条件分岐が使える ● マクロでループが使える ● マクロでプリント文が使える ● マクロを一段階展開したものが得られる マクロで普通にプログラミング出来る
  15. 15. 例 : unroll (defkernelmacro unroll ((n offset) &body body) `(progn ,@(loop for i below n collect `(symbol-macrolet ((,offset ,i)) ,@body)))) (defkernel test-unroll (void ((input-buffer float*) (output-buffer float*))) (let ((offset (* 4 (to-int (get-global-id 0))))) (unroll (4 i) (set (aref output-buffer (+ offset i)) (aref input-buffer (+ offset i)))))) int offset = (4 * (int)(get_global_id(0))); output_buffer[(offset + 0)] = input_buffer[(offset + 0)]; output_buffer[(offset + 1)] = input_buffer[(offset + 1)]; output_buffer[(offset + 2)] = input_buffer[(offset + 2)]; output_buffer[(offset + 3)] = input_buffer[(offset + 3)];
  16. 16. 例 : unroll-let (defkernelmacro unroll-let ((n offset vars) &body body) (let ((unrolled-vars (gensym)) (collected-vars (gensym))) (setf unrolled-vars (loop for (name init) in vars collect (loop for i below n collect (list (gensym (symbol-name name)) init))) collected-vars (loop for i below n collect (mapcar #'list (mapcar #'car vars) (mapcar #'(lambda (x) (car (nth i x))) unrolled-vars)))) (append (list 'let (reduce #'append unrolled-vars)) (loop for expr in body append (loop for i below n collect `(symbol-macrolet ((,offset ,i) ,@(nth i collected-vars)) ,expr)))))) 中間変数定義もアンロール
  17. 17. 例 : unroll-let (defkernel test-unroll-let (void ((input0-buffer float*) (input1-buffer float*) (output-buffer float*))) (let ((offset (* 4 (to-int (get-global-id 0))))) (unroll-let (4 i ((alfa 0.0) (bravo 0.0))) (set alfa (aref input0-buffer (+ offset i))) (set bravo (aref input1-buffer (+ offset i))) (set (aref output-buffer (+ offset i)) (+ alfa bravo)))))
  18. 18. 例 : unroll-let int offset = (4 * (int)(get_global_id(0))); { float alfa898 = 0.0f; float alfa899 = 0.0f; float alfa900 = 0.0f; float alfa901 = 0.0f; float bravo902 = 0.0f; float bravo903 = 0.0f; float bravo904 = 0.0f; float bravo905 = 0.0f; alfa898 = input0_buffer[(offset + 0)]; alfa899 = input0_buffer[(offset + 1)]; alfa900 = input0_buffer[(offset + 2)]; alfa901 = input0_buffer[(offset + 3)]; bravo902 = input1_buffer[(offset + 0)]; bravo903 = input1_buffer[(offset + 1)]; bravo904 = input1_buffer[(offset + 2)]; bravo905 = input1_buffer[(offset + 3)]; output_buffer[(offset + 0)] = (alfa898 + bravo902); output_buffer[(offset + 1)] = (alfa899 + bravo903); output_buffer[(offset + 2)] = (alfa900 + bravo904); output_buffer[(offset + 3)] = (alfa901 + bravo905); }
  19. 19. 例 : unroll-sphere (defkernelmacro unroll-sphere ((r vx vy vz) &body body) `(progn ,@(loop for z from (- r) to r append (loop for y from (- r) to r append (loop for x from (- r) to r when (>= r (sqrt (+ (* z z) (* y y) (* x x)))) collect `(symbol-macrolet ((,vz ,z) (,vy ,y) (,vx ,x)) ,@body)))))) 半径rの球へのアクセスを展開
  20. 20. 例 : unroll-sphere (defkernel test-unroll-sphere (void ((input-buffer float*) (output-buffer float*))) (let ((gx (to-int (get-global-id 0))) (gy (to-int (get-global-id 1))) (gz (to-int (get-global-id 2))) (sx (to-int (get-global-size 0))) (sy (to-int (get-global-size 1))) (total 0.0)) (unroll-sphere (2 vx vy vz) (set total (+ total (aref input-buffer (+ (* (+ gz vz) sy sx) (* (+ gy vy) sx) (+ gx vx)))))) (set (aref output-buffer (+ (* gz sy sx) (* gy sx) gx)) total)))
  21. 21. 例 : unroll-let int gx = (int)(get_global_id(0)); int gy = (int)(get_global_id(1)); int gz = (int)(get_global_id(2)); int sx = (int)(get_global_size(0)); int sy = (int)(get_global_size(1)); float total = 0.0f; total = (total + input_buffer[(((((gz + -2) * sy) * sx) + ((gy + 0) * sx)) + (gx + 0))]); total = (total + input_buffer[(((((gz + -1) * sy) * sx) + ((gy + -1) * sx)) + (gx + -1))]); total = (total + input_buffer[(((((gz + -1) * sy) * sx) + ((gy + -1) * sx)) + (gx + 0))]); … (中略) ... total = (total + input_buffer[(((((gz + 1) * sy) * sx) + ((gy + 1) * sx)) + (gx + 0))]); total = (total + input_buffer[(((((gz + 1) * sy) * sx) + ((gy + 1) * sx)) + (gx + 1))]); total = (total + input_buffer[(((((gz + 2) * sy) * sx) + ((gy + 0) * sx)) + (gx + 0))]); output_buffer[((((gz * sy) * sx) + (gy * sx)) + gx)] = total;
  22. 22. おわりに ● Common LispでCUDAもOpenCLも出来る ● カーネルのチューニングにCommon Lispの マクロ使うと便利そう

×