1 1 Тестовая последовательная задача

Для иллюстрации возможности технологии CUDA рассмотрим для начала решение задачи Эйлера, написанное на языке программирования C с использованием только возможностей центрального процессора компьютера. Подробно эту задачу мы обсуждали в одном из предыдущих параграфов, поэтому просто приведем исходный текст программы, реализующий численный метод ее решения.

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <sys/types.h>
  4. #include <time.h>
  5. #include <stdlib.h>
  6.  
  7. #define xmax 49152
  8. #define ymax 1000
  9.  
  10. //Подпрограмма задания начальных значений
  11. void initial(float *f[ymax]) {
  12. int x,y;
  13. //Задаем начальные значения массива
  14. for(x=0;x<xmax;x++) {
  15. for(y=0;y<ymax;y++) {
  16. f[x][y]=0.0;
  17. }}
  18. }
  19.  
  20. //Подпрограмма задания граничных условий
  21. void boundary(float *f[ymax]) {
  22. int x,y;
  23. //Задаем граничные значения массива
  24. for(y=0;y<ymax;y++) {
  25. f[0][y]=0.0;
  26. f[xmax-1][y]=0.0;
  27. }
  28. for(x=0;x<xmax;x++) {
  29. f[x][0]=sin((x*1.0)/(xmax/2));
  30. f[x][ymax-1]=0.0;
  31. }
  32. f[xmax/2][ymax-1]=-5.0;
  33. }
  34.  
  35. //Подпрограмма итерационного процесса
  36. float iter(float *a[ymax], float *b[ymax]) {
  37. float dt = 0.01;
  38. float dx = 0.5;
  39. float dy = 0.5;
  40. float dff, df;
  41. int x,y;
  42.  
  43. df=0.0;
  44. for(x=1;x<xmax-1;x++) {
  45. for(y=1;y<ymax-1;y++) {
  46. dff = dt * (
  47. ((a[x+1][y]-(2*a[x][y])+a[x-1][y])/(dx*dx))
  48. +
  49. ((a[x][y+1]-(2*a[x][y])+a[x][y-1])/(dy*dy))
  50. );
  51. b[x][y]=a[x][y]+dff;
  52. if( df < fabs(dff) ) { df=fabs(dff); }
  53.  
  54. }}
  55. return df;
  56. }
  57.  
  58. void main() {
  59. printf("Start... [%dx%d]\n",xmax,ymax);
  60. float df = 0.0; int n=0,i;
  61. float elapsed;
  62. clock_t start, end;
  63.  
  64. float **f0 = malloc(xmax * sizeof(float *));
  65. float **f1 = malloc(xmax * sizeof(float *));
  66. for(i=0;i<xmax;i++) f0[i] = malloc(ymax * sizeof(float));
  67. for(i=0;i<xmax;i++) f1[i] = malloc(ymax * sizeof(float));
  68.  
  69. initial(f0); initial(f1);
  70. boundary(f0); boundary(f1);
  71.  
  72. printf("Begin calculations...\n");
  73.  
  74. start=clock();
  75. do {
  76. if ( ((n/2)*2) == n ) {
  77. df = iter(f0,f1);
  78. }else{
  79. df = iter(f1,f0);
  80. }
  81. n++;
  82. //printf(" [%d] Diff: %f\n",n,df);
  83. } while ( df > 0.01 );
  84. end=clock();
  85. elapsed=((float) (end - start)) / CLOCKS_PER_SEC;
  86.  
  87. for(i=0;i<xmax;i++) free((void *) f0[i]);
  88. for(i=0;i<xmax;i++) free((void *) f1[i]);
  89. free((void *) f0); free((void *) f1);
  90.  
  91. printf("Calculation time: %2lf sec.\n",elapsed);
  92. printf("Iteration count: %d\n",n);
  93. printf("Averege Iteration time: %.2lf sec.\n",elapsed/n);
  94. }
  95.  

Вычисления мы будем проводить на матрице размера 49152x1000 элементов. Как и раньше особого смысла ни в начальных, ни в граничных условиях задачи нет, поскольку нас интересует в данном случае не физический смысл, а сам процесс счета, точнее его скоростные характеристики.

Поскольку графический процессор видеокарты по сути является мультипроцессором, каждое ядро которого способно выполнять несколько потоков команд обновременно, то логично будет разнести внутренний цикл итерации по оси Y разностной сетки(строка программы 45) в отдельные параллельно исполняемые блоки, получив значительный прирост быстродействия. Этим мы и займемся в следующем параграфе.


Copyright © 1998-2011 Юрий Сбитнев