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.GPGPU
1.1.GPGPU(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.GPGPU
© 2014 Masayuki Takagi-2-
1.1.GPGPU(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/

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

  • 1.
    cl-cuda : alibrary to use NVIDIA CUDA in Common Lisp 2014.7.29 Masayuki Takagi Lisp Meet Up presented by Shibuya.lisp #19 1.GPGPU 1.1.GPGPU(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.プログラミング・モデル 目次:
  • 2.
  • 3.
    © 2014 MasayukiTakagi-2- 1.1.GPGPU(General Purpose GPU) とは?  GPU の計算資源を、画像処理以外の目的に応用する技術
  • 4.
    © 2014 MasayukiTakagi-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 MasayukiTakagi-4- 1.3.スパコンへの浸透 GPGPU は、スパコン分野にも広く浸透しています。 TOP 500, June 2014, Poster
  • 6.
  • 7.
    © 2014 MasayukiTakagi-6- 2.1.CUDA とは?  NVIDIA が提供する、並列計算アーキテクチャ。NVIDIA 製 GPU にて動作  GPUを利用したコプロセッシングによって、データ並列の計算処理能力を大幅に向上  C ベースの言語(CUDA C)、コンパイラ、デバッガ、プロファイラといった、ソフトウェア開 発環境も包括的に提供 Kepler GK110 のチップ写真
  • 8.
    © 2014 MasayukiTakagi-7- 2.2.プロセッサ・アーキテクチャ CUDAでは、大量のプロセッサ・コアを、以下のような階層構造をとることで管理しています。  1つの GPU チップは、複数のストリーミング・マルチプロセッサ(SMX)からなる  1つのストリーミング・マルチプロセッサは、192 個の CUDA コアと1組のフロー・コント ローラ、 L1 キャッシュからなる  複数のスレッドをまとめたスレッドブロックごとに、ストリーミング・マルチプロセッサで処 理する GTX 680 ブロック図(一部省略)
  • 9.
    © 2014 MasayukiTakagi-8- 2.3.メモリ・アーキテクチャ CUDAにおけるメモリは、プロセッサ・コアの階層構造に対応して、以下のような階層構造をとってい ます。  レジスタは、1つの CUDA コアからのみアクセス可能  シェアードメモリおよび L1 キャッシュは、同一の SMX に属する CUDA コア間で共有  L2 キャッシュは、SMX 間で共有される。小容量だが、オンチップにあり高速  グローバルメモリは、SMX 間で共有される。大容量だが、オフチップにあり低速 グローバルメモリ L2 キャッシュ シェアードメモリ / L1 キャッシュ レジスタ CUDA コア ストリーミング・マルチプロセッサ(SMX) GPU チップ
  • 10.
    © 2014 MasayukiTakagi-9- 2.4.プログラミング・モデル CUDA のプログラミング・モデルは、ハードウェアのアーキテクチャに対応した階層構造となっていま す。  C を拡張した CUDA C によって、カーネル関数を定義。CUDA スレッドを構成し、1つ のCUDA コアで実行される。  スレッド数の指定とともに、カーネル関数を起動。スレッドブロックを構成し、1つのスト リーミング・マルチプロセッサ(SMX)で実行される。  並列度が高く1つのスレッドブロックに収まらない場合、複数のスレッドブロックをまとめ たグリッドを使い、複数の SMX で実行する。
  • 11.
  • 12.
    © 2014 MasayukiTakagi-11- 3.1.cl-cuda の特徴的な機能 cl-cuda は、Common Lisp から NVIDIA CUDA を使用するためのライブラリです。以下の機能を提 供します。  カーネル関数の定義  カーネル記述言語  カーネルマクロの定義  カーネルモジュールの遅延コンパイル及び遅延ロード  CUDA コンテキストの管理  ホストメモリ及びデバイスメモリの管理  ホスト=デバイス間のメモリ転送  OpenGL 相互運用
  • 13.
    © 2014 MasayukiTakagi-12- 3.2.使い方(1) ここでは、cl-cuda の使い方を簡単に示します。  配列加算(vectorAdd)サンプル  2つの配列の各要素を足し合わせ、3つ目の配列に格納  各 CUDA コアが、配列の各要素を担当し、並列に処理 配列A 配列B 配列C 1 2 3 3 2 1 4 4 4+
  • 14.
    © 2014 MasayukiTakagi-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 MasayukiTakagi-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 MasayukiTakagi-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 MasayukiTakagi-16- 3.5.デモ Nbody シミュレーション (:ql  :cl-­‐cuda-­‐interop-­‐examples) (cl-­‐cuda-­‐interop-­‐examples.nbody:main  :gpu  t  :interop  t)
  • 18.
    © 2014 MasayukiTakagi-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 MasayukiTakagi-18- 3.7.レポジトリ cl-cuda は、GitHub から入手できます。Quicklispは、そのテストポリシーの都合上、登録不可でした。 https://github.com/takagi/cl-cuda/