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のバンド幅が律速となっている気がするなあ。
波形を確認してみる。やはり、メモリアクセスはインオーダに実行されているようだ。