本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

Cell Broadband Engine プロセッサの能力を最大限発揮する: アプリケーションのパフォーマンスを引き出すための 25 個のヒント集

Daniel A. Brokenshire, Senior Technical Staff Member, IBM STI Design Center
Daniel A. Brokenshire は IBM STI デザインセンター (テキサス州オースチン) のシニアテクニカルスタッフメンバーです。彼は Cell/B.E. プロセッサのためのプログラミング標準、言語拡張、および再利用可能なソフトウェアライブラリの開発責任者でもあります。コンピュータサイエンスの学士号、電気工学の学士号と修士号をオレゴン州立大学で取得しています。Cell/B.E. プロセッサに取り組む前には、Tektronix と IBM の両社で 3 次元グラフィックス製品の開発に携わっていました。

概要: 従来のプロセッサと異なり、Cell Broadband Engine(Cell/B.E.)プロセッサでは実アプリケーションにおいて理論ピークに近い性能を引き出すことが可能です。そのためにはCell/B.E.プロセッサアーキテクチャの特徴を理解していなければなりません。アプリケーションのパフォーマンスを最適化するために、本記事で紹介する25のヒントを通じてCell/B.E.プロセッサアーキテクチャの特徴に対する理解を深めましょう。

日付:  2006年 6月 27日
レベル:  中級 この記事の原文:  英語
アクティビティー: 10371 ビュー
お気軽にご意見・ご感想をお寄せください: 


Cell/B.E.アーキテクチャは、64bit Power-compliant Processing Element(PPE)と8つのSynergistic Processing Elements(SPEs)から構成され、メモリサブシステムを通して疎結合されています。プログラマビリティを通して、SPEはASICs以上の柔軟性を提供しつつも従来のプロセッサを超える計算能力を提供します。SPEの命令セットやサポートされるデータタイプはネットワーク処理、暗号処理、ハイパフォーマンスコンピューティング(HPC)、画像幾何学処理、データ変換といった幅広く多様なアプリケーションにとって効率的なコンピュータ計算結果をもたらします。

従来のプロセッサと異なり、Cell Broadband Engineプロセッサでは実アプリケーションにおいて理論ピークに近い性能を引き出すことが可能です。しかしながら最適な性能を引き出すためには、プログラマもしくはコード生成ツール、場合によってはその両方がプロセッサアーキテクチャの特徴を理解していなければなりません。非対称な演算ユニット、SIMD演算処理エンジン、限られたローカルストア、ソフトウェアマネージドキャッシュ、メモリアクセスレイテンシ、デュアルイシュー規則、大きく幅広いレジスタファイル、4ワードメモリアクセス、分岐予測、同期機能といったものがアーキテクチャの特徴に含まれます。


図 1. The architecture of the Cell BE processor

本記事では汎用プロセッサに対し大幅なパフォーマンス改善を達成するといったCell/B.E.プロセッサアーキテクチャの特徴を活用するためのソフトウェアの戦略およびテクニックを提供します。処理性能結果の例は、本記事で提示した技術の有効性を立証したものです。

本記事では最適なアプリケーション性能を引き出すための25のプログラミングヒント集を提供します。ヒント1-3ではCell/B.E.プログラミング全般の実践情報を、ヒント4-6ではPPEに特化した実践情報を、ヒント7-14では効率的なメモリサブシステムに関する実践情報を、ヒント15-25ではSPEに特化したプログラミングの実践情報を提供します。

Cell/B.E.システム実践

ヒント1: できるだけ多くの仕事をSPEにオフロードすること

Cell/B.E.プロセッサには1つのPPEと8つのSPEが備わっています。例えSPEに不向きな演算(例えば分岐の多いスカラー演算)であったとしてもオフロードした方が良い可能性があります。PPEは制御用プロセッサとして使用しましょう。すなわちSPEの実行を調整したり、仮想メモリマネジメント(VMM)ミスといった例外イベントを補助したりするためにPPEを使用しましょう。そしてSPEは全ての重い演算処理を実行するデータプレーンプロセッサとして使用しましょう。

