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回繰り返し)
11.031962
21.021074
41.022565
81.021267
161.027765
321.763314
641.858461
1281.673958
2562.699386
5123.958413
10246.272787
204811.813739
409621.701357
819242.139092