Advertisement
Guest User

cudaAddKernel

a guest
Jan 27th, 2014
228
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.62 KB | None | 0 0
  1.  
  2. /* double型の配列A・B・Cに対して「C=A+B」を実行している(ベクタ演算) */
  3. /*
  4. Debug(Win32)で
  5. CPU計算時間:4.35151e-005[s] -> 376.513[MFLOPS]
  6. GPU計算時間:4e-005[s] -> 409.6[MFLOPS]
  7. 最大絶対誤差:0.0000000000000000
  8. Release(x64)で
  9. CPU計算時間:1.51892e-005[s] -> 1078.66[MFLOPS]
  10. GPU計算時間:3.7824e-005[s] -> 433.164[MFLOPS]
  11. 最大絶対誤差:0.0000000000000000
  12. */
  13.  
  14. /*
  15. XXX: GT610M の性能の推測
  16.  
  17. GT610M : CC=2.1, 48コア, 900MHz, 14.4Gbyte/s
  18. GT430  : CC=2.1, 96コア, 1400MHz, 28.8Gbyte/s (手持ち:現在はスロットが足りないので使ってない)
  19. CUDA-Z 0.7.181 では
  20.   int32 = 89.4 Giop/s
  21.   float = 178.3 Gflop/s
  22.   double = 22.3 Gflop/s
  23.  
  24. GT610M では、22.3 * 48/96 * 900/1400 = 7.16 Gflop/s
  25.  
  26. さらにaddKernelはメモリ律速だし(メモリ読み出し2回、double加算1回、メモリ書き出し1回)。
  27. 手元のGTS450をNsightで実行したら、
  28. memory load 31.76 GB/s
  29. memory store 15.88 GB/s
  30. Achived FLOPS 2.13 Gflop/s
  31. GT610Mではloadのバンド幅がこれより少ないので、確実にメモリ律速。
  32.  
  33. */
  34.  
  35. /* プリプロセッサ(CUDA実行用) */
  36. #include "cuda_runtime.h"
  37. #include "device_launch_parameters.h"
  38.  
  39. /* プリプロセッサ(その他) */
  40. #include <math.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <time.h>
  45. #include <windows.h>
  46.  
  47. /* 実行用関数。返り値はGPU演算の実行可否(cudaSuccessと等しければOK) */
  48. cudaError_t addWithCuda(double *c, double *a, double *b, unsigned int size);
  49.  
  50. /* カーネル関数(ポインタ相手に演算。ゆえに返り値なし) */
  51. __global__ void addKernel(double *c, double *a, double *b, int size_x)
  52. {
  53.     //blockDim.xはブロックサイズ、blockIdx.xはブロック番号、threadIdx.xはスレッドID
  54.     int x = blockDim.x * blockIdx.x + threadIdx.x;
  55.     int y = blockDim.y * blockIdx.y + threadIdx.y;
  56.     int i = y * size_x + x;
  57.    
  58.     //加算(注:Cにおいては配列≒ポインタ)
  59.     c[i] = a[i] + b[i];
  60. }
  61.  
  62. int main(void){
  63.     /* 問題サイズ。冷静に考えるとC文法で#defineしないのは変だが、
  64.        CUDAでは許されている模様 */
  65.     const int arraySize = 16 * 1024 * 1024;
  66.  
  67.     /* 各配列を定義 */
  68.     double *a = NULL, *b = NULL, *c = NULL, *c_ = NULL;
  69.     /* 時間計測用 */
  70.     LARGE_INTEGER Frequency, time_s, time_g;
  71.     double elapsedTime;
  72.     /* その他変数 */
  73.     int i;
  74.     cudaError_t cudaStatus;
  75.  
  76.     /* XXX: スタックは小さい(せいぜい2MB)だから、ヒープから確保する */
  77.     a = (double*) malloc(sizeof(double) * arraySize);
  78.     b = (double*) malloc(sizeof(double) * arraySize);
  79.     c = (double*) calloc(arraySize, sizeof(double));
  80.     c_ = (double*) calloc(arraySize, sizeof(double));
  81.  
  82.     /* 配列初期化。とりあえず[0,1)とした */
  83.     srand((unsigned) time(NULL));
  84.     for(i = 0; i < arraySize; i++){
  85.         a[i] = (double)(rand()) / RAND_MAX;
  86.         b[i] = (double)(rand()) / RAND_MAX;
  87.     }
  88.  
  89.     /* CPUによる演算 */
  90.     memset(&Frequency, 0x00, sizeof Frequency);
  91.     memset(&time_s,    0x00, sizeof time_s);
  92.     memset(&time_g,    0x00, sizeof time_g);
  93.     QueryPerformanceFrequency(&Frequency);
  94.     QueryPerformanceCounter(&time_s);
  95.     for(i = 0; i < arraySize; i++){
  96.         c[i] = a[i] + b[i];
  97.     }
  98.     QueryPerformanceCounter(&time_g);
  99.     elapsedTime = (double)(time_g.QuadPart - time_s.QuadPart) / Frequency.QuadPart;
  100.     printf("CPU計算時間:%3.9lf[s] -> %g[MFLOPS]\n", elapsedTime, 1.0 * arraySize / elapsedTime / 1000.0 / 1000.0);
  101.  
  102.     /* GPUを利用して並列演算 */
  103.     cudaStatus = addWithCuda(c_, a, b, arraySize);
  104.     if (cudaStatus != cudaSuccess) {    //失敗時の動作
  105.         fprintf(stderr, "addWithCuda failed!");
  106.         return 1;
  107.     }
  108.  
  109.     /* 誤差計算(デバッグ用) */
  110.     double max_diff = 0.0;
  111.     for(i = 0; i < arraySize; i++){
  112.         if(max_diff < fabs(c[i] - c_[i]))
  113.             max_diff = fabs(c[i] - c_[i]);
  114.     }
  115.  
  116.     /* 結果表示 */
  117.     /*for(i = 0; i < arraySize; i++){
  118.         printf("%d %f\t%f\t%f\t%f\n", i, a[i], b[i], c[i], c_[i]);
  119.     }*/
  120.     printf("最大絶対誤差:%1.16lf\n", max_diff);
  121.  
  122.     /* 終了用関数呼び出し */
  123.     cudaStatus = cudaDeviceReset();
  124.     if (cudaStatus != cudaSuccess) {
  125.         fprintf(stderr, "cudaDeviceReset failed!");
  126.         return 1;
  127.     }
  128.  
  129.     if (a) free(a);
  130.     if (b) free(b);
  131.     if (c) free(c);
  132.     if (c_) free(c_);
  133.  
  134.     return 0;
  135. }
  136.  
  137. /* 実行用関数。カーネル関数をここから呼び出す */
  138. cudaError_t addWithCuda(double *c, double *a, double *b, unsigned int size)
  139. {
  140.     //カーネル関数に値を渡すためのポインタ
  141.     double *dev_a = 0;
  142.     double *dev_b = 0;
  143.     double *dev_c = 0;
  144.     //ステータス用変数
  145.     cudaError_t cudaStatus;
  146.     //時間計測用
  147.     cudaEvent_t start, stop;
  148.     float elapsedTime;          //経過時間[ms]
  149.  
  150.     /* 1次元配列を2次元(size_x * size_y)とみなして、それをさらにCUDA blockに分割: CC=2.1の制限: gridsize>=65536を超えるため */
  151.     const dim3 blockSize(256, 1);
  152.     const int size_x = blockSize.x * 1024;  // 1ブロックは最大1024スレッド
  153.     const int size_y = (size + size_x - 1) / size_x;
  154.     const dim3 gridSize((size_x + blockSize.x - 1)/ blockSize.x, (size_y + blockSize.y - 1)/ blockSize.y);
  155.  
  156.     printf("size: %d\n", size);
  157.     printf("size_x,y: %d,%d\n", size_x, size_y);
  158.     printf("blockSize: %d,%d\n", blockSize.x, blockSize.y);
  159.     printf("gridSize: %d,%d\n", gridSize.x, gridSize.y);
  160.  
  161.  
  162.     /* どのCUDAデバイスを利用するかを選択(今回は番号0のもの)
  163.        ・cudaGetDeviceCount(int *count)で総数を取得できる
  164.        ・cudaGetDevice(int *current_device)で現在の番号を取得
  165.        ・cudaGetDeviceProperties(int *device, cdaDeiceProp*prop)で情報取得 */
  166.     cudaStatus = cudaSetDevice(1);
  167.     if (cudaStatus != cudaSuccess) {
  168.         fprintf(stderr, "cudaSetDevice failed!  Do you have a CUDA-capable GPU installed?");
  169.         goto Error;
  170.     }
  171.  
  172.     /* カーネル関数に渡せるようにメモリを確保 */
  173.     cudaStatus = cudaMalloc((void**)&dev_c, size * sizeof(double));
  174.     if (cudaStatus != cudaSuccess) {
  175.         fprintf(stderr, "cudaMalloc failed!");
  176.         goto Error;
  177.     }
  178.     cudaStatus = cudaMalloc((void**)&dev_a, size * sizeof(double));
  179.     if (cudaStatus != cudaSuccess) {
  180.         fprintf(stderr, "cudaMalloc failed!");
  181.         goto Error;
  182.     }
  183.     cudaStatus = cudaMalloc((void**)&dev_b, size * sizeof(double));
  184.     if (cudaStatus != cudaSuccess) {
  185.         fprintf(stderr, "cudaMalloc failed!");
  186.         goto Error;
  187.     }
  188.  
  189.     /* 入力用にデータをコピーする */
  190.     cudaStatus = cudaMemcpy(dev_a, a, size * sizeof(double), cudaMemcpyHostToDevice);
  191.     if (cudaStatus != cudaSuccess) {
  192.         fprintf(stderr, "cudaMemcpy failed!");
  193.         goto Error;
  194.     }
  195.     cudaStatus = cudaMemcpy(dev_b, b, size * sizeof(double), cudaMemcpyHostToDevice);
  196.     if (cudaStatus != cudaSuccess) {
  197.         fprintf(stderr, "cudaMemcpy failed!");
  198.         goto Error;
  199.     }
  200.     cudaThreadSynchronize();
  201.  
  202.     /* 時間計測の準備 */
  203.     cudaEventCreate(&start);
  204.     cudaEventCreate(&stop);
  205.     cudaEventRecord(start,0);
  206.      
  207.     /* 各エレメントに対しカーネル関数を実行(それぞれブロック数、スレッド数*/
  208.     addKernel<<<gridSize, blockSize>>>(dev_c, dev_a, dev_b, size_x);
  209.  
  210.     /* 時間計測結果を取得 */
  211.     cudaEventRecord(stop,0);
  212.     cudaEventSynchronize(stop);
  213.     cudaEventElapsedTime(&elapsedTime,start,stop);
  214.  
  215.     printf("GPU計算時間:%3.9lf[s] -> %g[MFLOPS]\n", elapsedTime / 1000, size / elapsedTime / 1000.0);
  216.  
  217.     /* エラーが起きていないかをチェック */
  218.     cudaStatus = cudaGetLastError();
  219.     if (cudaStatus != cudaSuccess) {
  220.         fprintf(stderr, "addKernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
  221.         goto Error;
  222.     }
  223.  
  224.     /* 演算が完了するまで待機 */
  225.     cudaStatus = cudaDeviceSynchronize();
  226.     if (cudaStatus != cudaSuccess) {
  227.         fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
  228.         goto Error;
  229.     }
  230.  
  231.     /* 出力用にデータをコピーする */
  232.     cudaStatus = cudaMemcpy(c, dev_c, size * sizeof(double), cudaMemcpyDeviceToHost);
  233.     if (cudaStatus != cudaSuccess) {
  234.         fprintf(stderr, "cudaMemcpy failed!");
  235.         goto Error;
  236.     }
  237.  
  238. /* エラー発生時時はすぐにメモリを解放して終了 */
  239. Error:
  240.     cudaFree(dev_c);
  241.     cudaFree(dev_a);
  242.     cudaFree(dev_b);
  243.  
  244.     return cudaStatus;
  245. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement