並列処理の概要

このセクションでは、インテル(R) コンパイラーでサポートされている並列プログラミングの 3 つの主要機能について説明します。

これらの機能はそれぞれ、プロセッサー数、ターゲット・アーキテクチャー (IA-32 または Itanium(R) アーキテクチャー)、アプリケーションの性質に応じて、アプリケーションのパフォーマンスの向上を実現します。並列プログラミングのこれらの機能を組み合わせて使用し、アプリケーションのパフォーマンスを高めることができます。

並列プログラミングを明示的に行う場合は、プログラマーが OpenMP 宣言子を使用して定義します。また、暗黙的に行う場合は、コンパイラーによる自動検出を実行します。暗黙的な並列処理は、最外ループの自動並列化、または最内ループのベクトル化自動処理のいずれか (または両方) を実装します。

OpenMP と自動並列化の宣言子で定義される並列処理は、スレッドレベルの並列処理 (TLP) に基づくものです。ベクトル化の自動処理手法により定義される並列処理は、命令レベルの並列処理 (ILP) に基づきます。

インテル・コンパイラーは、IA-32、インテル EM64T、および Itanium ベースのマルチプロセッサー・システム、デュアルコア・プロセッサー・システム、およびハイパースレッディング・テクノロジー (HT テクノロジー) 対応のシステムで、OpenMP と自動並列化をサポートします。

ベクトル化の自動処理は、Pentium(R) ファミリー、MMX(R) テクノロジー Pentium プロセッサー、Pentium II プロセッサー、Pentium III プロセッサー、および Pentium 4 プロセッサーでサポートされています。ベクトル化の自動処理を使ってコードのコンパイル処理を強化するために、ベクトライザー宣言子をプログラムに追加することもできます。Itanium ベース・システムではこれに関連した手法であるソフトウェアのパイプライン化 (SWP) が利用できます。

下記の表に、インテル・コンパイラーで利用可能な並列処理の各種実装方法の概要を示します。

並列処理

説明

明示的

ユーザーによってプログラミングされる並列処理

OpenMP (スレッドレベルの並列処理)

IA-32 および Itanium アーキテクチャー

サポートするシステム

  • IA-32、インテル EM64T、Itanium ベースのマルチプロセッサー・システムおよびデュアルコア・プロセッサー

  • ハイパースレッディング・テクノロジー対応のシステム

暗黙的

コンパイラーおよびユーザー指定のヒントによって生成される並列処理

最外ループの自動並列化 (スレッドレベルの並列処理)
IA-32 および Itanium アーキテクチャー

サポートするシステム

  • IA-32、インテル EM64T、Itanium ベースのマルチプロセッサー・システムおよびデュアルコア・プロセッサー

  • ハイパースレッディング・テクノロジー対応のシステム

最内ループのベクトル化の自動処理 (命令レベルの並列処理)
IA-32 および Itanium アーキテクチャー

サポートするシステム

  • Pentium プロセッサー、MMX テクノロジー Pentium プロセッサー、Pentium II プロセッサー、Pentium III プロセッサー、Pentium 4 プロセッサー

並列プログラムの開発

OpenMP

