狠狠撸

狠狠撸Share a Scribd company logo
cl-cuda : a library to use NVIDIA CUDA in Common Lisp
2014.7.29 Masayuki Takagi
Lisp Meet Up presented by Shibuya.lisp #19
1.骋笔骋笔鲍
1.1.骋笔骋笔鲍(General Purpose GPU) とは?
1.2.GPU の歴史
1.3.スパコンへの浸透
3.cl-cuda ライブラリ
3.1.cl-cuda の特徴
3.2.使い方
3.3.内部設計
3.4.カーネル関数を起動するまでの流れ
3.5.デモ
3.6.パフォーマンス比較
3.7.レポジトリ
2.NVIDIA CUDA
2.1.CUDA とは?
2.2.プロセッサ?アーキテクチャ
2.3.メモリ?アーキテクチャ
2.4.プログラミング?モデル
目次:
1.骋笔骋笔鲍
? 2014 Masayuki Takagi-2-
1.1.骋笔骋笔鲍(General Purpose GPU) とは?
? GPU の計算資源を、画像処理以外の目的に応用する技術
? 2014 Masayuki Takagi-3-
1.2.GPUの歴史
3次元グラフィックスレンダリング
? 仮想空間に配置したモデルから、画面のピクセルの色をそれぞれ計算
? VGA(640x480)の場合、独立した30万ピクセルの色を、60Hz(10-20msec)で処理する必要
? グラフィックアクセラレータ(GPU)の登場
GPGPU に至るまでのGPUの歴史的背景を、簡単になぞります。
固定パイプライン - 1990's
? 物体表面での光や色の計算を、
ハードウェアで実装
? グローシェーディング、フォン
シェーディング
プログラマブル?シェーダ - 2000's
? 物体表面での光や色の計算を、
ソフトウェア的にプログラム可能に
? バーテックスシェーダ、フラグメン
トシェーダ
General Purpose GPU - 2010's
? 汎用的に使えるんじゃね??
? 2014 Masayuki Takagi-4-
1.3.スパコンへの浸透
GPGPU は、スパコン分野にも広く浸透しています。
TOP 500, June 2014, Poster
2.NVIDIA CUDA
? 2014 Masayuki Takagi-6-
2.1.CUDA とは?
? NVIDIA が提供する、並列計算アーキテクチャ。NVIDIA 製 GPU にて動作
? GPUを利用したコプロセッシングによって、データ並列の計算処理能力を大幅に向上
? C ベースの言語(CUDA C)、コンパイラ、デバッガ、プロファイラといった、ソフトウェア開
発環境も包括的に提供
Kepler GK110 のチップ写真
? 2014 Masayuki Takagi-7-
2.2.プロセッサ?アーキテクチャ
CUDAでは、大量のプロセッサ?コアを、以下のような階層構造をとることで管理しています。
? 1つの GPU チップは、複数のストリーミング?マルチプロセッサ(SMX)からなる
? 1つのストリーミング?マルチプロセッサは、192 個の CUDA コアと1組のフロー?コント
ローラ、 L1 キャッシュからなる
? 複数のスレッドをまとめたスレッドブロックごとに、ストリーミング?マルチプロセッサで処
理する
GTX 680 ブロック図(一部省略)
? 2014 Masayuki Takagi-8-
2.3.メモリ?アーキテクチャ
CUDAにおけるメモリは、プロセッサ?コアの階層構造に対応して、以下のような階層構造をとってい
ます。
? レジスタは、1つの CUDA コアからのみアクセス可能
? シェアードメモリおよび L1 キャッシュは、同一の SMX に属する CUDA コア間で共有
? L2 キャッシュは、SMX 間で共有される。小容量だが、オンチップにあり高速
? グローバルメモリは、SMX 間で共有される。大容量だが、オフチップにあり低速
グローバルメモリ
L2 キャッシュ
シェアードメモリ / L1 キャッシュ
レジスタ
CUDA コア
ストリーミング?マルチプロセッサ(SMX)
GPU チップ
? 2014 Masayuki Takagi-9-
2.4.プログラミング?モデル
CUDA のプログラミング?モデルは、ハードウェアのアーキテクチャに対応した階層構造となっていま
す。
? C を拡張した CUDA C によって、カーネル関数を定義。CUDA スレッドを構成し、1つ
のCUDA コアで実行される。
? スレッド数の指定とともに、カーネル関数を起動。スレッドブロックを構成し、1つのスト
リーミング?マルチプロセッサ(SMX)で実行される。
? 並列度が高く1つのスレッドブロックに収まらない場合、複数のスレッドブロックをまとめ
たグリッドを使い、複数の SMX で実行する。
3.cl-cuda ライブラリ
? 2014 Masayuki Takagi-11-
3.1.cl-cuda の特徴的な機能
cl-cuda は、Common Lisp から NVIDIA CUDA を使用するためのライブラリです。以下の機能を提
供します。
? カーネル関数の定義
? カーネル記述言語
? カーネルマクロの定義
? カーネルモジュールの遅延コンパイル及び遅延ロード
? CUDA コンテキストの管理
? ホストメモリ及びデバイスメモリの管理
? ホスト=デバイス間のメモリ転送
? OpenGL 相互運用
? 2014 Masayuki Takagi-12-
3.2.使い方(1)
ここでは、cl-cuda の使い方を簡単に示します。
? 配列加算(vectorAdd)サンプル
? 2つの配列の各要素を足し合わせ、3つ目の配列に格納
? 各 CUDA コアが、配列の各要素を担当し、並列に処理
配列A
配列B
配列C
1 2 3
3 2 1
4 4 4+
? 2014 Masayuki Takagi-13-
3.2.使い方(2)
以下のようなコードで、Common Lisp から CUDA を使用できます。
(defkernel	
 ?vec-?‐add-?‐kernel	
 ?(void	
 ?((a	
 ?float*)	
 ?(b	
 ?float*)	
 ?(c	
 ?float*)	
 ?(n	
 ?int)))
	
 ?	
 ?(let	
 ?((i	
 ?(+	
 ?(*	
 ?block-?‐dim-?‐x	
 ?block-?‐idx-?‐x)	
 ?thread-?‐idx-?‐x)))
	
 ?	
 ?	
 ?	
 ?(if	
 ?(<	
 ?i	
 ?n)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(set	
 ?(aref	
 ?c	
 ?i)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(+	
 ?(aref	
 ?a	
 ?i)	
 ?(aref	
 ?b	
 ?i))))))
