Intel PAC AFUでポーリング処理をしてみると

Pocket

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