用于循环速度 c 的英特尔编译器
Intel compilator for loop speed c
我很难理解为什么这段代码 运行 使用 Intel 编译器 12 时速度惊人,而使用 Intel 编译器 16
时却变慢了
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i,t;
int n=10000000;
int T=1000;
time_t t1,t2;
// double A[n],B[n],C[n];
double *A = (double*) malloc (sizeof(double)*n);
double *B = (double*) malloc (sizeof(double)*n);
double *C = (double*) malloc (sizeof(double)*n);
for (i=0;i<n;i++)
{
A[i]=1.0;
B[i]=2.0;
}
t1=clock();
for (t=0;t<T;t++)
for (i=0;i<n;i++)
C[i]=A[i]*B[i];
t2=clock();
double sum=0.0;
for (i=0;i<n;i++) sum += C[i];
printf("sum %f\n",sum);
printf("time %f\n",(double)(t2-t1)/CLOCKS_PER_SEC);
}
- Intel 编译器 12:在 sandy bridge 上 运行 需要 0.1 秒;英特尔
编译器 16:在 sandy bridge
上 运行 需要 25 秒
生成文件:
icc -O2 -o array array.c
很可能,其中一个编译器积极优化了整个繁琐的嵌套循环。您的优化代码似乎最终可能是:
t1=clock();
t2=clock();
double sum=0.0;
for (i=0;i<n;i++) sum += A[i]*B[i];
编译器做这样的优化是完全没问题的。您可以通过使循环迭代器 volatile
.
来阻止优化
确保您在两个编译器上启用了相同级别的优化。
这两个嵌套循环是可向量化的,前提是编译器确保 A
、B
和 C
指向的三个内存区域没有别名。具体来说,通过 C
存储的值永远无法通过 A
和 B
再次读取 - 如果循环迭代 运行 并行,这将是一个危险,不同于代码中暗示的加载和存储顺序。
在一般情况下,编译器将无法从函数调用返回的指针中推断出这一点,尽管它可能合法地了解更多关于标准库函数的语义,例如 malloc()
而不是单独的函数签名会推断出来。
您看到的差异可能是由于编译器版本之间别名规则的严格性发生了变化,或者可能是由于不同的默认选项开关。
在指针声明中添加 restrict
限定符告诉编译器它可以假设别名不会通过使用指针发生,并且责任在于程序员 gua运行开球。
double * restrict A = malloc (sizeof(double)*n);
double * restrict B = malloc (sizeof(double)*n);
double * restrict C = malloc (sizeof(double)*n);
我很难理解为什么这段代码 运行 使用 Intel 编译器 12 时速度惊人,而使用 Intel 编译器 16
时却变慢了#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i,t;
int n=10000000;
int T=1000;
time_t t1,t2;
// double A[n],B[n],C[n];
double *A = (double*) malloc (sizeof(double)*n);
double *B = (double*) malloc (sizeof(double)*n);
double *C = (double*) malloc (sizeof(double)*n);
for (i=0;i<n;i++)
{
A[i]=1.0;
B[i]=2.0;
}
t1=clock();
for (t=0;t<T;t++)
for (i=0;i<n;i++)
C[i]=A[i]*B[i];
t2=clock();
double sum=0.0;
for (i=0;i<n;i++) sum += C[i];
printf("sum %f\n",sum);
printf("time %f\n",(double)(t2-t1)/CLOCKS_PER_SEC);
}
- Intel 编译器 12:在 sandy bridge 上 运行 需要 0.1 秒;英特尔 编译器 16:在 sandy bridge 上 运行 需要 25 秒
生成文件: icc -O2 -o array array.c
很可能,其中一个编译器积极优化了整个繁琐的嵌套循环。您的优化代码似乎最终可能是:
t1=clock();
t2=clock();
double sum=0.0;
for (i=0;i<n;i++) sum += A[i]*B[i];
编译器做这样的优化是完全没问题的。您可以通过使循环迭代器 volatile
.
确保您在两个编译器上启用了相同级别的优化。
这两个嵌套循环是可向量化的,前提是编译器确保 A
、B
和 C
指向的三个内存区域没有别名。具体来说,通过 C
存储的值永远无法通过 A
和 B
再次读取 - 如果循环迭代 运行 并行,这将是一个危险,不同于代码中暗示的加载和存储顺序。
在一般情况下,编译器将无法从函数调用返回的指针中推断出这一点,尽管它可能合法地了解更多关于标准库函数的语义,例如 malloc()
而不是单独的函数签名会推断出来。
您看到的差异可能是由于编译器版本之间别名规则的严格性发生了变化,或者可能是由于不同的默认选项开关。
在指针声明中添加 restrict
限定符告诉编译器它可以假设别名不会通过使用指针发生,并且责任在于程序员 gua运行开球。
double * restrict A = malloc (sizeof(double)*n);
double * restrict B = malloc (sizeof(double)*n);
double * restrict C = malloc (sizeof(double)*n);