ヒント2: アトミック処理と同期イベントを最小化するような分割および仕事割り当ての戦略を選択すること

自律的、非同期的なコンピューティングはスループットを最大化する上で非常に重要です。一つの取りえる戦略として、仕事をアルゴリズム的に分割してSPEに割り振ることが挙げられます。例えば、スキャンラインがn個のSPEによって処理されるような画像処理アプリケーションを考えてみましょう。各SPEは、以下の簡単な方程式を解くことによって、アルゴリズム的に割り当てられた仕事を計算することができます。

height = CEIL(image_height / n);
first_line = height * spe_num
last_line = MIN(image_height, first_line+height)-1

あるいはまた、制御プロセッサが仕事要求を仕事キューもしくは仕事キューの集合に入れることも可能です。もし仕事要求が計算上可変かつ予測不可能であれば、SPEはアトミック処理を使うことによって一つのキューから仕事を取得するといった自己調停が可能となります。タスクが持続時間内で予測可能であるときには、制御プロセッサが各SPEに対して別々のキューに対して仕事要求を配信することが可能です。

全ての領域で問題を分割するように熟考して下さい。例えば多くのアプリケーションは空間と時間の両面で分割することが可能です。

ヒント3: 潜在するデータ型の違いに適応すること

PPEとSPEでは同一サイズのデータ型を使用することができないことがあります。PPEのデータモデルはILP32(integer型、long型、ポインタが全て32bit)もしくはLP64(integer型が32bit、long型およびポインタが64bit)のどちらか一方となります。SPEは常にILP32です。そのため64ビットアプリケーションでは互換性のある型やデータアラインメントを保護するためにも、PPEとSPEがアクセスする共有データ型を作成する際には、気をつけなければなりません。

PPEは単精度と倍精度演算の両方に最適化されています。しかしながら最初のCell/B.E.の実装は単精度浮動小数点結果を計算する際に著しく効果的になっています。毎サイクル4Way SIMD 単精度浮動小数点の積和演算は、6サイクルのレイテンシ(結果が入手可能)で命令発行されます。対照的に、2Way SIMD 倍精度浮動小数点の積和演算は、7サイクル毎に命令発行され、レイテンシは13サイクルになります。そのため倍精度演算が必要でなければ、単精度演算を用いるようにしましょう。

(訳注: PowerXCell 8iでは倍精度浮動小数点演算性能がおよそ5倍向上しています)


PPEプログラミング実践

ヒント4: マルチスレッドを活用すること

PPEは2スレッド同時実行可能であり、2つのスレッドのarchitectural stateが保持されています。しかしながらハードウェア実装コストを削減するために多くの実行リソースがスレッド間で共有されているため、スレッド間は完全に独立しているわけではありません。そのため次のときにマルチスレッド化が強く推奨されます:

  1. スレッドが重大なL1およびL2キャッシュミスに遭遇するような場合。これは一般にアプリケーション内でたくさんのポインタ追跡や分散された配列/ベクタへのアクセスが行われた場合に発生します。
  2. スレッドは十分にパイプライン化されていない固定小数点もしくは浮動小数点演算を含んでいるような場合。演算の間に依存関係が存在するとき(例えばある演算の入力がそれ以前の演算に依存する場合)実行ストールが発生します。

ヒント5: 自己管理キャッシュ

予測可能なデータアクセスパターンを持つアプリケーションであれば、必要なときにデータが利用可能であるようにキャッシュにプリロードすることで、ここで紹介する知識を活用することが可能です。

PPEは古典的なもの(th=0)と拡張されたもの(th=8)の2つの形式のdcbt(data cache block touch)命令をサポートしています。古典的な形式は一つのキャッシュラインをメモリからL1およびL2へとプリフェッチします。拡張されたものはページメモリからL2へとプリフェッチします。