インテル・コンパイラーは、OpenMP C/C++ バージョン 2.5 API 仕様 (OpenMP の Web サイトに掲載: http://www.openmp.org) をサポートしています。OpenMP 宣言子は、反復のパーティショニング、データの共用、スレッドのスケジューリング、および同期化に関する下位の詳細レベルを処理して、ユーザーの負担を軽減します。

自動並列化

インテル・コンパイラーの自動並列化機能は、入力プログラムのシリアルな部分を同等のマルチスレッド・コードに自動的に変換します。自動並列化機能は、次のようなループを特定します: ワークシェアリング候補である、正しい並列実行を確認するためにデータフロー解析を行う、または OpenMP 宣言子のプログラミングに必要な場合、スレッドコード生成のデータをパーティショニングする。OpenMP と自動並列化アプリケーションでは、マルチプロセッサー・システム、デュアルコア・プロセッサー・システムおよびハイパースレッディング・テクノロジー対応の IA-32 プロセッサー上の共用メモリーによるパフォーマンス・ゲインも実現します。

ベクトル化の自動処理

ベクトル化の自動処理機能は、並列で実行できるプログラム内の演算を検出し、シーケンシャル・プログラムをデータ型に応じて、2、4、8、または 16 までの要素を 1 つの演算で処理するように変換します。場合によっては、自動並列化とベクトル化を組み合わせて最良のパフォーマンスを得ることができます。

次の例では、並列化とベクトル化による利点を明示的に得るためのコードの記述方法を示します。-parallel -xP (Linux*) または /Qparallel /QxP (Windows*) を使用して下記のコードをコンパイルすると、コンパイラーは外側のループを並列化して、最内ループをベクトル化します。

#include <stdio.h>

#define ARR_SIZE 500 //Define array

int main()

{

  int matrix[ARR_SIZE][ARR_SIZE];

  int arrA[ARR_SIZE]={10};

  int arrB[ARR_SIZE]={30};

  int i, j;

  for(i=0;i<ARR_SIZE;i++)

   {

     for(j=0;j<ARR_SIZE;j++)

      {

       matrix[i][j] = arrB[i]*(arrA[i]%2+10);

      }

   }

}

正しいオプションを使用して上記の例をコンパイルすると、コンパイラーは次のような結果を表示します。

vectorization.c(18) : (col. 6) remark: LOOP WAS VECTORIZED.

vectorization.c(16) : (col. 3) remark: LOOP WAS AUTO-PARALLELIZED.

ベクトル化の自動処理は、Pentium プロセッサー、MMX テクノロジー Pentium プロセッサー、Pentium II プロセッサー、Pentium III プロセッサー、Pentium 4 プロセッサー・ベースのシステム上で動作するアプリケーションのパフォーマンスを向上します。

次の表に、ベクトル化の自動処理、自動並列化、OpenMP サポートを有効にするオプションをリストします。

ベクトル化の自動処理: IA-32 のみ

Windows

Linux

説明

/Qx

-x

{K|W|N|B|P} で指定された拡張命令をサポートするプロセッサーでのみ動作する専用コードを生成します。Mac OS* システムでは、有効な値は P のみです。

次のコンパイラー・オプションのトピックを参照してください。

/Qax

-ax

{K|W|N|B|P} で指定される拡張命令専用のコードを 1 つのバイナリー上に生成し、汎用の IA-32 コードも生成します。Mac OS システムでは、有効な値は P のみです。

通常は、汎用コードの方が実行速度が遅くなります。

次のコンパイラー・オプションのトピックを参照してください。

/Qvec-report

-vec-report

ベクトライザーの診断メッセージを制御します。詳細は、表の次のサブセクションを参照してください。

次のコンパイラー・オプションのトピックを参照してください。

自動並列化: IA-32 および Itanium アーキテクチャー

Windows

Linux

説明

/Qparallel

-parallel

自動パラレライザーを有効にして、並列で安全に実行できるループのマルチスレッド・コードを生成します。

インテル Itanium ベース・システムのみ:

  • -opt-mem-bandwith1 (Linux) または /Qopt-mem-bandwidth1 (Windows) を意味します。

次のコンパイラー・オプションのトピックを参照してください。

/Qpar-threshold[:n]

-par-threshold{n}

並列実行が効果的である可能性に基づいてループの自動並列化のしきい値を設定します (n=0 から 100)。

次のコンパイラー・オプションのトピックを参照してください。

/Qpar-report

-par-report

自動並列化の診断レベルを制御します。

次のコンパイラー・オプションのトピックを参照してください。

OpenMP: IA-32 および Itanium アーキテクチャー

Windows

Linux

説明

/Qopenmp

-openmp

OpenMP 宣言子に基づいてマルチスレッド・コードを生成する処理を、パラレライザーに許可します。

インテル Itanium ベース・システムのみ:

  • -opt-mem-bandwith1 (Linux) または /Qopt-mem-bandwidth1 (Windows) を意味します。

次のコンパイラー・オプションのトピックを参照してください。

/Qopenmp-report

-openmp-report

OpenMP パラレライザーの診断レベルを制御します。

次のコンパイラー・オプションのトピックを参照してください。

/Qopenmp-stubs

-openmp-stubs

シーケンシャル・モードで OpenMP プログラムのコンパイルを有効にします。OpenMP 宣言子は無視され、スタブ OpenMP ライブラリーがリンクされます。

次のコンパイラー・オプションのトピックを参照してください。

コマンドラインで -openmp-parallel (Linux)、/Qopenmp/Qparallel (Windows) の両方が指定されると、-parallel (Linux)、/Qparallel (Windows) オプションは、OpenMP 宣言子を含まないルーチンでのみ有効となります。OpenMP 宣言子を含むルーチンでは、-openmp (Linux)、/Qopenmp (Windows) オプションのみが適用されます。

適切なオプションを選択することには、以下のような利点があります。

さらに、OpenMP 宣言子を各自のコードに追加するだけの簡単な処理で、プログラマーはシーケンシャル・プログラムを並列プログラムに変換できます。

次の例では、コード内で OpenMP プラグマを使用する 1 つの方法を示します。

#include <stdio.h>

#define ARR_SIZE 100 //Define array

void foo(int ma[][ARR_SIZE], int mb[][ARR_SIZE], int *a, int *b, int *c);

int main()

{

  int arr_a[ARR_SIZE];

  int arr_b[ARR_SIZE];

  int arr_c[ARR_SIZE];

  int i,j;

  int matrix_a[ARR_SIZE][ARR_SIZE];

  int matrix_b[ARR_SIZE][ARR_SIZE];

  

  #pragma omp parallel for

// Initialize the arrays and matrices.

  for(i=0;i<ARR_SIZE; i++)

  {

    arr_a[i]= i;

    arr_b[i]= i;

    arr_c[i]= ARR_SIZE-i;

    for(j=0; j<ARR_SIZE;j++)

    {

       matrix_a[i][j]= j;

       matrix_b[i][j]= i;

    }

  }

  foo(matrix_a, matrix_b, arr_a, arr_b, arr_c);

}

void foo(int ma[][ARR_SIZE], int mb[][ARR_SIZE], int *a, int *b, int *c)

{                                  

  int i, num, arr_x[ARR_SIZE];

  #pragma omp parallel for private(num)

// Expresses the parallelism using the OpenMP pragma: parallel for.

// The pragma guides the compiler generating multithreaded code.

// Array arr_X, mb, b, and c are shared among threads based on OpenMP

// data sharing rules. Scalar num si specifed as private

// for each thread.

  for(i=0;i<ARR_SIZE;i++)

   {

     num = ma[b[i]][c[i]];

     arr_x[i]= mb[a[i]][num];

     printf("Values: %d\n", arr_x[i]); //prints values 0-ARR_SIZE-1

   }

}