4年くらい前に購入したノートパソコン上の FreeBSD で、実験した結果。 何も工夫しない場合 testddot.c に比べて、ループの アンロールをした場合 testddot2.c はスピードが 4 倍以上になる。
#include <stdio.h>
#define N 10000
/*
* 10k*10k=100M 回の乗算
* 10k*10k=100M 回の加算
* 200M回の浮動小数点演算
* 素朴にコンパイル 47.545u -> 4.2MFLOPS
* -O4 7.611u -> 26.3MFLOPS
* -O 9.061u -> 22.1MFLOPS
*/
double ddot(int n, double *x, double *y)
{
int i;
double s = 0;
for (i = 0; i < N; i++)
s += x[i] * y[i];
return s;
}
int main()
{
int i;
double x[N], y[N], z[N];
for (i = 0; i < N; i++) {
x[i] = rand();
y[i] = rand();
}
for (i = 0; i < N; i++)
z[i] = ddot(N, x, y);
}
#include <stdio.h>
#define N 10000
/*
* 10k*10k=100M 回の乗算
* 10k*10k=100M 回の加算
* 200M回の浮動小数点演算
* 素朴にコンパイル 9.483u -> 21.1 MFLOPS
* -O 1.940u -> 103.0 MFLOPS
* -O4 1.924u -> 104.0 MFLOPS
*/
double ddot(int n, double *x, double *y)
{
int i, n_div_8 = n / 8;
double s = 0;
for (i = 0; i < n_div_8; i++)
s += x[i] * y[i]
+ x[i+1] * y[i+1]
+ x[i+2] * y[i+2]
+ x[i+3] * y[i+3]
+ x[i+4] * y[i+4]
+ x[i+5] * y[i+5]
+ x[i+6] * y[i+6]
+ x[i+7] * y[i+7];
for (i = 8 * n_div_8; i < n; i++)
s += x[i] * y[i];
return s;
}
int main()
{
int i;
double x[N], y[N], z[N];
for (i = 0; i < N; i++) {
x[i] = rand();
y[i] = rand();
}
for (i = 0; i < N; i++)
z[i] = ddot(N, x, y);
}
2017-06-19