SlideShare a Scribd company logo
Common Lispで
GPGPU
関東GPGPU勉強会 #4
2016-08-21
gos-k
自己紹介
●
名前 : gos-k
– gos_k : twitter, bitbucket, qiita
– gos-k : github, hatenablog
●
仕事 : 渋谷の某社でWebプログラマ
– Common LispとかReact.jsとか
– それ以前は産業用機器のソフトや3D画像処理のチューニングの仕事
●
趣味 : パンケーキ
発表の流れ
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年に標準規格リリース
●
制御構造、再帰関数呼び出し、ガベージコレクション、インク
リメンタルコンパイル、オブジェクトシステム、コンディション
システム等々を持つ
参考文献 : Peter, 実践 Common Lisp, 2008
関連用語
●
SBCL (Steel Bank Common Lisp)
– Common Lispの処理系
– 色々あるけど非商用の処理系ならとりあえずコレ
●
Quicklisp
– Common Lispのパッケージ管理ツール
– pipとかgemとかnpmとかの仲間?
●
Roswell
– 処理系管理ツール?
– デフォルトでSBCLとQuicklispが入って、直ぐに使い始められる
発表の流れ
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)
– gos-k/cl-oclapi (github)
●
OpenCL C
– gos-k/oclcl (github)
CUDAもOpenCLも、ホストもデバイスも、
Common Lispで書ける
発表の流れ
1) Common Lispに関する簡単な説明
2) Common LispにおけるGPGPU関連の現状
3) Common LispでOpenCL
4) Common Lispでカーネルコードのマクロ展開
cl-oclapi
●
3bさんのOpenCL APIは動くけど
– Quicklisp対応してない
– 何年もメンテされてない?
●
OpenCL 1.2 APIのラッパーをスクラッチから作った
– 数年だれもやってなかったネタなのに、guichoさんと数週間差でネタか
ぶり
– しかし、その他色々なライブラリの都合により、cl-oclapiがQuicklispの
GPGPU関連で一番最初に登録される
oclcl
●
cl-cudaからフォークして、カーネル部分取り出し
– S式からCを生成
– マクロのサポート
– シンボルマクロのサポート
●
変更点
– キーワードの置換や組込み関数の拡充
●
__global__を__kernelにしたり__synchronizeをbarrierにしたり
– スカラ型ベクタ型のサポート拡大
– テストコードのOpenCL APIライブラリをeazy-openclとcl-oclapiに
– Quicklisp登録済み
発表の流れ
1) Common Lispに関する簡単な説明
2) Common LispにおけるGPGPU関連の現状
3) Common LispでOpenCL
4) Common Lispでカーネルコードのマクロ展開
Common Lispで?
●
Cでカーネル書きたくない
– 不便だから
– カーネルの言語は規格上はCのみ
– その他言語はAPI対応ばかりで、カーネルまで書けるのはあまりない
●
自分で作れるか
– Common Lispなら既にcl-cudaがある
●
これをベースにすればOpenCLも出来るのでは
– マクロ使えばカーネル最適化に便利そう
Common Lispで?
●
マクロで変数が使える
●
マクロで関数が使える
●
マクロで条件分岐が使える
●
マクロでループが使える
●
マクロでプリント文が使える
●
マクロを一段階展開したものが得られる
マクロで普通にプログラミング出来る
例 : 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)];
例 : 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))))))
中間変数定義もアンロール
例 : 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)))))
例 : 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);
}
例 : 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の球へのアクセスを展開
例 : 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)))
例 : 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;
おわりに
●
Common LispでCUDAもOpenCLも出来る
●
カーネルのチューニングにCommon Lispの
マクロ使うと便利そう

More Related Content

What's hot

Cython intro prelerease
Cython intro prelereaseCython intro prelerease
Cython intro prelerease
Shiqiao Du
 
ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用
ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用
ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用
MITSUNARI Shigeo
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングKiwamu Okabe
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
MITSUNARI Shigeo
 
Xbyakの紹介とその周辺
Xbyakの紹介とその周辺Xbyakの紹介とその周辺
Xbyakの紹介とその周辺
MITSUNARI Shigeo
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
MITSUNARI Shigeo
 
V6でJIT・部分適用・継続
V6でJIT・部分適用・継続V6でJIT・部分適用・継続
V6でJIT・部分適用・継続
7shi
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxpsMITSUNARI Shigeo
 
Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)
Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)
Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)MITSUNARI Shigeo
 
C++のビルド高速化について
C++のビルド高速化についてC++のビルド高速化について
C++のビルド高速化についてAimingStudy
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
MITSUNARI Shigeo
 
LLVM最適化のこつ
LLVM最適化のこつLLVM最適化のこつ
LLVM最適化のこつ
MITSUNARI Shigeo
 
