FPGAでベンチマークしたとき
に苦労した話 @fpgax#12
2019/11/12
安藤 潤
自己紹介
● 名前
○ 安藤 潤
● 略歴
○ 国内ASICベンダーで11年ほど画像処理IP開発
■ アルゴ~Cモデル~RTL設計~検証~FPGA評価~ES評価
○ ザイリンクスで1年ほど技術
Xilinx Alveo
昨年、量産向けFPGAアクセラレータカードを発表
ベンチマークしなくては!
SDAccelがあるからHLSでサクッといけそう(楽観 / 無知)
CPUやGPUに勝つには?
CPU GPU FPGA
動作周波数 3GHz 1.5GHz 300MHz
メモリ帯域 ~数百GB/s ~数百GB/s ~数百GB/s
並列度 ~数十 ~数千 任意
アーキテクチャ
ノイマン型コンピュータ
命令セットアーキテクチャ
DSA
(ドメイン特化
アーキテクチャ)
● FPGAに向いている計算
○ DRAMアクセス<計算量
■ メモリ帯域がボトルネックにならないこと
○ データフローで表現できる計算
■ 計算(タスク)を並列化できる
■ データが流れてさえいれば演算器の稼働率が上がるデザイン
モンテカルロ法による円周率計算
● 乱数で平面にランダムな点(𝒙,𝒚)を打ち、
四分円の内側に入った数をカウントし
円周率を計算
● 乱数生成スピードでベンチマーク!
メルセンヌツイスタ
● ハードウェア実装に適していそう
内部状態更新
statet+1[623] = update(statet[0], statet[1], statet[397])
statet+1[0..622] = statet[1..623]
乱数出力
outt+1 = tempering(statet+1[623])
FPGA実装
● やることはふたつ
○ ハードウェアをHLSで記述
○ ホストアプリはOpenCL Runtime APIを使って記述
● 他の仕事はすべてSDAccelが面倒見てくれる、楽ちん!
GPU実装
● GPU(GeForce GTX 1080 Ti)
○ CUDA Toolkit v10.0.130
○ cuRAND
○ MTGP32 (Mersenne Twister for Graphic Processors)
ベンチマーク結果
● なんとか勝てた…
でももっとできる子のはず!!
性能 3x
性能/W 15x
並列度の向上
● U200のデバイスは3つのダイ(SLR)で構成される
○ が、1つしか使っていなかった…
○ 256並列のカーネルがひとつ
○ リンカの引数でカーネルを複製して複数のSLRへ分配!
xocc -l … ¥
--nk mcpi:5 ¥ 複製
--slr mcpi_1:SLR0 ¥ SLR割付
--slr mcpi_2:SLR0 ¥
--slr mcpi_3:SLR1 ¥
--slr mcpi_4:SLR2 ¥
--slr mcpi_5:SLR2
周波数の向上
● 当初は185MHz
● メルセンヌツイスタ実装方法を変更
○ 変更前:32bit x 624の内部状態をFFで保持 → 配線混雑
○ 変更後:BRAMで実装
● パイプライン構造を変更
○ 変更前:パイプラインが大きく遠くまで制御信号が広がる
○ 変更後:複数の小さなパイプラインをつなぐ構造へ
● HLSならアーキテクチャ探索が簡単!
大事そうなことなのでもう少し詳しく
● 良くない😫:大きなパイプラインがひとつ
○ ひとつのfor文に処理を詰め込む
■ ソフトウェア的な発想だと自然
○ 制御信号が遠くまで広がる
■ fanout、配線遅延、クロックリージョンまたぎ
○ SLRに納まりが悪そう
パイプライン
制御信号
for (int i=0; i<N; i++)
{
auto x = mem_in[i];
auto y = func_a(x);
auto z = func_b(y);
auto w = func_c(z);
mem_out[i] = w;
}
大事そうなことなのでもう少し詳しく
● 良さそう😀:小さなパイプラインをストリームでつなぐ
○ for文を分割
○ ストリーム(FIFO)により配置の自由度が向上
#pragma HLS DATAFLOW
hls::stream<DATATYPE> x, y, z, w;
#pragma HLS stream variable=x depth=2
#pragma HLS stream variable=y depth=2
#pragma HLS stream variable=z depth=2
#pragma HLS stream variable=w depth=2
mem_read(mem_in, x);
func_a(x, y);
func_b(y, z);
func_c(z, w);
mem_write(w, mem_out);
出来上がるハードウェアを
思い浮かべながらC++で記述!
改善結果 (改善前:256並列、185MHz、47Gs/s)
● 並列度
○ 64並列のカーネルを10個 = 640並列
● 周波数
○ 375MHzに改善
4個
2個
4個
性能 [Gs/s] 電力 [W] 性能比 性能比/W
GTX 1080 Ti 19.51 240 1.0 1.0
Alveo U200 222.95 73 11.4 37.5
最終ベンチマーク結果
一秒間に2230億個の乱数生成… エクストリーム感
まとめ
● パフォーマンスを引き出すには
○ FPGAのことを少しは知っていた方がいい
○ ツールがインプリしやすいハードウェアを書く
○ HLSツールと対話しお気持ちを理解
● FPGAの敷居が低くなった!
○ C++でハードとアプリを書くだけ
○ Vitisライブラリも出たし
○ 盛り上がるといいな
○ AWS F1ならすぐに試せます!是非!

FPGAでベンチマークしたときに苦労した話@fpgax#12