FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

RISC-V Vector 1.0 をサポートするオープンソースCPU Araを試す (3. ベンチマークの実行)

github.com

Araでベクトル化したmemcpyのベンチマークを実行したくて、いろいろ試行錯誤していたが、テストの追加方法が分かってきた。以下のテストプログラムを動かしたいとする。

void *memcpy_vec(void *dst, void *src, size_t n) {
  void *save = dst;
  // copy data byte by byte
  for (size_t vl; n > 0; n -= vl, src += vl, dst += vl) {
    vl = vsetvl_e8m8(n);
    vuint8m8_t vec_src = vle8_v_u8m8(src, vl);
    vse8_v_u8m8(dst, vec_src, vl);
  }
  return save;
}

これを実行するためのmain()は以下。2回回して、L1Dキャッシュに乗っている前提でサイクル数を測定する。

int main() {
  const int N = 1024;
  const uint32_t seed = 0xdeadbeef;
  srand(seed);

  long long vlenb;
  asm volatile ("csrr %0, vlenb":"=r"(vlenb));
  printf("VLENB = %lld\n", vlenb);

  // data gen
  double A[N];
  gen_rand_1d(A, N);

  // compute
  double golden[N], actual[N];
  memcpy(golden, A, sizeof(A));
  memcpy_vec(actual, A, sizeof(A));

  long long start_cycle;
  long long stop_cycle;

  asm volatile ("fence.i");
  asm volatile ("csrr %0, cycle":"=r"(start_cycle));
  // Replay with Cache
  memcpy_vec(actual, A, sizeof(A));
  asm volatile ("csrr %0, cycle":"=r"(stop_cycle));

  // compare
  printf(compare_1d(golden, actual, N) ? "pass" : "fail");
  printf("start_cycle = %lld, stop_cycle = %lld, cycle = %lld\n",
         start_cycle, stop_cycle, stop_cycle - start_cycle);
}

これをAraのapps/memcpy_vecに追加して、appsの上でビルドコマンドを実行する。

make bin/memcpy_vec

これで自動的にbin/mempcy_vecが作成される。RTLシミュレーションも、makeコマンドで一発だ。

app=memcpy_vec make simv trace=1
Simulation of Ara
=================

Tracing can be toggled by sending SIGUSR1 to this process:
$ kill -USR1 1a119c
Tracing enabled.
Writing simulation traces to sim.fst

Simulation running, end by pressing CTRL-c.
VLENB = 512
passstart_cycle = 102981, stop_cycle = 104040, cycle = 1059
[hw-cycles]:           0
[266730] -Info: ara_tb_verilator.sv:49: Assertion failed in TOP.ara_tb_verilator: Core Test *** SUCCESS *** (tohost = 0)
- /home/msyksphinz/work/riscv/ara_vector/ara/hardware/tb/ara_tb_verilator.sv:52: Verilog $finish
Received $finish() from Verilog, shutting down simulation.

Simulation statistics
=====================
Executed cycles:  208f5
Wallclock time:   62.993 s
Simulation speed: 2117.14 cycles/s (2.11714 kHz)
Trace file size:  b79b7df B

なるほど、しかし8kBのコピーを1059サイクルでコピーしたとならば、バンド幅は8B程度となりスカラ命令と同じくらいの性能になってしまう。波形を見てみよう。

AXIに対してメモリアクセスが走っているのは分かる。AXIのバスが128ビットだから、それを512回繰り返している、ということか。本当はロードとストアがオーバラップしてほしいのだが、ここが制約で性能がボトルネックになっているのかな。

次にSAXPYを流してみよう。

// reference https://github.com/riscv/riscv-v-spec/blob/master/example/saxpy.s
void saxpy_vec(size_t n, const float a, const float *x, float *y) {
  size_t l;

  vfloat32m8_t vx, vy;

  for (; n > 0; n -= l) {
    l = vsetvl_e32m8(n);
    vx = vle32_v_f32m8(x, l);
    x += l;
    vy = vle32_v_f32m8(y, l);
    vy = vfmacc_vf_f32m8(vy, a, vx, l);
    vse32_v_f32m8 (y, vy, l);
    y += l;
  }
}
Simulation of Ara
=================

Tracing can be toggled by sending SIGUSR1 to this process:
$ kill -USR1 1a3003
Tracing enabled.
Writing simulation traces to sim.fst

Simulation running, end by pressing CTRL-c.
passed
start_cycle = 514468, stop_cycle = 517606, cycle = 3138
[hw-cycles]:           0
[1267454] -Info: ara_tb_verilator.sv:49: Assertion failed in TOP.ara_tb_verilator: Core Test *** SUCCESS *** (tohost = 0)
- /home/kimura/work/riscv/ara_vector/ara/hardware/tb/ara_tb_verilator.sv:52: Verilog $finish
Received $finish() from Verilog, shutting down simulation.

Simulation statistics
=====================
Executed cycles:  9ab7f
Wallclock time:   306.943 s
Simulation speed: 2064.64 cycles/s (2.06464 kHz)
Trace file size:  31a98bed B

4096要素のSAXPYを3138サイクルで実行しているので、1要素あたりは0.76サイクルで実行されている。これもAXIのバンド幅が律速となっている気がするなあ。

波形を確認してみる。やはり、メモリアクセスはインオーダに実行されているようだ。