Ryuz's tech blog

FPGAなどの技術ブログ

非ノイマン型について再考してみる

はじめに

なんとなくお散歩中に考えていたことを先ほどとめどなく X にツイートしていたのですが、少しまとめておきたく、久々にブログに書いておこうと思います。

私が今Xの固定ツイートにしている下記のデモ試作のアーキテクチャを題材に、非ノイマン型についての話が少し書ければと思います。

www.youtube.com

以前に書いたこちらのブログ記事とも関連してきます。

今のアーキテクチャノイマン型の比較

FPGAでの実装をタイミングチャートでみる

今回の題材の実際のFPGAへの実装と、大雑把な時系列での処理は下記のようになります。

FPGAでの実装

使っている IMX219 イメージセンサの MIPI-CSI は 1,824 Mbps で RAW10 を読みだすので、182.4MHz 以上で毎サイクル1ピクセルずつを演算できるだけのスループットを持てば処理できます。 したがってデータの帯域としては今のFPGAとしては驚くほどのものではありません。DDR4-SDRAMの帯域などと比べてもはるかに小さな帯域となります。

この帯域でバケツリレー的にパイプライン処理を行っています。

イメージセンサからは左上のピクセルから順次走査で右下の最終ピクセルまで1フレーム時間をかけて出力が行われますが、それらの画素データは外部メモリに溜めることなくダイレクトに各種演算ロジックに入力され、随時演算されていきます。

各演算では、各ピクセルの計算に必要な画素が揃った段階で逐次演算して出力していきます。ただし、現像処理であったり、CNN(畳み込みニューラルネットワーク)であったり、前後のラインのピクセルが必要な処理に関してはBRAMなどをラインバッファとして少し溜め込んでから利用することになりますので、その分の最低限のライン時間の遅延は追加されていきます。

データ的に依存関係があると、データが揃うまで演算できませんのでメモリに溜めざるを得ないのですが、

  • 必要最低限のデータしかメモリには溜めない
  • レイテンシを最小化しつつスループットは1サイクル1ピクセルを保つ

というポリシーで実装していますし、アルゴリズムもなるべくデータを溜めなくてよいような工夫を行って構築しています。

以前に、「メモリとはデータを未来に転送するデバイス」だと比喩したことがありますが、メモリに溜めるのはそのまま遅延となるので、省メモリはそのままリアルタイム性や応答性の改善にもなります。

もしもCPU/GPUで実装したら

さてこここで上記の処理を、もし CPUとかGPGPUとかで処理しようとするとどうなるか と言う話です。

恐らく下図のようになるかとおもいます。

CPU/GPUで実装した場合の想像

CPUもGPUノイマン型であり、ロード/ストアアーキテクチャですので、基本的にはメモリに入っているデータに対して処理を行うのが基本です。これらの計算時間はデータ依存でキャッシュヒット率なども変わってきますし、外部メモリ上のデータ配置やリフレッシュなどの影響もうけるので、少なくとも1フレーム時間内に処理が終わるように、最悪実行時間(WCET)を保証する形でマージンを持ってプログラムを書くことになります。

この時、多くのケースでは、イメージセンサからの1フレーム分の画像データがメモリに入りきってから演算を開始し、演算結果もメモリ上に作成し、演算が終わったら表示処理に回すという逐次的な処理を行うかと思います。

画像データのような大きなデータはしばしキャッシュを溢れますので、外部の DDR4-SDRAM などのメモリを何度も往復することになります。イメージセンサやディスプレイのデータ帯域の何倍ものデータ帯域がメモリに必要となります。

また、演算側のスループットを維持するのも簡単ではありません。

182.4M ピクセル/秒 で入ってくる画像を処理するには 5GHz のプロセッサでも1画素につき27命令しか使えません。さすがにそれでは必要な処理は出来ませんので CPU の SIMD(Single Instruction Multiple Data) 命令とか、GPGPU の SIMT(Single Instruction Multiple Thread) の機能を使って大量の並列演算を行って演算力を確保する必要があります。

SIMDもSIMT も 1命令のデコードで多くのデータを処理することで、ノイマンボトルネックを打ち破ろうとする素晴らしい仕組みですが、一方で「同時に同じ演算を並列に実行する」事しかできないため、そこにメモリからデータを供給するのが大変だったりもします。

以前、こちらこんなプレゼンをしました。

一斉に起こる Load/Store に堪えるバス幅が少なくとも L1 キャッシュに求められてきますし、先に述べたように最終段の DDR4-SDRAM にもデータを何往復もさせる帯域が必要となります。

したがって、どうしてもメモリ周りが高コストになりがちで、FPGAではそもそも外部メモリすら不要な実装が出来ているのとは対照的です。

また、CPU/GPUなどの処理では、通常1フレームの画素数よりも演算器の数はずっと少ない事が通常ですので、不足分は同じ処理を繰り返しループすることで処理を行います。 これはループの中で同じ命令のデコードを何度も繰り返すことになります。この点もFPGAでの実装に比べて電力観点で不利になっている可能性があります。

まとめ

今回の例は特に FPGA が有利になる事例ではあるのですが

  • FPGAなら高々カメラデータの帯域で良いものが、CPU/GPUだと広帯域のメモリシステムが無いと成立しない(より高価なチップが必要)
  • FPGAなら即座に出力できリアルタイム性が高まるものが、CPU/GPUだと大きな遅延となる

などの差が出てきています。

これはノイマンボトルネックの一つの事例とも言えるのではないかと思います。

FPGAでのRTLプログラミングはノイマン型にとらわれずにプログラミングが出来ます。

今回のような事例ではカメラの読み出しと同時に計算を行いますので、CPUやGPUでメモリにデータがキャプチャし終わってから演算しようとすると、その時にはFPGAはもう出力も終えているというような事もあり得ます。これはCPUやGPUをいくら速くしてもリアルタイム性の観点観点では永遠にFPGAに勝てないという事例になりうるのでとても面白いです。

CPU/GPUに向けたアルゴリズムだけではなく、FPGAで性能を出すアルゴリズムを考えてみるのもなかなか楽しいですよと言うのがご紹介できればと思った次第です。