(defun	
 ?main	
 ?()
	
 ?	
 ?(let*	
 ?((dev-?‐id	
 ?0)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(n	
 ?1024)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(threads-?‐per-?‐block	
 ?256)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(blocks-?‐per-?‐grid	
 ?(/	
 ?n	
 ?threads-?‐per-?‐block)))
	
 ?	
 ?	
 ?	
 ?(with-?‐cuda	
 ?(dev-?‐id)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(with-?‐memory-?‐blocks	
 ?((a	
 ?'float	
 ?n)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(b	
 ?'float	
 ?n)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(c	
 ?'float	
 ?n))
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(random-?‐init	
 ?a	
 ?n)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(random-?‐init	
 ?b	
 ?n)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(sync-?‐memory-?‐block	
 ?a	
 ?:host-?‐to-?‐device)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(sync-?‐memory-?‐block	
 ?b	
 ?:host-?‐to-?‐device)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(vec-?‐add-?‐kernel	
 ?a	
 ?b	
 ?c	
 ?n
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?:grid-?‐dim	
 ?	
 ?(list	
 ?blocks-?‐per-?‐grid	
 ?1	
 ?1)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?:block-?‐dim	
 ?(list	
 ?threads-?‐per-?‐block	
 ?1	
 ?1))
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(sync-?‐memory-?‐block	
 ?c	
 ?:device-?‐to-?‐host)
	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?	
 ?(verify-?‐result	
 ?a	
 ?b	
 ?c	
 ?n)))))
