MN-Coreを素人考察してみる (original) (raw)

はじめに

先般 MN-Ccore Challenge なるものが開催され、私もスキマ時間に気分転換的にちょこちょこ挑戦していたのですが(本業関係者への言い訳)、とても面白いアーキテクチャだなと思いました(順位はまあその力及ばず微妙な感じでしたが)。

普段 FPGAプログラミングが多い私ですが、いろいろ新しい観点で脳に刺激を頂きました。

今更私なんかが考察する余地もない気はしますが、折角なのでプログラミングではなく、プロセッサアーキの方を少しだけ感想程度に記録しておければと思います。

いろいろ資料も公式に公開されていますし、コンテストも終わったようなので(実は終了日を勘違いしていました)、安心してあれこれと自分用の勉強の教材にして楽しませて頂きたいなと思います。

なお、ほんとに素人考察なので、あんまりマサカリは投げないでおいてあげてください(言い訳)。

どんな構成なのか

最初に「ソフトウェア開発者マニュアル(SDM)」を読んでみて、書き起こしたのが下記の図です。

SDMを読んで最初に書いた図

私が適当に書いたので間違ってるかもしれませんが、とりあえず、階層構造というか、ピラミッド構造というか、そういう風になっているようです。階層ごとにメモリがあり上下の階層に対していろいろな転送(場合によっては縮約演算も)がPEの演算と並行して指示出来るようです。

このとき同じく階層構造をもつものとしてとして思い出したのが PEZY Computing さんの PEZY-SC2 などの資料で見た構造です。

一方で、最近の AI系のコアだと、Versal の AI コアでもある AMDXDNAであったり、 Tenstorrent の Whormhole / Blackhole であったり フラットな二次元メッシュ構造をよく見るような気がするので、それぞれにどういうメリットデメリットがあるのかは興味深いところです。

MN-Core はというべきか、 MN-Core もと言うべきか、キャッシュメモリが存在しないアーキテクチャなので、階層間での明示的データ転送が一つの大きな肝になってくるのでは無いかと思いました。

階層があるかどうかで、お隣さんなど他のノードとの距離とデータ交換コストの重みに違いがあるわけなので、このあたりの向き不向きが適用するアプリによってありそうな気がしなくもありません。

レジスタファイルではなくメモリ

次に肝心な計算ユニットであるPEですが、公式の図に私が勝手に赤字で落書きさせて頂いたのが下記ですが、なんとプロセッサなのにいわゆるレジスタファイル(汎用レジスタ)がなさそうです。シングルポートのメモリや、書き込み専用と読み込み専用のデュアルポートになっているメモリなど、比較的シンプルなメモリが演算器にそのまま繋がっています(つまり普通のCPUだとL1キャッシュに相当するメモリ階層がダイレクトに演算器に繋がっているとも解釈できそうです)。

レジスタファイルではなくメモリ

これはFPGAプログラマ的には凄くいいなと思いました。以前こんな記事こんな記事を書きましたが、FPGAの大敵である大量ポートのレジスタファイルなどは不要で、FPGAにあるBlockRAM でも同じような構成は低コストで再現できそうです。おそらくLSIにおいてもトランジスタ効率の良い実装なのでは無いでしょうか?

ではなぜこんなことが出来るのかと考えてみると、4サイクルを1ステップとする命令体系 にあるような気がします。普通は1つの命令で4データ処理すると言われると、4並列のSIMDを想像してしまいますが、MN-Core では1命令を4サイクルで実行します。

以前私がバレルプロセッサを作った際にこんな記事を書きましたが、同じように依存関係のないデータが並んでいれば、ハザードを起こさずにパイプラインを深くすることが出来るはずです(SIMDで並列実行できるようなデータ同士には演算順序の依存関係はないので)。そうすると多少レイテンシのかかるメモリや演算器であっても汎用レジスタのように利用可能になってくるようです。

