金曜日, 1月 18, 2013

マルチプロセッサとメモリアクセス

近年、ノートPCや携帯機器までマルチコアが普通に載るようになってきて、今ではスマートフォンにまでクアッドコア(4CPU)が登場するようになりました。だったらもっと載せればいいじゃないという話になりそうですが、実際はそう簡単にはいきません。

世の中のプログラムは必ずしも並列化できない(アムダールの法則)というのもありますが、もし並列化できたとしても、メモリアクセスの限界(フォン・ノイマン・ボトルネック)で、どうしても性能が抑えられてしまいます。CPUが計算するためには、まずメモリからプログラムとデータを読んで、計算結果をメモリに書き込む必要があります。CPUだけがどんなに速くても、メモリアクセスが間に合わなければ、全く意味がないわけです。

では、現在のマルチプロセッサはどのようにしてこの問題に対処しているのでしょうか?

cache_memory.png

現在、世の中に出回っている大部分のマルチコアプロセッサが、基本的にはこのような分散キャッシュメモリを持つ構成になります。この構成では各プロセッサは必要となるプログラムやデータの一部分をキャッシュメモリにコピーして使うので、共有メモリへのアクセスは格段に減ります。マルチコアプロセッサでは通常、キャッシュメモリと共有バスは外部の共有メモリよりも遥かに高速で動作しますので、ちゃんとプロセッサが増えただけの性能を発揮することができます。

キャッシュメモリの容量はプロセッサの性能に直結するので、今やプロセッサの中で最も電力と面積を必要とする部品となっています。キャッシュメモリは元々、外部メモリとプロセッサ内部の速度差を埋める役割を果たしていたのですが、マルチコアになるとキャッシュ一貫性によりメモリの同時アクセスのために欠かせない機構となりました。でも、メモリを内蔵する構成のプロセッサにおいては、当然ながら無用の長物です。

では、メモリを内蔵する小規模なマルチプロセッサは、どのような構成にすればよいでしょうか? まず考えられるのは、力技です。

shared_memory.png

マルチポートメモリを利用することにより、共有メモリとプロセッサを直結することが理論的には可能です。ですが、面積効率が悪く(ポート数の2乗に比例するといわれている)、またFPGAでは利用できないため(大抵は2ポートまで)、この方式は却下となります。

もう一つ考えられるのは共有メモリを諦めてプロセッサ毎に専用のメモリを持たせ、代わりに通信用のバスを用意する方式です。ハードウェアの設計が楽なのでこの構成は比較的よく見られ、例えばPS3Cellプロセッサはこれに近い構造となっています。

local_memory.png

これはハードウェア設計は楽なのですが、ソフトウェアの方は大変です。特に小規模の場合、ただでさえ少ないメインメモリが、プロセッサ毎に分割されてしまうのは論外といえます。無理やり他のプロセッサのメモリをアクセスする構成も考えられなくはないですが、プロセッサに負荷が掛かる分、複雑な割に効率が悪そうです。

共有メモリの分割をプロセッサ毎ではなく、アドレス領域に応じたメモリバンク分割にすることにより、また違った構成が考えられます。

crossbar_switch.png

クロスバースイッチにより、複数のプロセッサが別々のメモリバンクにアクセスする限りにおいて、同時アクセスが可能となります。ただし、複数のプロセッサが同一のバンクにアクセスしようとした場合には、一つを除いて他のアクセスがブロックされます。プロセッサが増えるとクロスバー機構が急激に肥大化するのが問題ですが、それをうまく簡略化するための研究が昔から盛んなようです。(例えばこことか)

もしここで、アドレスをプロセッサ数で割った余りでメモリバンク分割すると、面白いことが起きます。例えば上の図でメモリバンク0~3を、アドレスを4で割った余りが0から3の領域のメモリとします。もしある時点で4つのプロセッサの実行アドレスが100, 201, 302, 403とすると、それぞれ4で割った余りは0, 1, 2, 3となるので同時に別々のメモリから命令読み出しアクセスができます。次の時点では実行アドレスが101, 202, 303, 404となるので余りは1, 2, 3, 0となり、また同時アクセスが可能です。こうして、ジャンプ命令を実行しない限り、4つのプロセッサは同時アクセス可能な状態を維持し続けます。

この状況で、プロセッサ自体を回転させることができれば、クロスバー機構がまったく要らなくなります。回転といってもIC内部で物理的に回転させるわけにはいかないので、実際には全ての内部状態を信号としてつないで転送することになります。

cyclic_smp.png

プロセッサの内部状態というと、当然全てのレジスタの値も含まれますので、レジスタがたくさんある場合にはそれも全部隣に送らないといけません。つまりこの場合、レジスタが少なければ少ないほど有利なわけです。

ここで、レジスタレスアーキテクチャによる小規模マルチプロセッサの可能性が浮かび上がってきます。

(つづく)