VMXデータストリーム命令(dst、dstst、およびdststt)はCell/B.E.プロセッサでは何の効果もなく、キャッシュにプリロードするために使われるべきではないということに注意して下さい。

ヒント6: マイクロコードかされたオペコードを避けること

プログラマは、PPEマシンタイプによるコンパイルをサポートするコンパイラを使用することによってマイクロコード化されたインストラクションオペコードを避けなければならない。マイクロコード化されたオペコードがハードウェアスレッドのどちらか一方でも遭遇すれば、両方のスレッドがストールしてしまいます。

PPEのマイクロコード化されたオペコードは以下のものを含みます:

  • CRレコーディング命令 (Rc=1)
  • シフト量をレジスタで指定されるようなシフトおよびローテート命令 (即値で指定されるのとは対照的に)
  • 符号拡張ロード/ストア命令、異種ロード/ストア命令、ストリングロード/ストア命令
  • 32byte境界を跨いだデータキャッシュアクセスや倍精度浮動少数の奇数ワード境界へのロード/ストアを含むミスアラインアクセス

メモリサブシステムプログラミング実践

ヒント7: プログラママネージドデータ転送を有効活用すること

Cell/B.E.アーキテクチャはローカルストアに入出力される全てのデータ転送を手動で開始するようSPEプログラマに推奨している。これはプログラマに全てのデータアクセスを意識させ、アプリケーションのデータアクセスパターンに関して考えることを推奨しているのである。

一例として、GSPx2005にてA. Chowにより発表された (「参考文献」参照) 大きなFFTを考えてみましょう。この分かりやすいFFTの実装は、FFTを実行するために24回のデータ変換を必要とします。このような実装はメモリ依存になります。メモリアクセスを減らすために、Chowは8個のバタフライステージが同時に進行するというStockhamのself-sortingをベースに、D. H. Baileyが提供したstride-by-1アルゴリズムの変形を活用しました。メモリアクセスパターンを理解し補正することで、データ変換の回数を3回に減らすことができました。

ヒント8: 効果的なデータアクセスのためにデータ構造を設計すること

効率の良いSPEのデータアクセスを成し遂げるために、プログラマーはデータアラインメント、アクセスパターン、ロケーションのことを考慮しなければなりません。

SPEのMemory Flow Controller(MFC)は1、2、4、8、そして16byteの倍数(最大16k)のデータ転送をサポートします。16byte以下のデータ転送は自然にアラインされていなければならず、またquad-wordオフセットが送り側と受け取り側のアドレスで一致していなければなりません。

転送が最低でも128byteの場合にElement Interconnect Bus(EIB)のオーバーヘッドが最小になり、128byte以上の転送はキャッシュラインにアライン(128byteに整列)されていなければなりません。

PPEが大きなデータセットにアクセスしようとすることを避けましょう。何故ならSPEが起動するデータ転送の多くはシステムメモリからローカルストアへのもので、PPEのL2キャッシュからのものではないからです。MFCによるシステムメモリからの転送は高いバンド幅と中程度なレイテンシとなりますが、それに反してL2キャッシュからの転送は中程度なバンド幅と低いレイテンシとなってしまいます。

ヒント9: SPEからDMAを開始すること

SPEのプロキシコマンドキューを使って、PPEがSPEにデータを渡すようにする代わりに、SPEからDMAを開始することでSPEがデータを受け取るようにしましょう。これには以下のような理由が挙げられます。

  1. Cell/B.E.にはPPEの8倍ものSPEが存在します。
  2. SPEコマンドキューは、プロキシコマンドキューよりも2倍深いです。
  3. 使用する側で管理されたデータ転送の方が同期するのが簡単です。
  4. SPEから転送開始することに要するサイクル数の方が、PPEから同じ転送を行うよりも少ないです。

ヒント10: スラッシングをさけるためにロックすること