カーネル関数を定義
CUDA コンテキストを生成
ホストとデバイスに、メモリ領域を確保
ホストメモリからデバイスメモリへデータ
を転送
定義したカーネル関数を起動
デバイスメモリからホストメモリへデータ
を転送
? 2014 Masayuki Takagi-14-
3.3.内部設計
cl-cuda は、以下の3つのコンポーネントから構成されます。
cl-cuda.api
実際にユーザが利用するインターフェ
イスを提供。defkernel マクロ、カーネ
ルマネージャ、CUDA コンテキスト、メ
モリブロック、タイマ。
cl-cuda.lang
カーネル記述言語と、そのコンパイラ
を提供。コンパイラは、カーネル記述
言語を CUDA C へ変換する。CUDA
C から PTX ファイルへの変換は、cl-
cuda.api のカーネルマネージャが管
理する。
cl-cuda.driver-api
CUDA ドライバ API への FFI(Foreign
Function Interface)を提供。
? 2014 Masayuki Takagi-15-
3.4.カーネル関数を起動するまでの流れ
定義したカーネル関数を起動するまでの処理の流れは、以下のようになります。これらの処理は、
カーネルマネージャによって管理され、コンパイルやロードは、必要なタイミングまで遅延して実行さ
れます。
1. カーネル関数を定義
defkenrel マクロを使用して、カーネル関数を定義しま
す。
2. カーネル記述言語をコンパイル
cl-cuda.lang のコンパイラを用いて、カーネル記述言語
を CUDA C へコンパイルします。
3. CUDA C をコンパイル
NVIDIA の提供する NVCC (NVIDIA CUDA Compiler)
を呼び出し、CUDA C のコードをカーネルモジュール
(PTX ファイル)へコンパイルします。
4. カーネルモジュールをロード
CUDA ドライバ API を使用して、カーネルモジュールを
ロードします。
5. カーネル関数をロード
CUDA ドライバ API を使用して、起動したいカーネル
関数をロードします。
6. 引数として渡す値を配列に格納
引数として GPU に渡す値を格納した配列を用意しま
す。
7. カーネル関数を起動
CUDA ドライバ API を使用して、カーネル関数を起動
します。
? 2014 Masayuki Takagi-16-
3.5.デモ
Nbody シミュレーション
(:ql	
 ?:cl-?‐cuda-?‐interop-?‐examples)
(cl-?‐cuda-?‐interop-?‐examples.nbody:main	
 ?:gpu	
 ?t	
 ?:interop	
 ?t)
? 2014 Masayuki Takagi-17-
3.6.パフォーマンス比較
GPU を利用して並列計算することで、CPU での逐次処理に対し、40倍近い性能向上が得られまし
た。
x37.5
Amazon EC2 インスタンス
プロセッサ
コア数
g2.2xlarge g2.2xlarge
Xeon E5-2670 2.6GHz NVIDIA GRID K520
1 コア
(シングルスレッド、SIMD命令使用せず、gcc -O3相当)
1,536 コア
4.86[sec]
182.2[sec]
SPH(Smoothed Particle Hydrodynamics) による流体シミュレーション 11,774粒子
? 2014 Masayuki Takagi-18-
3.7.レポジトリ
cl-cuda は、GitHub から入手できます。Quicklispは、そのテストポリシーの都合上、登録不可でした。
https://github.com/takagi/cl-cuda/

More Related Content

