Cell
出典: CellFanWiki
Cellはソニー・コンピュータエンタテインメント、IBM、東芝によって開発されたプロセッサの通称である。当然、このWikiのターゲット。
Cellは非対称性のマルチコア構造を持っているなど、非常に個性的なデザインのプロセッサなので、それにあわせたプログラミングをすることが非常に重要。
このページでは、性能に影響を与えるCellの機能と、そこから導き出される効率的なプログラムの書き方をメモしておく。
目次 |
[編集] 辞書的なこと、歴史的なこと、政治的なこと
Cellの辞書的な定義などはWikipedia(日l)(米)などを参照。
以下は、とりあえず知っておいたほうが良い周辺事情。
Cellという用語自体は通称で、PS3に使用されているチップの正式名称は Cell Broadband Engine (略される場合は、Cell B.E. ?)。
また、チップの仕様としては Cell Broadband Engine Architecture (略称はCBEA)という名前で公開されているが、こちらはあくまでアーキテクチャレベルの仕様書であるため、両者を区別しておいたほうが良い。たとえば、仕様ではCBEAの要件として以下を要求している。
- 最低1個以上の PowerPC Processor Element (PPE)
- 最低1個以上の Synergistic Processor Element (SPE)
- 内部割込みコントローラ (IIC: Internal Interrupt Controller)
- エレメント接続バス (EIB: Element Interconnect Bus)
つまり、CBEAの仕様上は SPEが8個である必要はない。また、仕様上でオプションとして記述されている要素や、実装依存であると書かれている機能も多いので、CBEAの仕様書を読む際にはCell B.E.の実機では少し違うかもしれないということを常に頭の片隅に置いておく必要がある。
(この項は気付き次第追加)
[編集] Cellの構成
米Wikipediaに非常に判りやすい写真(IBMの広報資料)が掲載されている。シリコンの比率などが良くわかるので、まずそちらを見ておくことを薦める。
下図は、その写真をもとにした、Cellの物理構成図。
以下では、Cellの主な構成要素について解説する。
[編集] PowerPC Processor Element (PPE)
64bit の PowerPC Processor Unit + 付属キャッシュ。 普通のPowerPCの仕様である PowerPC Architecture, Book I-III に準拠することと、ベクトルマルチメディア拡張ユニット(つまりAltiVec)を備えることが仕様上要求されている。
LinuxなどのOSや、Cell用の特別な拡張が加えられていないアプリケーションは基本的にこのPPE上でだけ動く。
詳細はPPEのページにて。
[編集] Synergistic Processor Element (SPE)
OSの行うようなシステム管理機能を持たないシンプルなプロセッサ。単一命令/複数データ(SIMD)演算能力がある。データ演算に特化した新規デザインの命令セットを持つ。
構成要素としては、Synergistic Processor Unit (SPU)、メモリフロー・コントローラ(MFC: Memory Flow Controller)、ローカルストレージ・エリア(LS: Local storage) を含む。
詳細はSPEのページにて。
[編集] メモリフロー・コントローラ(MFC: Memory Flow Controller)
データ転送エンジン。 SPE内部にあるメインストレージとローカルストレージ間のデータ転送などを主に担う。
詳細はPPEのページにて。
[編集] 内部割込みコントローラ (IIC: Internal Interrupt Controller)
[編集] エレメント接続バス (EIB: Element Interconnect Bus)
[編集] 性能を引き出すためのTips
この節では、上記のハードウェアの構成から導き出される、Cellの性能を引き出すためのTipsについてまとめる。 ただし、PPEやSPEに閉じた性能向上のTipsはそれぞれPPE,SPEのページに記し、ここでは、それ以外の要素、つまり、Cellのシステム全体の性能向上に寄与するTipsをここに記す。
[編集] 極力SPEを使うべし
物理的なサイズの比率でもわかるとおり、Cellのチップの大部分はSPEで占められている。つまり、SPEはそれだけ優遇されており、SPEを使わないとCellの性能は全く引き出せないと言ってよい。
また、PPEとSPEは全く別個のコアなので、完全に独立動作できる。そのため、例えばPPEで処理していた仕事の一部を、遊んでいたSPEに振り分けるようにすれば、PPEは振り分けた仕事の処理時間ぶんだけ丸儲けになる。PPEはメモリやデバイスなどのリソース管理はもとより、SPEを使わない全てのプログラムが動いているので、PPEのCPU時間は高価だと考えるべきである。たとえSPEがあまり得意としない処理で、PPEで処理するよりも遅くなってしまうような処理であっても、SPEを遊ばせるぐらいなら、SPEにさせたほうが全体としては高速になる可能性がある。
[編集] 他人の邪魔はするな
これはマルチコアCPU一般に言えることだが、複数のコアが1つの同じ仕事を分割して処理している場合、所々で同期を取る必要が出てくる。この「同期」とはつまり「相手を待つ」ということであり、待っている間はCPUは完全に遊んでいる。当然ながら、そのような事態は極力さけるべきである。特に、SPEではコンテキストスイッチが非常に高コストなため(詳細はSPEのページ)、一般的なCPUのように、待っている間は別のプログラムを走らせる、ということが難しい。
それでは、この「待ち」はどうすれば減らせるだろうか。
まず、ひとつの仕事を複数のSPEに分割する場合を考えると、各SPEでは極力独立性が高い仕事、できれば全く依存関係の無い処理をしている形が理想である。依存関係が排除できない場合でも、同期をとる回数を極力減らし、少しでも長い間、誰にも邪魔されず一心不乱にSPEが走り続けられるよう設計すべきである。
一方、SPEとPPEの関係に関しては、本質的にどうしても同期が必要になる。というのも、データの入出力は常にPPEで行われるからである。逆に言えば、それ以外の同期は必ずしも必要では無いかもしれない、と常に考えるべきである。例えば、PPEがデータを多数に分割しSPEに仕事を割り振るプログラムの場合、SPEプログラムが1単位の仕事が終わったと報告してきてから、PPEプログラムが次の仕事をSPEに投げるような設計にしてはならない。そのように設計すると、SPEは1つの仕事が終わるたびにPPE待ちに入ることになり、無駄が生じてしまう。この場合、もし可能であれば、あらかじめデータ分割した情報をメインメモリにおいておけば良い。そうすれば、SPEはPPEと同期をとらずとも、メインメモリに直接アクセスして次の仕事を取得できるため、SPEは待ち無しで走り抜けることができる。(全てのデータをあらかじめ分割することが出来なくても、せめて「次の1件のデータ」だけでもメモリに書いておくことが出来ればSPEが待たされることはない。)
以上を一言でまとめると、プログラム設計の肝は、ともかく「他人に依存するな。他人を待つな、待たせるな。」ということになる。
(以下、執筆中)

