最新のプロセッサ能力を発揮するマルチコアアプリケーションをプログラミングするためには、いくつかの注意点を考慮する必要があります。このドキュメントは、逐次タスクの実行中にパイプライン処理によってマルチコアCPUのパフォーマンス向上を図る方法について説明します。
マルチコアプロセッシングとマルチスレッドアプリケーションを開発するには、最新のCPU能力を最大限に引き出す方法を常に考える必要があります。従来のテキストベース言語では、並列化コードのプログラミングと視覚化が困難でしたが、NI LabVIEWのようなグラフィカル開発環境を使用することで、短い開発期間で新しいアイデアを実装することができます。
NI LabVIEWはデータフローに基づいているため本質的に並列的であるため、マルチスレッドアプリケーションのプログラミングを非常に簡単に行えます。ブロックダイアグラム上の独立したタスクは、プログラムが特別な作業を行わなくても自動的に並列実行されます。独立していないタスク(コード)の場合はどうでしょうか。逐次処理的なアプリケーションを実装する際に、マルチコアCPUの能力を活かすためにはどうしたらよいでしょうか。
逐次ソフトウェアタスクのパフォーマンスを向上させる手法の1つとして、パイプライン処理がよく使用されます。パイプライン処理とは、簡単に言えば、逐次タスクを組み立てラインのように個々の段階に分割することです。
たとえば、自動車を組み立てラインで製造しているとします。最終タスクは完成した自動車を組み立てることですが、これを「フレームの組み立て」、「エンジンなど内部部品の取り付け」、「塗装」という3つの段階に分割します。
フレームの組み立て、部品の取り付け、塗装の各段階にはそれぞれ1時間かかると仮定します。したがって、1つの自動車を組み立てるために、3時間必要となることになります(図1参照)。
図1. この非パイプラインの例では自動車の組み立てに3時間必要です。
このプロセスはどのように改善できるでしょうか。各工程を別々に設置すると、1つの自動車が塗装されている間に、別の自動車に部品が取り付けられ、さらに別の自動車のフレームの組み立てを行うことができます。
新しいプロセスでは、1つ1つの自動車を仕上げるためには同じく3時間かかりますが、3時間に1台ではなく1時間に1台分の自動車を完成させることができ、スループットが3倍に向上します。この例では、パイプライン処理の概念を簡略化して説明していますが、「重要な注意点」のセクションにはさらに詳細な説明が記述されています。
[+] 画像を拡大
図2. パイプライン処理によるアプリケーションのスループット改善
上記の自動車の例で示したパイプライン処理の概念は、逐次タスクを実行するLabVIEWアプリケーションにも適用可能です。LabVIEWのシフトレジスタとフィードバックノードを使用して、各プログラムの「アセンブリライン」を形成することができます。以下の図は、複数のCPUコアで実行されるパイプライン処理アプリケーションの例を表しています。
図3. 複数のCPUコアで実行されるパイプライン処理を使用したアプリケーションのタイミング図
パイプライン処理を使用して実際にマルチコアアプリケーションを作成する際には、いくつかの重要な注意点を考慮する必要があります。たとえば、パイプライン処理によってパフォーマンスを向上させるためには、パイプラインステージの負荷を調整し、コア間でのメモリ転送を最低限に抑える必要があります。
上記の自動車製造とLabVIEWの例では、各パイプラインステージの実行に同じ長さの時間がかかると仮定していました。すなわち、これらのパイプラインステージは「負荷調整」されているとみなすことができます。しかし、実世界のアプリケーションでは、このようなケースは稀にしか見られません。以下の図では、ステージ1の実行にステージ2の3倍の長さの時間が掛かる場合、2つのステージをパイプライン化してもパフォーマンスはほとんど向上しません。
非パイプライン処理(全体の時間 = 4秒):
パイプライン処理(全体の時間 = 3秒):
メモ: パフォーマンス向上 = 1.33倍(パイプライン処理の効果が発揮されない)
この場合、ステージ1のいくつかのタスクをステージ2に移行して、両方のステージの実行時間がほぼ同じになるようにする必要があります。ただし、パイプラインステージの数が多い場合は、この作業が難しい可能性があります。
LabVIEWでは、各パイプラインのベンチマークによって負荷調整の度合いを確認することができます。これは、図4で示すようにフラットシーケンスストラクチャと「ティックカウント(ms)」関数を組み合わせて簡単に行うことができます。
図4. パイプラインステージのベンチマークによるパイプライン処理の負荷調整確認
パイプライン処理間では、大容量のデータの転送を出来る限り行わないことが望まれます。各パイプラインのステージは異なるプロセッサコアで実行されている可能性が高いため、ステージ間でデータを転送すると物理プロセッサコア間でのメモリ転送が必要となる恐れがあります。2つのプロセッサコアがキャッシュを共有しない場合またはメモリ転送サイズがキャッシュサイズを超える場合、アプリケーションのエンドユーザが得るパイプラインの効果が下がります。
パイプライン処理は、マルチコアマシンでの逐次処理アプリケーションのパフォーマンスを改善するための手法です。CPUの各チップのコア数が増加する傾向にある現在では、アプリケーション開発にパイプライン処理などの手法を取り入れることが重要です。
パイプライン処理によってパフォーマンスを最大限に高めるためには、各ステージの実行時間がほぼ同じになるよう負荷を慎重に調整する必要があります。また、パイプラインステージ間でのデータ転送を最低限に抑えて、複数のコアからのメモリアクセスによるパフォーマンスの低下を防止する必要があります。