繁体   English   中英

OpenMP C ++矩阵乘法

[英]OpenMP C++ matrix multiplication

我想并行化以下代码。 尤其是这些for循环,因为这是最昂贵的操作。

      for (i = 0; i < d1; i++)
         for (j = 0; j < d3; j++)
             for (k = 0; k < d2; k++)
             C[i][j] = C[i][j] + A[i][k] * B[k][j];  

这是我第一次尝试使用OpenMP并行化代码。 我已经尝试了几件事,但是与使用串行版本相比,我总是会遇到更糟糕的运行时。 如果您能告诉我代码或实用程序是否有问题,那将是很好的...

      #include <omp.h>
      #include <stdio.h>
      #include <stdlib.h>
      //#include <stdint.h>

      // ---------------------------------------------------------------------------
      // allocate space for empty matrix A[row][col]
      // access to matrix elements possible with:
      // - A[row][col]
      // - A[0][row*col]


      float **alloc_mat(int row, int col)
      {
          float **A1, *A2;

          A1 = (float **)calloc(row, sizeof(float *));      // pointer on rows
          A2 = (float *)calloc(row*col, sizeof(float));    // all matrix elements

          //#pragma omp parallel for
          for (int i=0; i<row; i++)
              A1[i] = A2 + i*col;

          return A1;
      }

      // ---------------------------------------------------------------------------
      // random initialisation of matrix with values [0..9]

      void init_mat(float **A, int row, int col)
      {   
          //#pragma omp parallel for
          for (int i = 0; i < row*col; i++)
              A[0][i] = (float)(rand() % 10);
      }

      // ---------------------------------------------------------------------------
      // DEBUG FUNCTION: printout of all matrix elements

      void print_mat(float **A, int row, int col, char *tag)
      {
          int i, j;

          printf("Matrix %s:\n", tag);
          for (i = 0; i < row; i++)
          {
              //#pragma omp parallel for
              for (j=0; j<col; j++) 
                  printf("%6.1f   ", A[i][j]);
              printf("\n"); 
          }
      }

      // ---------------------------------------------------------------------------

      int main(int argc, char *argv[])
      {
          float **A, **B, **C;  // matrices
          int d1, d2, d3;         // dimensions of matrices
          int i, j, k;          // loop variables


          double start, end;
          start = omp_get_wtime();

          /* print user instruction */
          if (argc != 4)
          {
              printf ("Matrix multiplication: C = A x B\n");
              printf ("Usage: %s <NumRowA>; <NumColA> <NumColB>\n",argv[0]); 
               return 0;
           }

           /* read user input */
           d1 = atoi(argv[1]);      // rows of A and C
           d2 = atoi(argv[2]);     // cols of A and rows of B
           d3 = atoi(argv[3]);     // cols of B and C

           printf("Matrix sizes C[%d][%d] = A[%d][%d] x B[%d][%d]\n", 
           d1, d3, d1, d2, d2, d3);

           /* prepare matrices */
           A = alloc_mat(d1, d2);
           init_mat(A, d1, d2); 
           B = alloc_mat(d2, d3);
           init_mat(B, d2, d3);
           C = alloc_mat(d1, d3);   // no initialisation of C, 
       //because it gets filled by matmult

           /* serial version of matmult */
           printf("Perform matrix multiplication...\n");



           int sum;
           //#pragma omp parallel
           //{
               #pragma omp parallel for collapse(3) schedule(guided)
               for (i = 0; i < d1; i++)
                   for (j = 0; j < d3; j++)
                       for (k = 0; k < d2; k++){
                       C[i][j] = C[i][j] + A[i][k] * B[k][j];
                       }
           //}


           end = omp_get_wtime();


           /* test output */
           print_mat(A, d1, d2, "A"); 
           print_mat(B, d2, d3, "B"); 
           print_mat(C, d1, d3, "C"); 

           printf("This task took %f seconds\n", end-start);
           printf ("\nDone.\n");

           return 0;
       }

正如注释中所建议的那样,矩阵的大小可能足够小,以至于初始化附加线程的开销大于并行计算矩阵乘法所节省的时间。 但是,请考虑以下图表,其中包含我通过在有和没有OpenMP的情况下运行代码所获得的数据。 串行与并行矩阵乘法比较

我使用从n = 10到n = 1000的平方矩阵。 请注意,并行版本如何在n = 50到n = 100之间变得更快。

但是,在尝试编写快速矩阵乘法时,还需要考虑其他问题,这主要与有效使用缓存有关。 首先,您连续分配整个矩阵(这很好),但是仍然使用两个指针重定向来访问数据,这是不必要的。 此外,矩阵以行主格式存储,这意味着您将连续访问A和C中的数据,而不是B中的数据。与其显式存储B并将A的行与B的列相乘,不如将其存储为A。通过存储B转置并将B的A元素行与B的换行相乘,可以更快地进行乘法。

这是仅针对A * B的优化,但是,在代码中可能还有其他地方存储B比B转置更好,在这种情况下,经常通过分块进行矩阵乘法可以提高缓存利用率

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM