Chiharu の日記

絵描き C/C++ プログラマーの日記です。

並列処理いろいろ

HPC の素人が並列処理を調べてます。ロードバランサーやアプリケーションインスタンスを複数起動する的なフロントエンドではなく、ネイティブコードで SIMD・スレッド並列・プロセス並列・GPGPU・MIC・クラスターにより並列処理するバックエンドの方です。

x86 プラットフォームを前提に、それぞれの実現方法をまとめます。

SIMD

単一スレッドで、CPU コアに含まれる SIMD 機能(SSEx, AVXx)によりデータを並列処理する方法です。

  • コンパイラーは VC, GCC, ICC なんでもよい。
  • コンパイラーに自動ベクタライズ機能はあるが、ほとんど効果がない。かろうじて ICC が単純ループの float 計算をそれなりに SIMD 化してくれる。
  • イントリンシックで SIMD プログラミングするのが良い。ハンドアセンブルでも実現できるが、コンパイラー間の移植性を考慮するとイントリンシックが望ましい。ただし、イントリンシックは C/C++ の文法でコンパイルされるため、下記の制約がある点に注意が必要である。
    • 命令のスケジューリングはコンパイラーの最適化に依存する。
    • SIMD 自動変数を多用すると、SIMD レジスターが不足して、変数がスタックに退避されることがある。そして、スタックのアライメントを保証してくれないライブラリーのコールバック中にスタック退避すると、アライメント違反が発生して CPU 例外になることがある…。

SIMD は、このほかの並列化手法と併用可能です。また、イントリンシックは難しくはありません。SoA / AoS 変換や直列演算 / 並列演算がパズルみたいで面白いです :-D CPU 例外はむかつきますけれど。

スレッド並列

単一プロセスで、複数スレッドにより並列処理する方法です。

  • コンパイラーは VC, GCC, ICC なんでもよい。
  • OpenMP, TBB, PPL を使うとスレッド並列が簡単に表現できる。
  • 複雑なシーケンスを並列化する場合は、普通にスレッドプログラミングする。

OpenMP は、スレッドプールに処理を適宜アタッチするような、器用なことをやってくれるんでしょうかね。parallel for のたびにスレッド生成・破棄してたら遅いですよね…。という懸念もあって、以前に実装した Parallel force では、普通にスレッドプログラミングしました。プロデューサー・コンシューマー・パターンは偉大です :-D

プロセス並列

複数プロセスにより並列処理する方法です。

  • コンパイラーは VC, GCC, ICC なんでもよい。
  • MPI でプロセス間通信すると簡単に表現できる。
  • 複雑なシーケンスを並列化する場合は、普通にプロセス間通信をプログラミングする。

後述のクラスターと透過性を持たせる場合は、MPI によるプロセス並列が選択肢に入ると思います。また、コードがスレッドセーフでない場合も、プロセス並列を選択することになると思います。そうでなければ、スレッド並列までで良い気がします。

GPGPU

PCIe 接続された GPU により並列処理する方法です。
CUDA, OpenCL, DirectCompute, C++ AMP など、ベンダーや用途によって方法が乱立しています。詳細は、リンク先の記事が参考になります。

実績を考慮すると、nVIDIAGPU を使用した CUDA が安全かな、と思います。IBM の POWER9 に nVLink 2.0 が実装されるという話もありましたし、GPGPU のメインストリームだと思います。

MIC

PCIe 接続された Xeon Phi により並列処理する方法です。

  • コンパイラーは ICC を使う。デバッガーを考慮すると Intel Parallel Studio XE がいいのかもしれない。
  • ICCXeon Phi 用コードをコンパイルして、実行バイナリーを Xeon Phi に転送して起動する。普通にヘテロジニアス的に並列処理する。
  • Offload ディレクティブを含むコードを ICCコンパイルして実行すると、Xeon Phi に動的に処理を分散する。

Xeon Phi がホスト環境になる構成もあるようですが、ここでは言及しません。情報を漁っていると、実行環境はアクセラレーターやペリフェラルというより、別のコンピューターと通信する雰囲気です。一度は使ってみたいですねぇ :-D

クラスタ

ネットワーク接続された異なる計算ノードにより並列処理する方法です。

  • コンパイラーは VC, GCC, ICC なんでもよい。
  • MPI でノード間通信すると簡単に表現できる。
  • 複雑なシーケンスを並列化する場合は、普通にソケットプログラミングする。いばらの道かも。

ここまで大掛かりな構成を使ったことはありませんが、ビッグデータを取り扱う場合は必要になる構成でしょうね。

並列処理の開発ツール

使用する開発ツールは下記を基準に考えれば良さそうです。

  • 自動ベクタライズを活用したい場合は、Intel Parallel Studio (Intel C++ Compiler) を使う。
  • Xeon Phi で並列処理したい場合は、Intel Parallel Studio (Intel C++ Compiler) を使う。
  • 処理時間を可視化したい場合は、Intel Parallel Studio (VTune) を使う。
  • CUDA で並列処理したい場合は、NVIDIA CUDA Compiler を使う。
  • SIMD・スレッド並列・プロセス並列・クラスターで並列処理したい場合は、VC, GCC, ICC など任意のコンパイラーを使う。
  • プロセス並列やクラスターで並列処理したい場合は、MPI を使うと簡単である。実装には Microsoft MPI, Open MPI, Intel MPI Library などがある。

――以上、HPC の素人がいろいろ調べてみました。あとは何をネタに並列処理で遊ぶか、ですね :-D