インテル®コンパイラー OpenMP*入門
デュアルコア・マルチコア対応アプリケーション開発@
<< 10 >>
並列化コンパイルフロー
自動並列化コンパイラーでは、プログラム内でループとして形成される一連の処理における、その実行タスクとデー
タフローを解析します。 実際には、プログラム中で利用される配列や変数がループ中でどのようにアクセスされるかを
解析します。このデータアクセスのパターンにおいて、ループの実行時にそのデータ参照において競合が無い事を確
認する依存性解析を行います。データアクセスのパターン解析では、プログラム内の配列や変数が、並列化した場合
に各スレッドが「Private」として個々に利用するものであるか、「Shared」としてスレッド間で共有されるかを判定します。
また、自動並列化では、ループ処理のタスクで並列に実行できる部分と、逐次処理する部分も分離して、並列化
処理のためのコードへの変換がなされます。実際には、スカラー最適化やループ最適化 (レジスター内でのベクトル
化やメモリー最適化) といった最適化機能と並列化機能の 2 つは緊密に統合されて、キャッシュの局所性を高め、ス
レッドレベル以外での並列性を効率的に利用しています。
自動並列化では、入れ子になった多重ループの場合、できるだけ外側のループを並列化の対象とするようになっ
ており、並列処理のオーバーヘッドを最大限減らすことに寄与します。例えば、二重にネストされたループの場合、
最内側ループについては、ベクトル化をはじめキャッシュの局所性を高め、レジスター利用の最適化を最大限に図り、
計算回数とメモリー参照を最小化するような最適化の適用を目指し、外側ループでマルチスレッド・コードを生成する
ような最適化を行います。自動並列化での並列処理は、 一般には、「細粒度」での並列処理となります。
例えば、 次のようなプログラムの自動並列化を考えてみましょう。
for (i=1; i<100; i++)
{
a[i] = a[i] + b[i] * c[i];
}
プログラム
スタック
データ
オリジナル
並列処理のための
コード変換
複数のタスクに分割
並列化されたプログラム
Program SPMD_Emb_Par ()
{
TYPE *tmp, *func();
global_array Data(TYPE);
global_array Res(TYPE);
int N = get_num_procs();
int id = get_proc_id();
if (id==0) setup_problem(N,DATA);
for (int I= 0; I<N;I=I+Num){
tmp = func(I);
Res.accumulate( tmp);
}
}
Program SPMD_Emb_Par ()
{
TYPE *tmp, *func();
global_array Data(TYPE);
global_array Res(TYPE);
int N = get_num_procs();
int id = get_proc_id();
if (id==0) setup_problem(N,DATA);
for (int I= 0; I<N;I=I+Num){
tmp = func(I);
Res.accumulate( tmp);
}
}
Program SPMD_Emb_Par ()
{
TYPE *tmp, *func();
global_array Data(TYPE);
global_array Res(TYPE);
int N = get_num_procs();
int id = get_proc_id();
if (id==0) setup_problem(N,DATA);
for (int I= 0; I<N;I=I+Num){
tmp = func(I);
Res.accumulate( tmp);
}
}
Program SPMD_Emb_Par ()
{
TYPE *tmp, *func();
global_array Data(TYPE);
global_array Res(TYPE);
int Num = get_num_procs();
int id = get_proc_id();
if (id==0) setup_problem(N, Data);
for (int I= ID; I<N;I=I+Num){
tmp = func(I, Data);
Res.accumulate( tmp);
}
}
共有データ
タスク、ローカルデータと
共有データの明確化
複数のタスクを分割し
逐次処理部分の分離
共有データ
分割されたタスクを
グループ化