Lisp Meet Up #19, cl-cuda: a library to use NVIDIA CUDA in Common Lisp

  • 1. cl-cuda : a library to use NVIDIA CUDA in Common Lisp 2014.7.29 Masayuki Takagi Lisp Meet Up presented by Shibuya.lisp #19 1.骋笔骋笔鲍 1.1.骋笔骋笔鲍(General Purpose GPU) とは? 1.2.GPU の歴史 1.3.スパコンへの浸透 3.cl-cuda ライブラリ 3.1.cl-cuda の特徴 3.2.使い方 3.3.内部設計 3.4.カーネル関数を起動するまでの流れ 3.5.デモ 3.6.パフォーマンス比較 3.7.レポジトリ 2.NVIDIA CUDA 2.1.CUDA とは? 2.2.プロセッサ?アーキテクチャ 2.3.メモリ?アーキテクチャ 2.4.プログラミング?モデル 目次:
  • 3. ? 2014 Masayuki Takagi-2- 1.1.骋笔骋笔鲍(General Purpose GPU) とは? ? GPU の計算資源を、画像処理以外の目的に応用する技術
  • 4. ? 2014 Masayuki Takagi-3- 1.2.GPUの歴史 3次元グラフィックスレンダリング ? 仮想空間に配置したモデルから、画面のピクセルの色をそれぞれ計算 ? VGA(640x480)の場合、独立した30万ピクセルの色を、60Hz(10-20msec)で処理する必要 ? グラフィックアクセラレータ(GPU)の登場 GPGPU に至るまでのGPUの歴史的背景を、簡単になぞります。 固定パイプライン - 1990's ? 物体表面での光や色の計算を、 ハードウェアで実装 ? グローシェーディング、フォン シェーディング プログラマブル?シェーダ - 2000's ? 物体表面での光や色の計算を、 ソフトウェア的にプログラム可能に ? バーテックスシェーダ、フラグメン トシェーダ General Purpose GPU - 2010's ? 汎用的に使えるんじゃね??
  • 5. ? 2014 Masayuki Takagi-4- 1.3.スパコンへの浸透 GPGPU は、スパコン分野にも広く浸透しています。 TOP 500, June 2014, Poster
  • 7. ? 2014 Masayuki Takagi-6- 2.1.CUDA とは? ? NVIDIA が提供する、並列計算アーキテクチャ。NVIDIA 製 GPU にて動作 ? GPUを利用したコプロセッシングによって、データ並列の計算処理能力を大幅に向上 ? C ベースの言語(CUDA C)、コンパイラ、デバッガ、プロファイラといった、ソフトウェア開 発環境も包括的に提供 Kepler GK110 のチップ写真
  • 8. ? 2014 Masayuki Takagi-7- 2.2.プロセッサ?アーキテクチャ CUDAでは、大量のプロセッサ?コアを、以下のような階層構造をとることで管理しています。 ? 1つの GPU チップは、複数のストリーミング?マルチプロセッサ(SMX)からなる ? 1つのストリーミング?マルチプロセッサは、192 個の CUDA コアと1組のフロー?コント ローラ、 L1 キャッシュからなる ? 複数のスレッドをまとめたスレッドブロックごとに、ストリーミング?マルチプロセッサで処 理する GTX 680 ブロック図(一部省略)
  • 9. ? 2014 Masayuki Takagi-8- 2.3.メモリ?アーキテクチャ CUDAにおけるメモリは、プロセッサ?コアの階層構造に対応して、以下のような階層構造をとってい ます。 ? レジスタは、1つの CUDA コアからのみアクセス可能 ? シェアードメモリおよび L1 キャッシュは、同一の SMX に属する CUDA コア間で共有 ? L2 キャッシュは、SMX 間で共有される。小容量だが、オンチップにあり高速 ? グローバルメモリは、SMX 間で共有される。大容量だが、オフチップにあり低速 グローバルメモリ L2 キャッシュ シェアードメモリ / L1 キャッシュ レジスタ CUDA コア ストリーミング?マルチプロセッサ(SMX) GPU チップ
  • 10. ? 2014 Masayuki Takagi-9- 2.4.プログラミング?モデル CUDA のプログラミング?モデルは、ハードウェアのアーキテクチャに対応した階層構造となっていま す。 ? C を拡張した CUDA C によって、カーネル関数を定義。CUDA スレッドを構成し、1つ のCUDA コアで実行される。 ? スレッド数の指定とともに、カーネル関数を起動。スレッドブロックを構成し、1つのスト リーミング?マルチプロセッサ(SMX)で実行される。 ? 並列度が高く1つのスレッドブロックに収まらない場合、複数のスレッドブロックをまとめ たグリッドを使い、複数の SMX で実行する。
  • 12. ? 2014 Masayuki Takagi-11- 3.1.cl-cuda の特徴的な機能 cl-cuda は、Common Lisp から NVIDIA CUDA を使用するためのライブラリです。以下の機能を提 供します。 ? カーネル関数の定義 ? カーネル記述言語 ? カーネルマクロの定義 ? カーネルモジュールの遅延コンパイル及び遅延ロード ? CUDA コンテキストの管理 ? ホストメモリ及びデバイスメモリの管理 ? ホスト=デバイス間のメモリ転送 ? OpenGL 相互運用
  • 13. ? 2014 Masayuki Takagi-12- 3.2.使い方(1) ここでは、cl-cuda の使い方を簡単に示します。 ? 配列加算(vectorAdd)サンプル ? 2つの配列の各要素を足し合わせ、3つ目の配列に格納 ? 各 CUDA コアが、配列の各要素を担当し、並列に処理 配列A 配列B 配列C 1 2 3 3 2 1 4 4 4+
  • 14. ? 2014 Masayuki Takagi-13- 3.2.使い方(2) 以下のようなコードで、Common Lisp から CUDA を使用できます。 (defkernel ?vec-?‐add-?‐kernel ?(void ?((a ?float*) ?(b ?float*) ?(c ?float*) ?(n ?int))) ? ?(let ?((i ?(+ ?(* ?block-?‐dim-?‐x ?block-?‐idx-?‐x) ?thread-?‐idx-?‐x))) ? ? ? ?(if ?(< ?i ?n) ? ? ? ? ? ? ? ?(set ?(aref ?c ?i) ? ? ? ? ? ? ? ? ? ? ? ? ?(+ ?(aref ?a ?i) ?(aref ?b ?i)))))) (defun ?main ?() ? ?(let* ?((dev-?‐id ?0) ? ? ? ? ? ? ? ? ?(n ?1024) ? ? ? ? ? ? ? ? ?(threads-?‐per-?‐block ?256) ? ? ? ? ? ? ? ? ?(blocks-?‐per-?‐grid ?(/ ?n ?threads-?‐per-?‐block))) ? ? ? ?(with-?‐cuda ?(dev-?‐id) ? ? ? ? ? ?(with-?‐memory-?‐blocks ?((a ?'float ?n) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(b ?'float ?n) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(c ?'float ?n)) ? ? ? ? ? ? ? ?(random-?‐init ?a ?n) ? ? ? ? ? ? ? ?(random-?‐init ?b ?n) ? ? ? ? ? ? ? ?(sync-?‐memory-?‐block ?a ?:host-?‐to-?‐device) ? ? ? ? ? ? ? ?(sync-?‐memory-?‐block ?b ?:host-?‐to-?‐device) ? ? ? ? ? ? ? ?(vec-?‐add-?‐kernel ?a ?b ?c ?n ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?:grid-?‐dim ? ?(list ?blocks-?‐per-?‐grid ?1 ?1) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?:block-?‐dim ?(list ?threads-?‐per-?‐block ?1 ?1)) ? ? ? ? ? ? ? ?(sync-?‐memory-?‐block ?c ?:device-?‐to-?‐host) ? ? ? ? ? ? ? ?(verify-?‐result ?a ?b ?c ?n))))) カーネル関数を定義 CUDA コンテキストを生成 ホストとデバイスに、メモリ領域を確保 ホストメモリからデバイスメモリへデータ を転送 定義したカーネル関数を起動 デバイスメモリからホストメモリへデータ を転送
  • 15. ? 2014 Masayuki Takagi-14- 3.3.内部設計 cl-cuda は、以下の3つのコンポーネントから構成されます。 cl-cuda.api 実際にユーザが利用するインターフェ イスを提供。defkernel マクロ、カーネ ルマネージャ、CUDA コンテキスト、メ モリブロック、タイマ。 cl-cuda.lang カーネル記述言語と、そのコンパイラ を提供。コンパイラは、カーネル記述 言語を CUDA C へ変換する。CUDA C から PTX ファイルへの変換は、cl- cuda.api のカーネルマネージャが管 理する。 cl-cuda.driver-api CUDA ドライバ API への FFI(Foreign Function Interface)を提供。
  • 16. ? 2014 Masayuki Takagi-15- 3.4.カーネル関数を起動するまでの流れ 定義したカーネル関数を起動するまでの処理の流れは、以下のようになります。これらの処理は、 カーネルマネージャによって管理され、コンパイルやロードは、必要なタイミングまで遅延して実行さ れます。 1. カーネル関数を定義 defkenrel マクロを使用して、カーネル関数を定義しま す。 2. カーネル記述言語をコンパイル cl-cuda.lang のコンパイラを用いて、カーネル記述言語 を CUDA C へコンパイルします。 3. CUDA C をコンパイル NVIDIA の提供する NVCC (NVIDIA CUDA Compiler) を呼び出し、CUDA C のコードをカーネルモジュール (PTX ファイル)へコンパイルします。 4. カーネルモジュールをロード CUDA ドライバ API を使用して、カーネルモジュールを ロードします。 5. カーネル関数をロード CUDA ドライバ API を使用して、起動したいカーネル 関数をロードします。 6. 引数として渡す値を配列に格納 引数として GPU に渡す値を格納した配列を用意しま す。 7. カーネル関数を起動 CUDA ドライバ API を使用して、カーネル関数を起動 します。
  • 17. ? 2014 Masayuki Takagi-16- 3.5.デモ Nbody シミュレーション (:ql ?:cl-?‐cuda-?‐interop-?‐examples) (cl-?‐cuda-?‐interop-?‐examples.nbody:main ?:gpu ?t ?:interop ?t)
  • 18. ? 2014 Masayuki Takagi-17- 3.6.パフォーマンス比較 GPU を利用して並列計算することで、CPU での逐次処理に対し、40倍近い性能向上が得られまし た。 x37.5 Amazon EC2 インスタンス プロセッサ コア数 g2.2xlarge g2.2xlarge Xeon E5-2670 2.6GHz NVIDIA GRID K520 1 コア (シングルスレッド、SIMD命令使用せず、gcc -O3相当) 1,536 コア 4.86[sec] 182.2[sec] SPH(Smoothed Particle Hydrodynamics) による流体シミュレーション 11,774粒子
  • 19. ? 2014 Masayuki Takagi-18- 3.7.レポジトリ cl-cuda は、GitHub から入手できます。Quicklispは、そのテストポリシーの都合上、登録不可でした。 https://github.com/takagi/cl-cuda/