B. ループのアンロールの効果の実験

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