プログラマSIMD命令に慣れている ことを逆手にとって、**SIMDっぽい命令体系を直列実行してパイプラインハザードを回避している** と捉えるとすごく面白い気がします(注:個人の感想です)。

また、4サイクルで1ステップと言いつつ、アドレスだけは4サイクル分個別に投入できる命令体系です。これはもう命令ストリームではなく、アドレスストリームとも言えるのでは無いでしょうか?FPGAプログラミングでいろんなところでSRAMへのアドレスジェネレータが重要になることがあるので、感覚的にはアドレスだけ命令密度が高いのもしっくりくるところがあったりもします。 まとまった単位で扱わないと性能の出ないDRAMに比べて、ランダムアクセスが得意なのがSRAMなので、ローカルSRAMにデータを持ってきた後はそこをフルランダムアクセスしてプログラムから使えるのはある意味でデバイス特性をフルに引き出していると言えるのかもしれません。

対して ALUなどの演算種別の切り替えは 4サイクルに一回で十分 という割り切りも、毎サイクルどころか1サイクルに異種の命令を何個も並列発行する現在のアオウトオブオーダーのスーパースカラプロセッサに隠れた無駄を指摘しているアンチテーゼにも思えます。

B/F(Byte per FLOP)など帯域の観点でも、ALUやMAUに対するL1メモリのデータ供給能力は十二分に見えます。ここも L1メモリ(通常はキャッシュ)からの帯域をレジスタファイルで補っている一般的なアウトオブオーダーのスーパースカラプロセッサと大きく違うところだと感じました。

乗算器について

特にAIなどで重要になる演算のうちトランジスタリソース消費の多いのが乗算と思われますが、MN-Core では ALU や 縮約転送 に乗算は無いようですので、基本的にハードマクロ乗算器は MAU に集まっていることになるようです。そして 倍精度、単精度、疑似単精度、半精度 をそれぞれ小さくなるほど一度に大量に演算できる仕組みがうまく構築できているように感じました。B/F の関係で大量の演算ほどメモリ帯域が必要となるため、半精度のみ2長語転送ができたりして、ここがコンテストで高得点を出す肝の1つにもなったりもしていたようでした。 (乗算は精度倍にするのにリソース2倍以上消費してしまうので、帯域と精度のバランス調整が難しそうですが、とてもうまく収まってるようです)

何れにせよ非常に柔軟に構成変更できる乗算器が、フォワーディング($mauf)すれば次の演算に使えているのでレイテンシ4サイクルで計算できているわけで、さすがと言ったところです(FPGAだとこうはいかない)。またこの柔軟性のおかげで倍精度の必要な Top500/Green500 でも高い評価を出しつつ、半精度で十分なケースもあるAIにも柔軟に対応できているのかなと思います。

ちなみに行列演算を見てみると、1命令でMAU 1つにつき倍精度だと 32MAC、単精度で128MAC、疑似単精度で 256MAC、半精度で 1024MAC となるようです。 AVX-2 などの SIMD だと、倍精度を単精度にしても2倍にしかなりませんが、ちゃんとデータ幅が半分になる毎に 4 倍、16倍と乗算器トランジスタリソースのオーダーで演算量が増えています。 これは、「倍精度の時は2つの命令に分けて演算する(dmmulu+dmfmad)」、「半精度の時は2長語転送ができる」などの工夫で成立しているようです。

ちなみに一番小さい乗算である半精度で仮数部9bit ですので、最低でも INT8 以上の精度を持つ事になり、FPGA などが得意とする、INT8以下に強く量子化されたネットワーク(極論するとバイナリネットワーク)のようなものの推論に関しては(学習は別)スコープ外なのかと思いますので、FPGAも住み分けて生き残れそうでちょっと安心したりもしました。

どこをプログラミングしているのか?

