c - FORTRAN 比 C 快 - 对于在同一处理器上运行的矩阵乘法程序,为什么?

标签 c matrix time fortran matrix-multiplication

我在至强处理器系统上使用 C 和 FORTRAN 运行 n*n 矩阵乘法代码。看到这两种方法之间的实时差异,我感到很惊讶。为什么 FORTRAN 代码执行速度更快?我正在使用 dgemm() 并从我的 C 代码中调用相同的函数。我尝试运行通用 C 代码来更改循环顺序并尝试使用不同的标志来优化模拟过程。我无法达到使用 dgemm() 获得的相同响应。

FORTRAN 代码 - dgemm():

#include "stdio.h"
#include "time.h"
#include "sys/time.h"
#include "math.h"
#include "stdlib.h"

long long readTSC(void)
{
 /* read the time stamp counter on Intel x86 chips */
  union { long long complete; unsigned int part[2]; } ticks;
  __asm__ ("rdtsc; mov %%eax,%0;mov %%edx,%1"
        : "=mr" (ticks.part[0]),
          "=mr" (ticks.part[1])
        : /* no inputs */
        : "eax", "edx");
 return ticks.complete;
}
volatile double gtod(void)
{
 static struct timeval tv;
 static struct timezone tz;
 gettimeofday(&tv,&tz);
 return tv.tv_sec + 1.e-6*tv.tv_usec;
}

void dgemm (char *transa, char *transb, int *x, int *xa, int *xb, double    *alphaa, double *ma, int *xc, double *mb, int *xd, double *betaa, double *msum,   int *xe);
 int main(int argc, char** argv)
 {
   int n = atoi(argv[1]);
   long long tm;

  //disabling transpose, disabling addition operation in C :=       alpha*op(A)*op(B) + beta*C
 char trans='N';
 double alpha=1.0;
 double beta=0.0;


 long long int p=2*n*n*n;
 long double q;
 double *a,*b,*sum;
 double t_real,t,flop_clk,flops;
 int i,j,k;

 //memory allocation
 a=(double*)malloc(n*n*sizeof(double));
 b=(double*)malloc(n*n*sizeof(double));
 sum=(double*)malloc(n*n*sizeof(double));

 //Matrix Initialization
 for (i=0;i<n;i++)
  {
    for (j=0;j<n;j++)
    {
       a[i+n*j]=(double)rand();
      b[i+n*j]=(double)rand();
      sum[i+n*j]=0.0;
    }
 }

//Clock cycles computation using timing2 function and t_real using timing1   function
  t = gtod();

 tm = readTSC();
//dgemm function call
 dgemm(&trans, &trans, &n, &n, &n, &alpha, a, &n, b, &n, &beta, sum, &n);
 tm = readTSC() - tm;
 t_real = gtod() - t;
 return 0;
 }

C代码 只需取 sum=0 然后

for (i=0;i<n;i++)
{
  for (k=0;k<n;k++)
  {
    for (j=0;j<n;j++)
    {
      sum [i+n*j] +=a[i+n*k]*b[k+n*j];
    }
  }
} 

编译:

  • icc –o C代码的可执行程序.c

  • icc -o executable program.c mkl=sequential for Fortran

性能

矩阵阶数为 5000*5000,我的代码得到了 4.2 GFLOPS,使用 dgemm() 得到了 21.7 GFLOPS。

最佳答案

您的表现仍然不足以给出明确的答案。值得注意的是,在任何关于性能的问题中,当您说某些东西更快时,您应该展示您所做的实际测量以及您用于编译可执行文件的命令。

总之,可以得出一些结论。

  1. 您似乎没有使用任何优化(-O-fast 标志)。那么任何性能分析基本上都是毫无意义的。

  2. 从您展示的源代码可以清楚地看出,您根本没有比较同一事物,您是在比较两种不同的算法。比较两种不同算法的速度绝对没有意义。 gemm 不包含您在自己的代码中使用的这种简单循环,它要复杂得多,主要是为了优化缓存利用率。

  3. 您在自己的 C 代码中使用了非常幼稚的矩阵相乘方法。事实上,您现在(根据您的评论之一)现在比 gemm 快,这实际上非常令人担忧。你确定你使用了足够大的矩阵吗?在 10x10 矩阵上调用 gemm 没有意义,它们应该有相当大的尺寸。对于足够大的矩阵,gemm 应该比原始循环快得多。如果您不对自己的函数使用任何编译器优化,那么 4.2 和 22 GFLOPS 的原始数字听起来很合理。

  4. 您声称您正在与 Fortran 进行比较。这不是真的。只有引用 BLAS 实现是用 Fortran 编写的,但它不用于实际需要快速 BLAS 的严肃计算。您似乎正在使用的 MKL 不是用 Fortran 编写的,它是一个非常优化的汇编代码。还有其他可用的 BLAS 实现(ATLAS、GotoBLAS、OpenBLAS),它们通常不是用 Fortran 语言编写的,而是用 C 语言或汇编语言编写的。

关于c - FORTRAN 比 C 快 - 对于在同一处理器上运行的矩阵乘法程序,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31335657/

相关文章:

c++ - 使用 C++ 在 OpenCV 中使用我的自定义最大值和自定义最小值对 0 和 1 之间的矩阵进行归一化

c++ - 矩阵(行,列)=值

ruby-on-rails - 检查当前时间是否在10之前 :27pm

algorithm - 在在线国际象棋游戏中,如何最大程度地减少时间控制滞后的影响?

ubuntu - ffmpeg 的输出

c - 如何使用 read 将字符正确存储在数组中?

c - memset 如何提供比 bzero 或 explicit_bzero 更高的安全性?

c - 是否有任何 C 实现具有无用的单位 `int` 位域?

C 使用 == 比较字符串

algorithm - 任意矩阵乘法的复杂性