マーク&スイープ勉強会
マーク&スイープ勉強会マーク&スイープ勉強会
マーク&スイープ勉強会
7shi
 
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
MITSUNARI Shigeo
 
Adding simpl GVN path into GHC
Adding simpl GVN path into GHCAdding simpl GVN path into GHC
Adding simpl GVN path into GHCKei Hibino
 
Rubyの御先祖CLUのお話(原本)
Rubyの御先祖CLUのお話(原本)Rubyの御先祖CLUのお話(原本)
Rubyの御先祖CLUのお話(原本)
洋史 東平
 
セミコロンレスc++
セミコロンレスc++セミコロンレスc++
セミコロンレスc++
京大 マイコンクラブ
 
Wavelet matrix implementation
Wavelet matrix implementationWavelet matrix implementation
Wavelet matrix implementationMITSUNARI Shigeo
 

What's hot (20)

Cython intro prelerease
Cython intro prelereaseCython intro prelerease
Cython intro prelerease
 
ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用
ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用
ElGamal型暗号文に対する任意関数演算・再暗号化の二者間秘密計算プロトコルとその応用
 
Nginx lua
Nginx luaNginx lua
Nginx lua
 
HaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミングHaskellではじめるCortex-M3組込みプログラミング
HaskellではじめるCortex-M3組込みプログラミング
 
フラグを愛でる
フラグを愛でるフラグを愛でる
フラグを愛でる
 
HPC Phys-20201203
HPC Phys-20201203HPC Phys-20201203
HPC Phys-20201203
 
Xbyakの紹介とその周辺
Xbyakの紹介とその周辺Xbyakの紹介とその周辺
Xbyakの紹介とその周辺
 
Intro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみたIntro to SVE 富岳のA64FXを触ってみた
Intro to SVE 富岳のA64FXを触ってみた
 
V6でJIT・部分適用・継続
V6でJIT・部分適用・継続V6でJIT・部分適用・継続
V6でJIT・部分適用・継続
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
 
Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)
Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)
Xeon PhiとN体計算コーディング x86/x64最適化勉強会6(@k_nitadoriさんの代理アップ)
 
C++のビルド高速化について
C++のビルド高速化についてC++のビルド高速化について
C++のビルド高速化について
 
高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装高速な倍精度指数関数expの実装
高速な倍精度指数関数expの実装
 
LLVM最適化のこつ
LLVM最適化のこつLLVM最適化のこつ
LLVM最適化のこつ
 
マーク&スイープ勉強会
マーク&スイープ勉強会マーク&スイープ勉強会
マーク&スイープ勉強会
 
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
準同型暗号の実装とMontgomery, Karatsuba, FFT の性能
 
Adding simpl GVN path into GHC
Adding simpl GVN path into GHCAdding simpl GVN path into GHC
Adding simpl GVN path into GHC
 
Rubyの御先祖CLUのお話(原本)
Rubyの御先祖CLUのお話(原本)Rubyの御先祖CLUのお話(原本)
Rubyの御先祖CLUのお話(原本)
 
セミコロンレスc++
セミコロンレスc++セミコロンレスc++
セミコロンレスc++
 
Wavelet matrix implementation
Wavelet matrix implementationWavelet matrix implementation
Wavelet matrix implementation
 

Similar to Common LispでGPGPU

ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
Kazuki Onishi
 
Slide
SlideSlide
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
Kiwamu Okabe
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
Masami Ichikawa
 
PBL1-v1-003j.pptx
PBL1-v1-003j.pptxPBL1-v1-003j.pptx
PBL1-v1-003j.pptx
NAIST
 
EmacsとGlossでお絵描きしてみるよ
EmacsとGlossでお絵描きしてみるよEmacsとGlossでお絵描きしてみるよ
EmacsとGlossでお絵描きしてみるよ
Kiwamu Okabe
 
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 HyのすすめLispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Satoshi imai
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)Takeshi Yamamuro
 
Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門
Fixstars Corporation
 
Real World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみたReal World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみたblackenedgold
 
Material
MaterialMaterial
Material
_TUNE_
 
PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptx
NAIST
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
Ransui Iso
 
Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_options
nyaocat
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Ransui Iso
 
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェアEmacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
Masaharu IWAI
 
StackExchangeで見たシステムプログラミング案件
StackExchangeで見たシステムプログラミング案件StackExchangeで見たシステムプログラミング案件
StackExchangeで見たシステムプログラミング案件
yaegashi
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
y_taka_23
 

Similar to Common LispでGPGPU (20)

Clojure
ClojureClojure
Clojure
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
Slide
SlideSlide
Slide
 
What is Metasepi?
What is Metasepi?What is Metasepi?
What is Metasepi?
 
