インテル® C++ コンパイラー 18.0 デベロッパー・ガイドおよびリファレンス
関数の呼び出し (行 %d)、IF 条件 (行 %d)、早期終了 (行 %d) を含むコードブロックをループの外側に移動することで、行 %d のループを並列化できます。
ループを並列化するために、関数呼び出しと関連するリターンをループの中から (ループの前に持ってくるなどして) 移動します。
このようなループ中の関数とリターンは、通常ループ中のエラー条件を処理します。プログラムのセマンティクスを変更することなく、このエラーチェックをループの実行前に行える場合、コンパイラーはループを並列化してパフォーマンスを向上できる可能性があります。
次の例について考えてみます。
extern int num_nodes; typedef struct TEST_STRUCT { // city1 の座標 float latitude1; float longitude1; // city2 の座標 float latitude2; float longitude2; } test_struct; extern int *mark_larger; extern float *distances, **matrix; extern test_struct** nodes; extern test_struct ***files; extern void init_node(test_struct *node, int i); extern void process_nodes(void); float compute_max_distance(void); extern int check_error_condition(int width); #include <math.h> #include <stdio.h> void process_nodes(int width) { float const R = 3964.0; float temp, lat1, lat2, long1, long2, result, pat2; int m, j, temp1 = num_nodes; nodes = files[0]; m = 1; #pragma loop count min(4) #pragma parallel for (int k=0; k < temp1; k++) { if (check_error_condition(width)) { return; } lat1 = nodes[k]->latitude1; lat2 = nodes[k]->latitude2; long1 = nodes[k]->longitude1; long2 = nodes[k]->longitude2; // 2 つの地点間の距離を計算 temp = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(long1-long2); result = 2.0 * R * atan(sqrt((1.0-temp)/(1.0+temp))); pat2 = 0; for(j=0; j<width; j++) { pat2 += distances[j]; matrix[k][j] = distances[k]+j; } // 計算した距離を distances 配列にストア if (result > distances[k]) { distances[k] = result + pat2; } } }
この例では、コンパイラーは行 38 のループを並列化できません。
安全であることが分かっている場合は、次のようにプログラムコードを変更します。
extern int num_nodes; typedef struct TEST_STRUCT { // city1 の座標 float latitude1; float longitude1; // city2 の座標 float latitude2; float longitude2; } test_struct; extern int *mark_larger; extern float *distances, **matrix; extern test_struct** nodes; extern test_struct ***files; extern void init_node(test_struct *node, int i); extern void process_nodes(void); float compute_max_distance(void); extern int check_error_condition(int width); #include <math.h> #include <stdio.h> void process_nodes(int width) { float const R = 3964.0; float temp, lat1, lat2, long1, long2, result, pat2; int m, j, temp1 = num_nodes; nodes = files[0]; m = 1; if (check_error_condition(width)) { return; } #pragma loop count min(4) #pragma parallel for (int k=0; k < temp1; k++) { lat1 = nodes[k]->latitude1; lat2 = nodes[k]->latitude2; long1 = nodes[k]->longitude1; long2 = nodes[k]->longitude2; // 2 つの地点間の距離を計算 temp = sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(long1-long2); result = 2.0 * R * atan(sqrt((1.0-temp)/(1.0+temp))); pat2 = 0; for(j=0; j<width; j++) { pat2 += distances[j]; matrix[k][j] = distances[k]+j; } // 計算した距離を distances 配列にストア if (result > distances[k]) { distances[k] = result + pat2; } } }
関数の呼び出しがループ内のどの演算にも依存していないこと、およびこのコード変更によってオリジナルのプログラムのセマンティクスが変更されないことを確認してください。