ヘテロジニアスとメニーコアのプログラミング・モデル
Yonghong Yan, Barbara M. Chapman, Michael Wong

HPCコミュニティーは、エクサスケール時代に向かい、かつてないレベルの複雑さと大きさを実現するように期待されている。将来のアプリケーション性能を最大にする挑戦は、ノード内の全ての資源を使うノード内実行効率に依存していると、コミュニティーは同意している。これらのノードは、複数のコヒーレンシ領域内にある多くの同一計算コアから成ることもあれば、制約があるものの効率が良い専用のコアを含む異質(ヘテロジニアス)なものから成ることもある。一般的に、ヘテロジニアスとマルチコアのプロセッサーの両方が一般的になると期待されている。ノードそれぞれの中で物理的に共有されるメモリーを期待するが、アクセス速度は、コアの内部かコアにまたがるか、メモリーの種類、より深いメモリー階層、そして性能最適化にとって挑戦的なNUMA (Non Uniform Memory Access) によって、大きく異なる。現在のアクセラレーターによって示されるように、ノード内のメモリーは異なるアドレス空間を持ち、明示的なデータ移動が必要である。
大規模な並列計算機資源を利用するための重大な課題は、システム・ソフトウェア・スタックによって効率的な実装を可能にしながら、ノード内のハードウェア資源の全てを利用するために、必要とされる並列性のレベルの実現を促進するような、プログラミング・モデルの提供である。ノード・レベルの並列モデルには、CPUとSMPのための、pthreads、C++11 threads、Boost thread libraryのようなスレッド・プリミティブ、NVIDIA専用のCUDAやオープン・スタンダードOpenCLのような、アクセラレーター用の低水準のもの、高水準でディレクティブに基づくOpenMPとGPUアクセラレーターのサポートから始まったOpenACC、Windows上でのC++開発環境であるMicrosoft Visual C++による並列プログラミング、他には、Cilkplus、TBB、vectorプリミティブのような選択肢がある。
プログラミング・モデルは、アプリケーションとハードウェア・アーキテクチュアの間に位置する。言語の機能は、特定のハードウェア機能を仮想化する必要があるか、あるいは、アプリケーションが使用するアルゴリズムや並列処理パターンの表現を簡素化する。言語機能とインターフェースのデザインは、抽象化の詳細に同意する必要がある。この記事では、最近と将来の、ヘテロジニアスとメニーコア・アーキテクチュアをサポートするための並列プログラミング・モデルの機能の包括的なリストをまとめる。次に、これらの機能に対するプログラミング・モデルを比較する。背景と関連を追加するために、私たちの同僚である Michael Wolfe氏の記事が参考になる。その記事は、並列プログラミングの概念と様々な並列化階層をこことここに論じている。
機能
機能とその分類の一覧は、Vivek Sarkar氏が率いるライス大学の Habanero Extreme Scale Software Research Projectの実行モデルを参考にしている。
並列処理:このモデルでは、並列アーキテクチュアに容易に対応させられ、並列アルゴリズムの表現を可能にするような、異なる種類の並列処理を、利用者が選べるべきである。少なくとも4種類の並列処理機構を比較する必要がある。(1) データ並列、例えば並列ループの入れ子は、それぞれのデータ並列粒度に応じて、メニーコア・アクセラレーターまたはベクトル・アーキテクチュアに、典型的に対応する。(2) 非同期タスク並列は、不規則あるいは再帰的な並列アルゴリズムのような、ある種の並列アルゴリズムを容易に表現できる。(3) データ/イベント駆動計算は、制御フローよりもデータの流れに特徴付けられる。(4) ホストとデバイスによる並列処理は、コプロセッサーとオフロード・モデルに依存し、最近のアクセラレーターによるアーキテクチュアと能力に対応し、ホストのみで並列処理をサポートするモデルとアクセラレーターによる並列処理があるモデルを区別する。
アーキテクチュアの抽象化とデータ、演算のバインディング:ccNUMA (訳注:cache coheret non uniform memory access、複数のコアメモリーを共有し、自動的にキャッシュの整合性が保証されているが、近くのメモリーと遠くのメモリーのアクセス速度が異なる) メカニズムの共有メモリーを持つマシン上で並列アプリケーションの最適化は困難である。システムによって異なる、キャッシュ・コヒーレンシの影響、すなわち偽共有(false sharing、訳注:隣接するメモリー・アドレスに複数のスレッドが書き込み、性能が低下する現象)とNUMAの複雑さによって、アプリケーションの性能は影響を受ける。最近の複雑なメモリー階層を持ち、異なるアドレス空間を持つかもしれないアーキテクチュアにおいては、問題はさらに挑戦的になる。プログラミング・モデルが問題の解決を助けるためには、(1) アーキテクチュア抽象化、例えば、性能にとって重要な部分においてNUMAメモリーの「explicit」表記、(2) データ局所性 (locality) を有利に扱うために、ユーザーが計算とデータの結合を制御できるような文法、(3) 異なる場所とアドレス空間にあって共有されているデータの明示的なマッピングと移動がある。
同期:プログラミング・モデルは、例えばbarrier、reduction、join操作のような、並列スレッドあるいはタスクの間の並列性を調整する機能を持ち、並列処理においてパイプラインあるいはワークフローを実現するため、あるいは、ストリーミング計算のためのフェーズに基づく同期のために、1対1通信とwait操作を持っている。
排他制御:ロックやミューテックスなどのインターフェイスは、今でもデータ・アクセスを保護するために使われている。モデルは、並列計算に必要な排他的データ・アクセスを容易に可能にできるような、言語機能を持つべきである。そして、デッドロックが発生しにくいように、mutual exclusionのセマンティクスを定義できるべきである。transactional memoryのようなアーキテクチュアの変更は、並列モデルのインターフェーイスの一部分として、同様のデータ保護を実現するための代替手段を用意すべきである。
その他の機能:エラー処理、ツールのサポート、複数の言語とライブラリーのバインディングは、並列プログラミングのための重要な機能である。エラー処理は、ユーザー・プログラム、システム、アプリケーションが、システムの問題から回復しやすくするための、サポートを提供する。ツール、例えばデバッガーとパフォーマンス・プロファイラーは、並列プログラムの開発とチューニングの生産性向上に不可欠である。HPCにおいて、C/C++およびFortranは、依然として広く使われている。関数型言語は、同時実行におけるクリーナーの抽象化を提供できるが、既存のプログラムとライブラリーの書き換えは容易でない。理想的には、モデルは、少なくとも、C/C++/Fortranをサポートすべきである。
HPCのノード・レベルプログラミングについて、これらの機能を比較するために、我々は、次の商用実装を使った。OpenMP、Intel Cilkplus、Intel TBB、OpenACC、Nvidia CUDA、OpenCL、C++11、pthreadsである。pthreadsとC++11は、マルチ・スレッディングのサポートを拡張しているので、我々が高水準言語機能と比較するための、言語とライブラリーの基準となった。CUDA (Nvidia GPU専用) とOpenCLは、メニーコア・アクセラレーターのための低水準言語として、高水準インターフェースをコンパイラーが変換するための、比較基準とした。OpenACCは、メニーコア・アクセラレーターをディレクティブ・ベースで使うための、標準として、新しい試みである。Intel TBBとCilkplusは、タスク・ベースのプログラミング・モデルであり、共有メモリーのマルチコア・スステム用で、商用とオープンソースの両方の実装がある。OpenMPは、産業界、学界、政府機関において、広く使われている標準であり、多くのハードウェアをサポートし、商用とオープンソースの両方の実装があり、現存の科学コードが使っている。
比較
図1と図2に比較を示す。並列処理をサポートするためには、すべてのモデルにおいて、非同期タスク動作あるいはスレッド動作が、基礎であり続け、OpenMP worksharingのようなデータ並列処理が、非同期タスク動作とjoin同期の基盤として使われることもある。全てに渡って、OpenMPは、ホストとデバイスの両方の上で、様々な並列パターンとアーキテクチュアの広範囲なセットをサポートできる。しかし、他のモデルでは、ホストあるいはデバイスのどちらかだけの並列処理をサポートする。NVIDIA GPUのようなアクセラレーターについて、OpenACCとCUDAは、並列処理パターンをサポートする言語構文を持っている。アーキテクチュアの抽象化については、OpenMPだけがメモリー・モデル階層(as places)とデータに計算をバインディングする(proc_bind clause) 構文を持っている。どのプログラミング・モデルも、メニーコア・アーキテクチュアをサポートし、それぞれの方法で1000を超えるスレッドの組織化と階層化をできる。例えば、OpenMPのスレッド「team」、OpenACCの「gang/worker/vector」構文、CUDAの「block/thread」、OpenCLの「work group」である。デバイスとオフロードをサポートするモデルは、別々のメモリー空間の間でデータを移動を指定する構文を持っているが、その他のモデルには必要ない。
図1:ヘテロジニアスとメニーコアのプログラミング・モデルの比較 — 並列化パターン、アーキテクチュア抽象化、データと計算のバインディング
図2では、異なる分類によって機能を比較している。3種類の一般的な同期操作、つまり、バリアー、リダクション、ジョイン操作である。OpenMPだけが、全てをサポートしている。CilkとIntel TBBは、スレッドよりもタスクを強調しているので、スレッド・バリアーの概念がなく、ここでの比較に含めなくても問題ない。ロックとミューテックスは、ここでも排他的動作を提供するために広く使われている。多くのモデルはCとC++を対象としているが、OpenMPとOpenACCはFortranも対象としている。ほとんどのモデルは、エラー処理と多くのC++例外をこの目的のためにサポートしていない。一つの例外はOpenMPであり、「cancel」構文によって新しいエラー処理モデルをサポートしている。ツールのサポートに注目すれば、Cilkplus、CUDA、OpenMPは専用ツールのインターフェイスとソフトウェアを提供する実装である。多くの「host only」モデルでは、Linux perfのようなシステムに標準で備わっているツールを使うようになっている。いくつかの場合においては、OpenMPプログラムを分析するために、ベンダーあるいはサード・バーティー製のツールがある。
図2:ヘテロジニアスおよびメニーコアプログラミングモデルの比較 – 同期、排他制御、言語バインディング、エラー処理とツールのサポート
結論
ここまでの比較によると、OpenMPは明らかにほとんどの機能の包括的なセットをサポートしている。OpenMPは、今では、アクセラレーター、通常の共有メモリーSMP、NUMA、マルチコア、新しいヘテロジニアスとメニーコアに対応して、急速に進化してきた。OpenMPアーキテクチアReview Boardの新たなミッション・ステートメントは、「高水準の複数の言語に対するディレクティブに基づく標準、即ち、性能、生産性、移植性」であり、HPCワークロードを超えて並列処理を導くことを明らかにしている。デバイスに依存するユニークなディレクティブ・ベースのアプローチ、つまりOpenACCも、ソースコードを新しい言語で書き直す必要がないので、アプリケーションの移行と移植作業を大幅に減らすことが可能なプログラミング・モデルである。OpenMPは、単一の言語を使って、ホスト、ノードの両方の複数のCPU、コプロセッサーをサポートできる。
仕様について、業界標準であっても正式な標準であっても、並列プログラミングのインターフェイスを定義でき、品質が良い実装があるもののみが使われる。OpenMPやOpenACCのような高水準プログラミング・モデルについては、実現している。ライブラリ・ベースのTBBとpthreadsについて、OpenCL、CUDA、Cilkplusのように既存の言語の拡張については、まだ小さな課題がある。本稿の執筆時に最新である、OpenACC標準バージョン2.0には、NVIDIA GPUアーキテクチュアに対して、PGIとCrayによる商用実装がある。最新のOpenMP標準は、GNUコンパイラー、Oracle Solaris Studio、Intel Parallel Studioに、部分的実験的に実装されている。Clang/LLVMコンパイラーにOpenMPを完全に実装する努力が続き、標準に近づいている。Pathscaleも、OpenACCとOpenMPの両方の最新版をサポートしようと、精力的に働いている。
特定のアプリケーションとハードウェア・アーキテクチュアに対して並列プログラミング・モデルを選ぶことは、実装によって得られる性能だけでなく、プログラミングの労力と移植性にも依存する。例えば、GPGPUアクセラレーターは、高水準のプログラム・インターフェースを持ち、ノード・レベルの並列プログラミングに使えるが、OpenACCとOpenMPの選択肢がある。OpenACCは、より早い時期に開発が始まり、複数のコンパイラーによるサポートがある。しかし、高水準プログラミング・モデルによって得られる性能よりも、より高い性能を求めて、生産性の低下にもかかわらず、NVIDIA専用言語であるCUDAを選ぶユーザーもいる。このように、複数のプログラミング・モデルの存在は、それぞれがユーザーやアプリケーションの特定の必要に応える独自の機能セットを持ち、生産性と性能のトレードオフは、依然として必要である。
著者について
訳注:本記事で言及されているDr. Michael Wolf氏の記事の日本語訳は、ここにある。