beg*_*ner 0 c time fortran matrix matrix-multiplication
我n*n在 Xeon 处理器系统上使用 C 和 FORTRAN运行矩阵乘法代码。我很惊讶地看到两种方法之间的实时差异。为什么 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;
}
Run Code Online (Sandbox Code Playgroud)
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];
}
}
}
Run Code Online (Sandbox Code Playgroud)
汇编:
icc –o C 代码的可执行程序.c
icc -o 可执行程序.c mkl=sequential for the Fortran one
表现
使用 5000*5000 的矩阵顺序,我的代码得到 4.2 GFLOPS,使用 dgemm() 得到 21.7 GFLOPS。
您仍然没有表现出足够的明确答案。值得注意的是,在任何有关性能的问题中,当您说某些东西更快时,您应该显示您所做的实际测量以及用于编译可执行文件的命令。
无论如何,可以得出一些结论。
您似乎没有使用任何优化(-O或-fast标志)。那么任何性能分析基本上都是毫无意义的。
从您展示的源代码中可以明显看出,您根本没有比较同一件事,而是在比较两种不同的算法。比较两种不同算法的速度绝对没有意义。gemm不包含您在自己的代码中使用的这种简单循环,它主要是为了优化缓存利用率而复杂得多。
您使用非常天真的方法在您自己的 C 代码中乘以矩阵。事实上,你现在(根据你的评论之一)现在比gemm实际上非常令人担忧。你确定你使用了足够大的矩阵吗?调用gemm10x10 矩阵是没有意义的,它们应该有一定的尺寸。gemm对于足够大的矩阵,应该比朴素循环快得多。如果您不对自己的函数使用任何编译器优化,那么 4.2 和 22 GFLOPS 的原始数字听起来是合理的。
您声称您正在与 Fortran 进行比较。这不是真的。只有参考 BLAS 实现是用 Fortran 编写的,但它不用于实际需要快速 BLAS 的严肃计算。您似乎正在使用的 MKL 不是用 Fortran 编写的,它是一个非常优化的汇编代码。还有其他可用的 BLAS 实现(ATLAS、GotoBLAS、OpenBLAS),它们通常不是用 Fortran 编写的,而是用 C 或汇编编写的。