超音波流体屋のプログラム備忘録

CULA (R14, CUDA 4.4)

最終更新:

usapfrog

- view
管理者のみ編集可
CUDA 4.1, CULA Dense R14 版の(古い)情報です。
CULA Dense (R17, CUDA 5.5)
CULA Sparse (S5, CUDA 5.5)

CULA free editionならfloat, float complex限定、連立方程式・最小二乗法・LU分解あたりが使える。
ダウンロードは以下からID登録してから。
http://www.culatools.com/downloads/dense/
linuxは落としてきた.runを管理者権限でbashで実行。
今回はCULA Dense R14 free editoinを使用。
要CUDA 4.1だったので、CUDAも4.1にバージョンアップ。

ソース

CULA使い方の一例として、連立方程式 Ax = bを解く話。
んで今回はMatlab記法で A=ones(10 000, 10 000)-eye(10 000); b=ones(10 000, 1);
対角成分だけ0、後は1の行列。解は確か全部 1/9999。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. //cuda, cula関係のヘッダ
  5. #include <cutil.h>
  6. #include <cula.h>
  7. #include <cula_lapack.h>
  8. #include <cula_lapack_device.h>
  9.  
  10. int main(int argc, char** argv){
  11.  
  12. CUT_DEVICE_INIT(argc, argv);
  13. culaStatus s; //失敗するとculaNoError以外が入るらしい
  14. s = culaInitialize();
  15.  
  16. //ホスト領域の確保・値の代入
  17. float *a, *b;
  18. int n=10000;
  19. int m=10000;
  20. a = (float *)calloc(sizeof(float), m*n);
  21. b = (float *)calloc(sizeof(float), m);
  22. //やってみたらいわゆるColumn-major, CLapackと同じらしい
  23. int i, j;
  24. for(i=0; i<n; i++){
  25. for(j=0; j<m; j++){
  26. a[i+j*n]= (float) (i != j);
  27. }
  28. b[i] = 1;
  29. }
  30. //その他、行数・列数情報。CLapackと同じ。
  31. int ipiv[n];
  32. int nrhs = 1;
  33. int lda = n;
  34. int ldb = n;
  35.  
  36. //時間計測用タイマー
  37. unsigned int timer = 0;
  38. CUT_SAFE_CALL( cutCreateTimer( &timer));
  39. CUT_SAFE_CALL( cutStartTimer( timer) );
  40.  
  41. //連立方程式を解く。これ1行。
  42. s = culaSgesv(n, nrhs, a, lda, ipiv, b, ldb);
  43.  
  44. //タイマーストップ
  45. CUT_SAFE_CALL( cutStopTimer( timer));
  46. printf("Elapsed time : %f (ms)\n", cutGetTimerValue(timer));
  47.  
  48. //エラー処理等したければ。 正常終了なら0が返る。
  49. printf("culastate %d noerr:%d \n", s, culaNoError);
  50.  
  51. //結果表示
  52. for(j=0; j<m; j++) printf("%f ", b[j]);
  53.  
  54. //終了処理
  55. free(a);
  56. free(b);
  57. culaShutdown();
  58. CUT_SAFE_CALL( cutDeleteTimer( timer));
  59. CUT_EXIT(argc, argv);
  60. return 0;
  61. }
  62.  

コンパイル

Makefileはこんな感じ。環境変数を工夫すればもっと短くてすむはず。
  1. CC=nvcc
  2. LIB=-lcutil_x86_64 -lcula_core -lcula_lapack
  3. SRC=sample.cu
  4. OUT=sample.out
  5. LIB1=-L~/NVIDIA_GPU_Computing_SDK/C/lib
  6. LIB2=-L/usr/local/cula/lib64
  7. INC1=-I~/NVIDIA_GPU_Computing_SDK/CUDALibraries/common/inc
  8. INC2=-I/usr/local/cula/include/
  9. all:
  10. ${CC} ${SRC} -o ${OUT} ${LIB} ${LIB1} ${LIB2} ${INC1} ${INC2}
  11.  

計算時間

NVS 4200M のthinkpad T420sで13.4 sec。
CPU: Core i7-2640M 2.8GHz (smpとか無しで)
octaveで 109sec, clapackのdgesv_で496sec。
だいたい8倍くらいは速いかも。

あらかじめGPUに格納しときたいときは

culaDeviceSgesvほかdevice系の関数を使う。
行列Aとベクトルbに対応する領域、加えて関数に必要な配列ipivなども忘れずにデバイス上に確保してから、
同様の関数を採用すればよい。上記42行付近は以下の通りに書き換える。
  1. {
  2. double *da, *db;
  3. int *dipiv;
  4. CUDA_SAFE_CALL(cudaMalloc((void**) &da, sizeof(double)*n*n));
  5. CUDA_SAFE_CALL(cudaMalloc((void**) &db, sizeof(double)*n));
  6. CUDA_SAFE_CALL(cudaMalloc((void**) &dipiv, sizeof(int)*n))
  7.  
  8. CUDA_SAFE_CALL(cudaMemcpy(da, a, sizeof(double)*n*n, cudaMemcpyHostToDevice));
  9. CUDA_SAFE_CALL(cudaMemcpy(db, b, sizeof(double)*n, cudaMemcpyHostToDevice));
  10.  
  11. s = culaDeviceSgesv(n, nrhs, da, lda, dipiv, db, ldb);
  12. }
  13.  


精度

単精度のせいか、大行列になると荒れる。
上記の例ですでにばらつきが大きい。
n=5000ぐらいが限界だろうか。
それ以上は倍精度対応版を買うしかないと思われる。

まあDense/Sparseともアカデミックなら$95、商用でも$395/年。
(買って落とした分はずっと使っていいけど、期限後のバージョンアップには更新がいるみたい)
年数十〜数百万ふんだくるどこぞの解析ソフトよかはお得じゃないかしら。




目安箱バナー