x86とコンテキストスイッチ
x86とコンテキストスイッチx86とコンテキストスイッチ
x86とコンテキストスイッチ
 
PBL1-v1-003j.pptx
PBL1-v1-003j.pptxPBL1-v1-003j.pptx
PBL1-v1-003j.pptx
 
EmacsとGlossでお絵描きしてみるよ
EmacsとGlossでお絵描きしてみるよEmacsとGlossでお絵描きしてみるよ
EmacsとGlossでお絵描きしてみるよ
 
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 HyのすすめLispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
Lispmeetup #53 PythonベースのLisp方言、 Hyのすすめ
 
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
LLVMで遊ぶ(整数圧縮とか、x86向けの自動ベクトル化とか)
 
Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門Halide による画像処理プログラミング入門
Halide による画像処理プログラミング入門
 
Real World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみたReal World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみた
 
Material
MaterialMaterial
Material
 
PBL1-v1-006j.pptx
PBL1-v1-006j.pptxPBL1-v1-006j.pptx
PBL1-v1-006j.pptx
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_options
 
Gocon2013
Gocon2013Gocon2013
Gocon2013
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
 
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェアEmacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
Emacsでの翻訳 - Emacsで訳す、gettextで国際化されたソフトウェア
 
StackExchangeで見たシステムプログラミング案件
StackExchangeで見たシステムプログラミング案件StackExchangeで見たシステムプログラミング案件
StackExchangeで見たシステムプログラミング案件
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 

Common LispでGPGPU

  • 2. 自己紹介 ● 名前 : gos-k – gos_k : twitter, bitbucket, qiita – gos-k : github, hatenablog ● 仕事 : 渋谷の某社でWebプログラマ – Common LispとかReact.jsとか – それ以前は産業用機器のソフトや3D画像処理のチューニングの仕事 ● 趣味 : パンケーキ
  • 3. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  • 4. 今流行りのLisp方言 ● Clojure – JVMで動くヤツ ● Common Lisp – Lisp方言を寄せ集めたヤツ ● Scheme – 関数型のヤツ ● Emacs Lisp – Emacsで動くヤツ 今回はCommon Lispを扱う
  • 5. Common Lispとは ● 1980年代に数々のLispマシンやLisp方言が生まれた ● コミュニティ分裂の懸念を解消すべく、Common Lispとし て標準化を行う – 既存のLispから最良の機能を集結 – ANSIから1996年に標準規格リリース ● 制御構造、再帰関数呼び出し、ガベージコレクション、インク リメンタルコンパイル、オブジェクトシステム、コンディション システム等々を持つ 参考文献 : Peter, 実践 Common Lisp, 2008
  • 6. 関連用語 ● SBCL (Steel Bank Common Lisp) – Common Lispの処理系 – 色々あるけど非商用の処理系ならとりあえずコレ ● Quicklisp – Common Lispのパッケージ管理ツール – pipとかgemとかnpmとかの仲間? ● Roswell – 処理系管理ツール? – デフォルトでSBCLとQuicklispが入って、直ぐに使い始められる
  • 7. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  • 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. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  • 10. cl-oclapi ● 3bさんのOpenCL APIは動くけど – Quicklisp対応してない – 何年もメンテされてない? ● OpenCL 1.2 APIのラッパーをスクラッチから作った – 数年だれもやってなかったネタなのに、guichoさんと数週間差でネタか ぶり – しかし、その他色々なライブラリの都合により、cl-oclapiがQuicklispの GPGPU関連で一番最初に登録される
  • 11. oclcl ● cl-cudaからフォークして、カーネル部分取り出し – S式からCを生成 – マクロのサポート – シンボルマクロのサポート ● 変更点 – キーワードの置換や組込み関数の拡充 ● __global__を__kernelにしたり__synchronizeをbarrierにしたり – スカラ型ベクタ型のサポート拡大 – テストコードのOpenCL APIライブラリをeazy-openclとcl-oclapiに – Quicklisp登録済み
  • 12. 発表の流れ 1) Common Lispに関する簡単な説明 2) Common LispにおけるGPGPU関連の現状 3) Common LispでOpenCL 4) Common Lispでカーネルコードのマクロ展開
  • 13. Common Lispで? ● Cでカーネル書きたくない – 不便だから – カーネルの言語は規格上はCのみ – その他言語はAPI対応ばかりで、カーネルまで書けるのはあまりない ● 自分で作れるか – Common Lispなら既にcl-cudaがある ● これをベースにすればOpenCLも出来るのでは – マクロ使えばカーネル最適化に便利そう
  • 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. 例 : 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. 例 : 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. 例 : 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. 例 : 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. 例 : 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. 例 : 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;