通常のCPUであれば 「ALU に何をさせるか」をプログラミングさせるかと思います。一方で、MN-Core ではどうやら、ニモニックこそそれっぽく見せかけているものの(人に優しい)、その実体(機械語)はマルチプレクサのスイッチをプログラムする仕組みになっているようです。なのでALUなどの出力を一度に複数の種類のメモリに書き込んだり出来てしまいます。

マルチプレクサの切り替えをプログラム

そしてこれらは決して巨大マルチプレクサではなく、一個一個はそれこそFPGAに持ってきても許容できる程度のコンパクトなものになっています(注:FPGAはマルチプレクサ苦手なものが多いです)。そしてこれらもまた4サイクルに一回切り替えられれば十分という、従来の固定観念を見直させてくれるなかなか興味深い構成となっているように思いました。

マルチプレクサの切り替えは データ経路のプログラミング に他ならないので、その点はHailoとか、ルネサスさんのDRPなどに通じる部分もひょっとするとあるのかもしれません。

FPGAプログラミングとの違い

それでもやはり汎用計算機の宿命なのかなと思ったのが、PE内で ALU なり MAU なりで演算されたデータはまた元のところに戻ってきてぐるぐる回りながら演算する構成であるところでしょうか。フォワーディングレジスタのおかげでかなり面白いデータ流が作れそうですが、やはりサイクル内ではMABに閉じた流れにはなりそうに思いました。

私が画像処理の経験が多かったせいかもしれませんが、FPGAプログラミングではALUのような多目的な演算器ではなく固定の演算を並べて配置する事が多いので、データはある演算器で計算したら次の演算器に渡されるといった、パイプラインを構成する事が多いように思います。もちろんそれはFPGAはASIC化されてないFPGAのままだから出来るプログラミングではあるのですが、やはり少し毛色の違いは感じてしまいました。

AVX-262144 というネタも飛び出しておりましたが、全部のPEが同時に全部同じことをする という並列プログラミングの宿命なのかもしれません(それで FizzBuzz も解けてしまうのだから驚きなのですが)。

おわりに

LSI上に存在するトランジスタリソースを如何に高密度に演算に割り当てるか?」という問題と「如何に汎用性を持たせるか?」という2つの相反する問題に、それぞれ何らかの尺度の中で限界まで挑んでいるのが昨今のプロセッサかと思います。

そんな中でかなり演算性能に重みを振って理論限界に迫っているプロセッサの一つが MN-Core なのかとは思います。限界に近づくほどにいろんな特徴が見えくるのは感じました。

FPGA大好き人間の私にも、随所で参考になりそうなものはいろいろありましたので、今後のFPGAプログラミングの参考にさせて頂きたいなと思った次第です。

余談ですが、きっとPFNさんの中では試作段階でFPGAでの評価とかもされてるのではないかと想像しますが、FPGAにも優しい設計になっていそうな気はしました。

あと、今回のチャレンジで上位スコアを取るような方々が特定の問題を解くためのFPGAプログラミングなんかしたらとんでもなく凄いコードが出てくるんだろうなと、凄い人たちの凄さを改めて体感した次第でした。

(追記:コンテストでは私はあまり触らなかったので理解できてないのがメモリ帯域や容量配置などなのバランスなのですが、機会があればそれらも調べて身みたい気がします。)

追記

本ブログ記事、牧野先生ご本人から X で取り上げて頂いておりました。感謝申し上げます。 下記に連なる書き込みで、コンパイラの最適化を容易にするための意図であったり、2004年の論文のご紹介などを頂いており、大変勉強になりました。 🙇‍♂️

会議資料から逃避中なので https://t.co/33YevIWyaq MN-Coreを素人考察してみるを。いや素人じゃないよねというか基本的にそうですみたいな。

— Jun Makino (@jun_makino) 2024年9月25日

さらに追記

なんと、30位だったにも関わらず、抽選で Par賞 を頂きました!! 有難うございます! 最後の Inversion がインチキ解法だったのでちょっと心苦しいのですが、ここは有難くPCのメモリ増設に充てさせていただきます。