Cell/B.E.プロセッサのReplacement Management Table(RMT)機能を使って、L2キャッシュのアドレス範囲をロックすることを考えましょう。これによりしばしばアクセスされるデータバッファがキャストアウトされることを許し、そしてストリームデータが他のキャッシュ上のデータによりキャストアウトされないようにします。

ヒント11: ページテーブルとTLBスラッシングを減らすために大きなデータセットは大きなページから確保すること

Cell/B.E.プロセッサは3種類の共存するページサイズ -- 4KBと64KB、1MB、16KBの内の2つ -- をサポートしています。大きなデータセットを大きなページから確保することは、しばしば起こるTLBリロードのペナルティを減らします。TLBスラッシングは非常に重要です。例えば、16M-point FFTのサンプルがIBM Cell Broadband Engine Software Development Kit((SDK; 「参考文献」参照) で提供されていますが、このプログラムは4KBのページからデータバッファが確保されている場合と比較して、16MBのページから確保した場合には3倍高速に動作します。

ヒント12: 同期変数を自らのリザベーションブロックに保持すること

アトミック処理は128byteキャッシュラインに相当するリザベーションブロックを引き起こします。結果として、他のアトミックでないロード/ストア命令が不意なロストリザベーションを引き起こさないためにも、同期変数は自身のキャッシュラインに置かれるべきです。

ヒント13: メモリバンクへのアクセスを一様に割り当てること

Cell/B.E.のメモリサブシステムは16のメモリバンクから構成され、キャッシュライン境界にインターリーブされます。2KB離れたアドレスは同じメモリバンクにアクセスします。システムメモリのスループットは全てのメモリバンクが一様にアクセスされれば最大になります。

16M-point FFT (「参考文献」参照) の初期実装では2つ(実部と虚部)の16M要素の浮動小数点配列を16MBのページ境界に配置していました。8つのSPEは通常2のべき乗のアドレスへとアクセスするため、16個のメモリバンクの内半分の8個のみが同時にアクセスされていました。実装がメモリと密に結合していたため、メモリバンクアクセスの割り当てを改善することが性能を改善するためには要求されました。解決策は、16個全てのメモリバンクが同時にアクセスされるために虚部の配列を1K(8個のメモリバンク)に分けることでした。この単純な変更によって25%もの性能改善がみられました。

ヒント14: チップ内にとどまること

EIBはシステムメモリよりもさらに高いバンド幅を提供します。多くのアプリケーションはメモリに依存しており、それ故データ転送、通信、同期をチップ上で保つことができ、メモリのバンド幅を浪費しないという恩恵が受けられます。これはSPE間でデータ共有する際にローカルストア間のDMA転送を活用することや、Mailboxを利用すること、小さなデータ通信や同期処理のためにシグナル通知レジスタを利用することを含んでいます。


SPEプログラミング実践

ヒント15: 外部のスカラーを避けること

SPEはローカルストア上のquad-wordにのみ一度にアクセスします。そのためスカラー(subquad-word)のロード/ストアはいくつかの依存した命令を必要とします。これはスカラーのロードがプリファードスロットのベクター要素に変換され、スカラーのストアが読み込み、スカラーの挿入、書き込み命令を要するという事実に基づくためです。以下に示すサンプルコードは、今説明したオーバーヘッドを示すためのものです。



いくつかの戦略は、スカラーコード(ベクター化に適さないコード)をより効率的にします。これらは以下のものを含みます。

  • スカラーをquad-wordのベクターに変換すること。これは一見無駄なことのように思えますが、スカラーのロード/ストアのために要する余計な3命令のことを加味すると、実際にはコードサイズにとって肯定的な影響を及ぼすことが可能です。
  • スカラーをグループにまとめ、quad-wordのメモリアクセスを利用して一度に複数のスカラーをロードすること。必要に応じてスカラーを手動で抽出もしくは挿入します。これによって余計なロードとストアを削除することになるでしょう。

RC4(256byteの動的状態テーブルを活用したキャラクタベースの暗号化アルゴリズム)の実装を考えてみて下さい。何故ならば、アルゴリズムの各反復は以前の反復に依存しており、並列化できないように思えるためです。しかしながら上記で述べた戦略を活用することで、かなりの性能向上を達成することができます。まず256byteの状態テーブルを16個の要素が全てunsigned charで同じ値を持つベクターで構成される256のquad-word状態テーブルに展開します。入力と出力のメッセージは余計なロード、ストア、およびそれぞれのレイテンシを排除するためにquad-wordで一度にフェッチおよびストアされます。この変更が86%もの性能改善という結果をもたらしました。

ヒント16: SIMDを活用すること

プログラマが高級言語(例えばCやC++)でコードを書くとき、プログラマはSPEのSIMD演算能力を活用するためにコードを自動的にベクタ化するといったコンパイラ技術に頼らなければなりません。しかしながら、これらの高級言語が持つ柔軟性は多くのアプリケーションで最適な性能を達成することを非常に困難にしています。これはプログラマが望む結果を達成するためには、パフォーマンスクリティカルな部分でアセンブリ言語を使うことに頼らなければならないという結果をもたらしています。SPE上で動作するアセンブリを書くことは、巨大なレジスタファイルや独特な命令発行規則によりコードが肥大化し複雑になってしまうため、非常にやっかいな仕事です。

そこで中間的なソリューションとして提供されているのが組み込み関数です。組み込み関数は本質的にはC言語の関数呼び出し構文を持つインラインアセンブリです。組み込み関数はプログラマに使用する命令群を明示的に指定する方法を提供します。しかし(アセンブリとは違い)コンパイラが得意としている最適化タスクの多くを失ってしまいます。これらはregister coloring、命令スケジューリング、データのロード/ストア、ループと分岐、そしてリテラルベクタ構成などを含んでいます。

ヒント17: 命令セットと発行規則を理解すること

組み込み関数を用いてコーディングする際には、命令セットを理解しなくてはなりません。これは以下に示すような理解を含んでいます。

  1. どのように組み込み関数が命令にマッピングされているか
  2. 余分なリテラル構成を避けるための即値の動的範囲と符号
  3. 効率的な条件文を作り出す分岐命令
  4. どのようにベクタリテラルが構成されているか

同様に重要なこととして、プログラマは命令発行規則とレイテンシを理解しなくてはなりません。SPEは2つの命令パイプラインを持っており、各命令は事前にどちらかのパイプラインで実行されかが割り当てられています。つまり2つの命令が以下の想定の基に毎クロック発行されます。

  • いかなる依存関係も存在しない
  • オペランドは使用可能である
  • 偶数アドレス命令(最下位の3アドレスbitが000)はパイプライン0で実行される命令である
  • 奇数アドレス命令(最下位の3アドレスbitが100)はパイプライン1で実行される命令である
  • 命令はパイプライン0から発行され、続いてパイプライン1へと発行される

それ故、命令を賢く選択することによって、デュアルイシューレートを改善することができます。


表 1. Instructions for the even pipeline
Pipeline 0 (even) Instructions Latency (clocks)
Single precision floating-point ops6
Double precision floating-point ops6+7
Integer multiplies
Integer/float convert
Interpolate estimate
7
Immediate loads
Logical ops
Integer add/subtract
Sign extend
Count leading zero
Select bits
Carry/borrow generate
2
Element rotates and shifts
Special bytes operations
4

表 2. Instructions for the odd pipeline
Pipeline 1 (odd) Instructions Latency (clocks)
Loads and stores
Branch hints
Channel operations
Moves to/from SPRs
6
Shuffle bytes
Quad-word rotates and shifts
Estimate (reciprocal, reciprocal sqrt)
Gather bits
Form select mask
Generate insertion control
Branches
4

ヒント18: 最適なSIMD戦略を選ぶこと

アルゴリズムをSIMD化する方法はいくつかあります。選ばれた方法は、アルゴリズム、データ構成、ローカルストア容量にとって妥当でなければなりません。

一例として、図 2のように浮動小数の頂点a、b、cで定義される単一の三角形が複数の三角形に再分割されるという細分化曲面を考えてみましょう。


図 2. Point subdivision illustrated

このアルゴリズムをベクタ化する方法がいくつかあります。それらは以下のものを含んでいます。

  1. 同時に再分割された頂点を評価する
    この方法は再分割を行う上で、伝統的なスカラ手段です。頂点は一般に"vec-access"フォーマットで表現されています。(すなわち各3つもしくは4つの頂点が一つのSIMDベクタで扱われます。)この3次元の頂点を表現する方法は非常に自然な発想であり、しばしば小さなコードを生成します。しなしながら、この方法を適用した場合、あまり効率の良いコードは生成されず、また性能を向上するために多くのループ除去作業を必要とします。もし頂点がベクタが保持できる(例えば3つの頂点成分)よりも少ない成分を含んでいるような場合、より一層効率に対する妥協が必要になります。
  2. 同時に4つの独立した三角形の再分割された頂点を評価する
    コードをSIMD化する簡単な方法の一つは、スカラでプログラムされたものを独立したデータとしてベクタに移植するというものです。頂点のデータは各頂点成分が異なる配列に保持されるという"parallel-array"フォーマットで表現されます。もし入力がvec-accrossフォーマットであれば、spu_shuffle組み込み関数を使うことで、parallel-arrayフォーマットに変換することができます。
  3. 同時に1つの三角形から4つに再分割された頂点を評価する
    このケースでは、四つの再分割された頂点が並列演算可能なように頂点制御データはベクタを跨いで複製され独自の重み付け要因が各ベクタの要素に保持されます。再分割された頂点の数が4の倍数でないとき結果は無効なものとなります。上記3つのSIMD化戦略はCurved Point-Normal triangle subdivision (「参考文献」参照) にそれぞれ適用することができます。以下の測定結果は、性能、コードサイズ、そしてそれぞれのテクニックによる効果を比較するために抽出されたものです。データは最適な解決策は2の戦略であることを示しています。

表 3. Performance of various SIMD-conversion strategies
Metric Strategy
1 2 3
Unroll factornone24nonenone
Normalized perf1.01.261.541.701.34
CPI1.101.040.900.990.96
Dual issue %9.112.618.513.611.9
Dependency stall %14.113.65.84.72.6
Registers used72112127113107
Text size (bytes)1472249644805121856

ヒント19: ループを取り除きパイプライン化すること

ループはほとんど全てのプログラム(特にストリームアプリケーション)にとって基礎となるものです。しかし、もしループの反復回数が定数であれば、完全にループを取り除くことを考慮してみて下さい。もしループの反復回数が変数であれば、ループが比較的独立(すなわちループの反復が以前の反復に依存していないということ)している間はループを取り除くようにしてみて下さい。SPEは大きなレジスタファイルを持っているため、重要なループ除去はレジスタ溢れが発生する前に達成することができるでしょう。レジスタ溢れはある瞬間に有効な変数の数がレジスタファイルのサイズを超過した場合に発生します。ループを除去することは、オプティマイザにとって効率の良いスケジューリングが可能な命令を新たに提供することにもなります。

ループを取り除くときには、新たなローカル変数が"false dependencies"を回避するためにループ変数内で必要となる。これらのfalse dependenciesの回避に失敗することは、ループが取り除かれたとしてもコンパイラによってインターリーブされないという現象を引き起こすことになってしまう。

以下のデータは、OpenGLのような座標変換および光の効果を実行したサンプルワークロードでループを取り除くことの有効性を示すものです。


表 4. Performance metrics for unrolling loops
Metric Unroll Factor
1 2 4 8
Normalized perf1.01.521.731.66
CPI1.350.910.760.67
Dual issue %3.319.834.335.8
Dependency stall %27.25.90.91.5
Registers used78103128128
Text size (bytes)768134430765252

ほとんどのループは、一般的に同じような基本構造を持っています。反復毎に入力データをロードし、演算を行い、最終的に結果をストアします。ロード、ストア、quad-wordローテート、シャッフルはパイプライン1で実行され、多くの演算命令はパイプライン0で実行されるため、データをロード/ストアするのと同時に計算してしまうことでデュアルイシューレートを改善し、ループはソフトウェアパイプライン化されます。


図 3. Pipelining and dual-issue

先に参照された頂点変換と光の効果を実行したワークロード結果にパイプライン化を適用することで、改善された結果を以下に示します。


表 5. Performance results for pipelining
Metric Unroll Factor
2 4
Normalized performance1.821.83
CPI0.750.69
Dual issue %36.747.8
Dependency stall %1.30.5
Registers used114128
Text size (bytes)24363468
Speedup vs. non-pipelined1.161.08

ヒント20: データの移動と計算をオーバーラップさせること

データアクセスのレイテンシを隠蔽するためには、ダブル(もしくはマルチ)バッファリングのテクニックを活用しましょう。コードおよびデータのサイズ、そしてデータアクセスパターンに応じて、データ(より典型的)もしくはコードをダブルバッファリングすることが可能です。


図 4. A double-buffer loop

ダブルバッファリングを行う際には、以下の原則を適用しましょう。

  • マルチバッファ毎にユニークなDMAタグIDを使用する
  • タググループに対して順番通りにDMAを発行するためにはfencedコマンドを使用する
  • キューイングされた順番通りにDMAを発行するためにはbarrierコマンドを使用する

ヒント21: 分岐を消すかもしくは減らすこと

分岐は比較的高価な代償(分岐ミスにより18-19サイクル)を要します。分岐ミスによる命令発行とストールへの代償だけでなく、分岐ミスはスケジュールの最適化にも境界を生んでしまいます。それ故、可能な限り分岐を避けるべきです。

分岐をなくすための鍵は、select bit命令を活用することにあります。例えばif-then-elseの記述では、thenとelseでの結果を両方とも求め、どちらの結果を選ぶかにselect bit命令を用いてることで分岐をなくすことができます。例えば以下の条件、

if (a > b) c += 1;
else d = a+b;

は以下のようにして分岐をなくすことができます。

  select = spu_cmpgt(a, b);
c_plus_1 = spu_add(c, 1);
a_plus_b = spu_add(a, b);
c = spu_sel(c, c_plus_1, select);
d = spu_sel(a_plus_b, d, select);

どうしても分岐を削除できないときには、分岐ミスの数を減らすように試みてみましょう。これはフィードバック最適化技術もしくはプログラマの指示による分岐予測を活用することで達成することができます。プログラマは__builtin_expect言語拡張を使用することで、明示的に分岐予測を指定することができます。上記の例で言えば、コンパイラに対して"a"は"b"以下であることが多いことを指示し、それによって以下のように__builtin_expectを加えることでelseの条件を優先するようになります。

   if (__builtin_expect((a > b), 0)) 	c += 1;
else d = a+b;

ヒント22: 整数の乗算を避けること

SPEは16x16bitの乗算器しか持っていません。それ故に32ビット整数の乗算は部分積を積み重ねるために5命令 --3つの16bit乗算と2つの加算 -- かかってしまいます。

乗算に要する余分なサイクルを避けるために、以下のルールに従いましょう。

  • オペランドが16bit以下のサイズであれば、乗算を開始する前にunsigned short型にキャストしてSPEに備わっている乗算器の恩恵を受けましょう。
  • 定数は暗黙のうちにint型ですので、キャストするようにしましょう。
  • データを検索する際に乗算を避けるためにも配列要素を2の累乗に保ちましょう。
  • キャストによる符号拡張やマスクといった意図しない動作を避けるためにも、明確に32bitの整数乗算を行うのであればマクロを使うことを考慮しましょう。

ヒント23: オフセットポインタを使用すること

d-formとは?

SPUの命令セット(PowerPCの命令セットと同様に)は多様な形式のロード/ストア命令をサポートしています。その中にはa-form、d-form、そしてx-formといったものが含まれています。それらの形式の違いはロード/ストアが行われるターゲットアドレスが構成される手段によります。a-formでは即値アドレス(言い換えればアドレスは命令の中に埋め込まれます)から構成されます。x-formでは二つのレジスタの総和から構成されます。d-formでは、レジスタの総和と即値オフセットから構成されます。

PowerPCプロセッサは更新付ロード/ストア命令をサポートしています。これらの命令は配列のポインタをインクリメントするためのさらなる命令を必要せずに、配列を通じて逐次実行することができます。

SPEは、この命令フォームをサポートしていません。その代わりに配列の基底アドレスから小さなリテラル配列オフセットを指定することで d-formを利用すべきでしょう。

ヒント24: 計算してしまうことと事前に計算された結果を使用することを比較して検討すること

何年もの間、プログラマは事前に計算された値のテーブルを開発することで、アプリケーションの性能を向上してきました。しかしSPEのプログラムにとっては、これは理想ではありません。何故ならこのようなテーブルはよくSIMD化されておらずローカルストアの容量を消費してしまうからです。そのためプログラマはSPEの非常に強力な演算能力を利用すること、つまり必要な値はその場で求めるという代替方法があることを考慮しなければなりません。

ヒント25: 256KBのローカルストアを考慮した設計をすること

SPEのローカルストアは限られたリソースです。256Kbytesがプログラム、スタック、データ、DMAバッファのために使用可能です。また本記事で紹介したたくさんの最適化技術がさらに限りあるローカルストアを圧迫することでしょう。そのため全ての最適化が実際のアプリケーションに適用可能ということにはならないこともあり、プログラマーは数少ない最適化を有効活用することに注力することになることになります。

しばしば、プラグインとして知られているコードオーバーレイを使いローカルストアに配置されるプログラムを動的に管理することでローカルストア容量に対する制約を減らすことが可能になります。


結論

Cell/B.E.プロセッサは非常に強力な処理能力の集合体です。特化したプログラミングテクニックをプログラマーが直接費やしたり、間接的にツール(特にコンパイラ)が費やすことで、アプリケーション性能に対する大きな恩恵が受けられます。この記事で紹介された戦略やテクニックを使って、Cell Broadband Engineプロセッサの潜在能力を最大限に引き出すことが可能です。

この記事で引用した作業量と性能結果を提供していただいたSTIデザインセンターのソフトウェア&パフォーマンスチームのメンバーに大変感謝致します。

参考文献

学ぶために

製品や技術を入手するために

議論するために

著者について

Daniel A. Brokenshire は IBM STI デザインセンター (テキサス州オースチン) のシニアテクニカルスタッフメンバーです。彼は Cell/B.E. プロセッサのためのプログラミング標準、言語拡張、および再利用可能なソフトウェアライブラリの開発責任者でもあります。コンピュータサイエンスの学士号、電気工学の学士号と修士号をオレゴン州立大学で取得しています。Cell/B.E. プロセッサに取り組む前には、Tektronix と IBM の両社で 3 次元グラフィックス製品の開発に携わっていました。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Multicore acceleration
ArticleID=317785
ArticleTitle=Cell Broadband Engine プロセッサの能力を最大限発揮する: アプリケーションのパフォーマンスを引き出すための 25 個のヒント集
publish-date=06272006
author1-email=brokensh@us.ibm.com
author1-email-cc=dwpower@us.ibm.com