Inte PAC AFUに何か処理をオフロードする場合,当然,結果を待つ必要があります.
シンプルにMMIO読み出しを使ってポーリングで処理完了を待つのに必要な時間を afu_hello をベースに測定してみました.
実験環境
afu_helloを使って,AFU処理終了をポーリングで待つのにかかる時間を測ってみました.afu_helloのメインのファイルafu.svに定義されているレジスタアクセスを,次のように変更します.また,テスト用のCプログラムもあわせて変更.
レジスタへの書き込み
//
// Receive MMIO writes
//
always_ff @(posedge clk)
begin
if (reset)
begin
scratch_reg <= '0;
scratch_reg2 <= '0;
scratch_reg3 <= 64'h80000000_00000000;
test_counter <= '0;
end
else
begin
// set the registers on MMIO write request
// these are user-defined AFU registers at offset 0x40.
if (cp2af_sRxPort.c0.mmioWrValid == 1)
begin
case (mmioHdr.address)
16'h0020: scratch_reg <= cp2af_sRxPort.c0.data[63:0];
16'h0022: scratch_reg2 <= cp2af_sRxPort.c0.data[63:0] * 2;
16'h0024: scratch_reg3 <= cp2af_sRxPort.c0.data[63:0];
endcase
end else if (scratch_reg3[63] == 1'b0) begin
if (test_counter[62:0] == scratch_reg3[62:0]) begin
scratch_reg3[63] <= 1'b1;
test_counter <= 64'd0;
end else begin
test_counter <= test_counter + 1;
end
end
end
end
レジスタへの読み込み
//
// Handle MMIO reads.
//
always_ff @(posedge clk)
begin
if (reset)
begin
...
end
else
begin
...
if (cp2af_sRxPort.c0.mmioRdValid == 1'b1)
begin
...
case (mmioHdr.address)
...
// Scratch Register. Return the last value written
// to this MMIO address.
16'h0020: af2cp_sTxPort.c2.data <= scratch_reg;
16'h0022: af2cp_sTxPort.c2.data <= scratch_reg2;
16'h0024: af2cp_sTxPort.c2.data <= scratch_reg3;
...
default: af2cp_sTxPort.c2.data <= 64'h0;
endcase
end
end
end
テスト用Cプログラム
volatile fpga_result r = FPGA_OK;
volatile uint64_t d;
double t0 = get_localtime_in_sec();
for(volatile int i = 0; i < 1000000; i++){
r = fpgaWriteMMIO64(afc_handle, 0, 0x90, v);
do{
r = fpgaReadMMIO64(afc_handle, 0, 0x90, &d);
//printf("status %016lx\n", d);
}while((d << 63) == 0);
}
double t1 = get_localtime_in_sec();
printf("elapsed time: %lf sec\n", (t1-t0));
r = fpgaReadMMIO64(afc_handle, 0, 0x90, &d);
printf("status %016lx\n", d);
実験結果
AFU処理に相当するカウンタの値を適当に設定しながら,実行時間を測定します.
for i in $(seq 14); do ./a.out $((2**($i-1))); done
として実行した結果は次の通り.1,000,000回ループした実行時間であることに注意してみてください.
目安としては1回あたりMMIO読み書きで1us,
また,AFUでの処理が500サイクルを超えるあたりから,ポーリングのオーバヘッドはあまり気にしなくてもよい,と言ってもいいかな?
もちろん,処理待ち時間をうまく他の処理で隠蔽するとか試みるのがいいですけどね.
カウンタ(AFU処理サイクル数) | 実行時間(秒,1000000回繰り返し) |
---|---|
1 | 1.031962 |
2 | 1.021074 |
4 | 1.022565 |
8 | 1.021267 |
16 | 1.027765 |
32 | 1.763314 |
64 | 1.858461 |
128 | 1.673958 |
256 | 2.699386 |
512 | 3.958413 |
1024 | 6.272787 |
2048 | 11.813739 |
4096 | 21.701357 |
8192 | 42.139092 |