C
概要 †
- GPGPUのプログラムの書き方
- 最適化されたGPUは、最適化されたCPUの2倍程度の早さ
- CUDAなら100倍!!とか言ってる人を見かけたら、「それCPUのほうも最適化したらどうなるんですか?」と聞いてあげるようにしましょう。
- 本気じゃないなら、「簡単に書けて早い」「コーディング時間少なく早い」という程度に思っているべき
- 組み込みGPGPU
参考 †
GPUの速度 †
- Core i7は100GFLops
- GeForce? 285は1000GFlops(この性能は1997年のスパコンレベル、なお2009年は131TFlops)
- 8コアCore i7(第四世代2013年6月)は単精768GFlops, GeForce? GTX Titan Z(2014年4月)は単精度8121GFlops
- 例えば粒子計算はいい加減実装でも1000倍早い。
- 1.2はfloatのみ、1.3(GT200以降)からはdoubleが扱える
- CPUとGPUは並列に処理可能(例外はcudaMemcpy)
- cudaMemcpy
- CPU->GPU, GPU->CPU, GPU->GPUのデータコピー
- cudaMemcpyAsync?:非同期転送は現状効率が悪く、デバイスドライバの改良が待たれる
- nvccはエミュレーション機能がある
- 数千スレッドを立ち上げるのでハングアップしたように感じる。速度は1/1000以下になる。低問題サイズで行うべき
- エミュレーションではprintfが使えるようになる。#ifdef __DEVICE_EMULATION__を活用
- メモリ関係のデバッグは不能
- カーネル関数のエラー検知はほぼ不可能
- CUDA APIはcudaError_tで検知し、cudaGetErrorString?で詳細。cudaGetLastError?で最終エラー検知
- GPUの特徴
- カーネル関数はSPMD、各SMの中の8個のSPはSIMD
- CPUにあってGPUに無いもの:Out-of-Order, 分岐予測, if文
- メモリの種類
- ローカル・グローバルメモリは100倍遅い(それでも159GB/s。CPUは36GB/s)
- レジスタ:変数の数によって増減、32が上限なので無駄な変数は削減せよ
- シェアードメモリ:高速
- 性能評価
- Occupacy 100%は良い事。
- Active Thread Blocks per Multiprocessorが重要
- SMあがり3ブロックがアクティブになると強い
名前 | 価格(円) | GFlops | GT 720 | 5500 | 306 | GT 730 | 6000 | 692.7 | GTX 780 | 64000 | 3976.7 | GTX 780 Ti | 90000 | 5045.7 | GTX TITAN Z | 400000 | 8121.6 | GTX TITAN Black | | 5120.6 | GTX TITAN | | 4499.7 |
名前 | 価格(円) | GFlops | GTX 980 Ti | 85000 | 5632 | GTX 980 | 70000 | 4612 | GTX 970 | 40000 | 3494 | GTX 960 | 24000 | 2308 | GTX 950 | 18500 | 1573 | GTX TITAN X | 130000 | |
環境構築 †
- NVIDIA GTX 960
- Compute CapabilityがTensor Flow for GPUに適合していたため
- Ubuntu 14.04.3
CUDA †
- CUDA 7.5
- CUDAインストールは,パソコンが起動しなくなるリスクがある.重要な情報は必ず退避せよ
- Ubuntuだと,Ubuntuの下に丸が5点ついた状態で止まる.何回かリセットしているとCUIで起動することもある.
- debパッケージで入れること&初心者は計算専用GPUを作りたいとか言っていないで,まずはGPGPUすることを目標とすること
- runファイルは何故か動かなかった.debで入れること!(ArrayFire?はdeb推奨)
- GPGPU+描画用を分けるにしても,NVIDIA+NVIDIAとメーカは揃えたほうがいい.
- 間違っても,作業中にsudo apt-get install nvidia-340-devなんて打たないこと.ドライババージョンが変わって,何も動かなくなる
- インストール手順(必ず公式ガイドを参照)
- 重要な事前知識
- NVIDIA Driverはデフォルトのnouveauと競合してカーネルパニックを起こして起動しなくなる→nouveauを切ってCUIモードで作業必須
- runではなくdebが推奨(ArrayFire?などもそう言ってる)
- 必要なデータ退避
- GPU刺す(外部電源あり.電源逆刺しに注意)
- 起動
- CUDA 7.5のdebをダウンロードし,~/に置く
- lspci | grep -i nvidia # GPU認識されていること確認
- /etc/modprobe.d/blacklist-nouveau.confを作成,以下を入れる.
blacklist nouveau
options nouveau modeset
- sudo update-initramfs -uで更新反映
- sudo vi /etc/default/grubのCMDLINEを以下に変更
GRUB_CMDLINE_LINUX_DEFAULT="text"
- 変更更新
update-grub
update-grub2
sudo init 6 # 再起動
- 起動したら以下打って確認
lsmod | grep nouveau #何も表示されないことを確認
- debのインストール
コマンドなんだっけ
- grubをGUIに戻す
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
- 変更更新して再起動
sudo update-initramfs -u
sudo init 6 # 再起動
- GUIモードになったら,サンプルチェック
- 煙のサンプルが動くことを確認.
- /usr/local/cuda-7.5/samples/0_Simple/template
- /usr/local/cuda-7.5/samples/5_Graphics/particle
Arrayfire †
- バイナリインストーラを使うこと
- gitは設定とコンパイルが面倒
- OpenCLは使わないことにした
sudo apt-get install libopenblas-dev
sudo apt-get install build-essential cmake cmake-curses-gui xorg-dev libglu1-mesa-dev
git clone https://github.com/arrayfire/arrayfire/wiki/GLFW-for-ArrayFire
wget https://github.com/glfw/glfw/archive/3.0.4.zip -O glfw-3.0.4.zip
unzip glfw-3.0.4.zip
cd glfw-3.0.4
mkdir build
cd build
cmake .. -DBUILD_SHARED_LIBS=ON
make -j8
sudo make install
http://www.arrayfire.com/docs/installing.htm#Ubuntu
sudo ./ArrayFire-v3.2.2_Linux_x86_64.sh --exclude-subdir --prefix=/usr/local
sudo apt-add-repository ppa:keithw/glfw3
sudo apt-get update
sudo apt-get install libglfw3-dev
cd ~
cp -r /usr/local/share/ArrayFire/examples .
cd examples
mkdir build
cd build
cmake ..
make
ArrayFire? †
- 素人が適当にCUDAで組むより早い!
- n * n行列(ランダムに初期化,密行列)演算.100x100行列の二乗からGPUのほうが早い!
ベンチマーク †
- GTX 960
1 * 1 time: 7.11001e-05, GFlops: 2.81294e-05
2 * 2 time: 0.000118369, GFlops: 0.00013517
4 * 4 time: 0.000118451, GFlops: 0.00108062
8 * 8 time: 0.000118374, GFlops: 0.00865055
16 * 16 time: 0.000118299, GFlops: 0.0692486
32 * 32 time: 0.000118254, GFlops: 0.554198
64 * 64 time: 0.000118398, GFlops: 4.42818
128 * 128 time: 0.00011918, GFlops: 35.1931
256 * 256 time: 0.000118702, GFlops: 282.678
512 * 512 time: 0.000530851, GFlops: 505.67
1024 * 1024 time: 0.003441, GFlops: 624.087
2048 * 2048 time: 0.025118, GFlops: 683.966
4096 * 4096 time: 0.207298, GFlops: 663.002
8192 * 8192 time: 1.64625, GFlops: 667.889
16384 * 16384 time: 13.2567, GFlops: 663.518
- AMD Phenom(tm) II X6 1100T Processor(並列化してる???TODO)
1 * 1 time: 3.87344e-07, GFlops: 0.00516337
2 * 2 time: 4.20973e-07, GFlops: 0.0380072
4 * 4 time: 4.42147e-07, GFlops: 0.289497
8 * 8 time: 6.19577e-07, GFlops: 1.65274
16 * 16 time: 1.31718e-06, GFlops: 6.21933
32 * 32 time: 5.1171e-06, GFlops: 12.8072
64 * 64 time: 3.1213e-05, GFlops: 16.7971
128 * 128 time: 0.000147203, GFlops: 28.4934
256 * 256 time: 0.000705, GFlops: 47.5949
512 * 512 time: 0.005114, GFlops: 52.4903
1024 * 1024 time: 0.030352, GFlops: 70.7526
2048 * 2048 time: 0.281418, GFlops: 61.0475
4096 * 4096 time: 2.49413, GFlops: 55.1049
8192 * 8192 time: 23.0691, GFlops: 47.6618
16384 * 16384 time: 185.721, GFlops: 47.3618
API †
- 基本
- 名前空間はaf
- Eigen::MatrixXf?に相当するのはarray
シンボル | 説明 | 備考 | randu(m, n) | 0-1に初期化されたm x n行列を作成 | | timeit(func) | void (*func)(void)の実行時間を返す | funcが早く終わる場合は1秒間何回も実行した平均 | timer::start() | timer t = timer::start(); proc(); double proc_time = timer::stop(t);で時間計測出来る | なぜかproc_time = 0だったことがある.怪しい. | *オペレータ | 要素積 | 行列積でないので注意!! | matmul(a, b) | 行列積 | |
cuライブラリ †
- cuSPARCEなど、いい感じのライブラリがそろっている
|