Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
FORTRAN比C快——对于在同一个处理器上运行的矩阵乘法程序,为什么?_C_Matrix_Time_Fortran_Matrix Multiplication - Fatal编程技术网

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

FORTRAN比C快——对于在同一个处理器上运行的矩阵乘法程序,为什么?,c,matrix,time,fortran,matrix-multiplication,C,Matrix,Time,Fortran,Matrix Multiplication,我在xeon处理器系统上使用C和FORTRAN运行n*n矩阵乘法代码。我惊讶地看到这两种方法之间的实时差异。为什么FORTRAN代码给了我更快的执行时间?我使用了dgemm(),并从我的C代码中调用了相同的函数。我尝试运行通用C代码,改变循环顺序,并尝试使用不同的标志来优化模拟过程。我无法获得使用dgemm()获得的相同响应 FORTRAN代码-dgemm(): #包括“stdio.h” #包括“time.h” #包括“sys/time.h” #包括“math.h” #包括“stdlib.h”

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

FORTRAN代码-dgemm():

#包括“stdio.h”
#包括“time.h”
#包括“sys/time.h”
#包括“math.h”
#包括“stdlib.h”
长读TSC(无效)
{
/*读取英特尔x86芯片上的时间戳计数器*/
并集{long-long-complete;无符号整数部分[2];}个记号;
__asm_uu2;(“rdtsc;mov%%eax,%0;mov%%edx,%1”
:“=mr”(第[0]部分),
“=mr”(第[1]部分)
:/*无输入*/
:“eax”、“edx”);
返回ticks.complete;
}
挥发性双gtod(无效)
{
静态结构时间值电视;
静态结构时区;
gettimeofday(&tv,&tz);
返回tv.tv_sec+1.e-6*tv.tv_usec;
}
无效dgemm(字符*transa,字符*transb,字符*x,字符*xa,字符*xb,双字符*alphaa,双字符*ma,字符*xc,双字符*mb,字符*xd,双字符*betaa,双字符*msum,双字符*xe);
int main(int argc,字符**argv)
{
int n=atoi(argv[1]);
朗朗tm;
//禁用转置,禁用C中的加法运算:=alpha*op(A)*op(B)+beta*C
char trans='N';
双α=1.0;
双β=0.0;
长整型p=2*n*n*n;
长双q;
双倍*a、*b、*和;
双t_real,t,flop_clk,flops;
int i,j,k;
//内存分配
a=(双*)malloc(n*n*sizeof(双));
b=(双*)malloc(n*n*sizeof(双));
总和=(双*)malloc(n*n*sizeof(双));
//矩阵初始化

对于(i=0;i只是一个猜测,因为OP没有显示任何代码。如果他正在调用(来自LAPACK BLAS),则可能是用Fortran编写的

C和Fortran中的规则是不同的

在C例程中声明形式时,可以(小心!)使用
restrict
关键字。这应该会有所帮助

此外,C和Fortran中的算术也不同。在C的某些方言中(例如C89),每个浮点运算都是基于双精度数字计算的。IIRC在Fortran中的定义不同。并且在C89和C99之间发生了变化(可能在C11中也发生了变化)

如果您的两个代码是由最近的编译器编译的(即,对于c代码使用
gcc-O2 foo.c
,对于Fortran90代码使用
gfortran-O2 foo.f90
),则这两个编译器都会生成相似的内部表示(Gimple,您可以使用
-fdump tree ssa
或许多其他生成数百个转储文件的
-fdump
标志获得它),然后对其进行优化。因此,在这种情况下,编译器后端相同,中间端非常相似,但前端确实不同

您只需查看汇编代码(使用
gcc-O2-fverbose asm
&
gfortran-O2-fverbose asm
)即可发现差异


您可以使用其他选项,如
-ffast math
(这使编译器能够针对标准进行优化)或
-mtune=native
(这要求GCC编译器针对特定处理器进行优化)除了
-O2
-O3
优化标志…

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

无论如何,可以得出一些结论

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

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

  • 您在自己的C代码中使用了非常简单的方法来乘以矩阵现在比
    gemm
    快实际上是非常令人担忧的。你确定你使用了足够大的矩阵吗?在矩阵10x10上调用
    gemm
    是没有意义的,它们应该有一些相当大的大小。
    gemm
    应该比足够大的矩阵的原始循环快得多。原始数字为4.2和22 GFLOPS sou如果您不为自己的函数使用任何编译器优化,那么nd是合理的

  • 您声称您正在与Fortran进行比较。这不是真的。只有参考BLAS实现是用Fortran编写的,但它不用于实际需要快速BLAS的严重计算。您似乎正在使用的MKL不是用Fortran编写的,它是一个非常优化的汇编代码。BLAS av还有其他实现它们通常不是用Fortran编写的,而是用C或汇编语言编写的


  • 可能有很多原因,但通常Fortran是为数学工作和Fortran编译器设计的(一开始很好)在语言存在的近60年中,它才变得更好。像这样的问题会有很多猜测,但除非你在问题中同时展示Fortran和C代码,否则没有人能给你一个准确的答案。解释你是如何测量基准的也是一个好主意。关于什么工具的详细信息s、 编译器和传递的编译器标志也很有用。请显示一些代码以便编辑您的问题。如果OP选择修改此问题,请
    #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;
     }
    
    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];
        }
      }
    }