パフォーマンスファイル (*.inf) はP-NCASで静的負荷分散型・動的負荷分散型の並列プログラムを設計するときに必要なファイルです。このファイルには並列計算で使用するプロセッサの計算能力値と通信時間最小となる分割形状のデータが記述されている。P-NCASではこのファイルを参照することで静的負荷分散・動的負荷分散型の並列プログラムを設計します。パフォーマンスファイルはP-NCASが事前に用意している、プロセッサ処理能力測定並列プログラム (measure4.c) を実行することで得ることができる。以後では
l パフォーマンスファイルの内容
l パフォーマンスファイルの作成方法
について説明していきます。
具体的にパフォーマンスファイルの内容について説明します。
これは並列計算を行うプロセッサ数が4台の場合である。各プロセッサを順にそれぞれRANKNO 0,1,2,3と名前付けしている。
パフォーマンスファイルを入手するにはプロセッサ処理能力測定並列プログラム (measure4.c) を、並列計算で使用する各プロセッサ上で実行します。プロセッサ処理能力測定並列プログラムが実行終了するとパフォーマンスファイル(performance.inf)が作成されます。
プロセッサ処理能力測定並列プログラムの所在は…
NCASシステム内のtempディレクトリ内にmeasure4.cとして存在します。このファイルを元にしてプロセッサの処理能力を測定してください。
このプログラムはSPMDタイプの並列プログラムとなっている。
プログラムを実行する前にプログラム内のパラメータを設定する必要があります。設定が必要なパラメータと測定プログラムのコメントを記します。
measure4.c
#include <stdio.h>
#include <math.h>
#include <mpi.h>
#include <time.h> /*include time function */
/*Definition of constatnts */
/* All number of CPU */
#define CPU_NUMBER 6 プロセッサ数の設定。使用するプロセッサの数と一致させてください。設定必要
#define DIM 2 計算するモデルの次元数を設定してください。設定必要
/* Mesh Number of Computaiton Model */
#define IMAX 50 ← 設計するモデルのx方向のメッシュ数 設定必要
#define JMAX 50 ← 設計するモデルのy方向のメッシュ数 設定必要
#define KMAX 50 ← 設計するモデルのz方向のメッシュ数(DIMが2ならば無視される) 設定必要
/* Case of 2dim,This constant no concern.*/
/* debug */
#define _debug_ TRUE
/* Definition of constants */
#define COUNT1 10000 /* performance loop counter 1*/
#define COUNT2 1000 /* performance loop counter 2*/
#define COUNT3 100 /* communicate loop counter */
#define COUNT4 1000 /* Domain Calc. loop counter */
↑COUNT1, COUNT2 プロセッサ処理能力を測定するループの繰り返す数
COUNT3 最小通信時間測定ループの繰り返す数
COUNT4 得られたデータから実際に分割領域を行い、変数があると想定して行う計算の繰り返す数
測定プログラムの実行時間が極端に長い、もしくは短い場合は設定必要
/* Definition of Parallel constants */
#define X_MIN (1)
#define Y_MIN (1)
#define Z_MIN (1)
#define X_MAX (IMAX-1)
#define Y_MAX (JMAX-1)
#define Z_MAX (KMAX-1)
/* prototypes definition of all functions in this program */
int main();
void CPU_Measure();
void CPU_Measure_Domain();
void MPIinit();
void MPIfinish();
void Data_Gather();
void Data_ALLGather();
void Data_Standard();
void Data_Ranking();
void Output();
void Output2();
void Output3();
void Set_Parameter();
void Set_Range();
void Para_Range();
void Para_Range_Static();
void Data_Shift_Measure();
void Data_Shift();
void Data_Shift_Ranking();
void init();
/* MPI type Variables */
MPI_Request isend1;
MPI_Request isend2;
MPI_Request jsend1;
MPI_Request jsend2;
MPI_Request ksend1;
MPI_Request ksend2;
MPI_Request irecv1;
MPI_Request irecv2;
MPI_Request jrecv1;
MPI_Request jrecv2;
MPI_Request krecv1;
MPI_Request krecv2;
MPI_Status status;
MPI_Request data_send;
MPI_Request data_recv[CPU_NUMBER];
/* Int type Variables */
int myrank;
int nprocs;
int myranki;
int istart;
int iend;
int istart2;
int iend2;
int iup;
int idown;
int ilen;
int myrankj;
int jstart;
int jend;
int jstart2;
int jend2;
int jup;
int jdown;
int jlen;
int myrankk;
int kstart;
int kend;
int kstart2;
int kend2;
int kup;
int kdown;
int klen;
#if DIM == 2
int table[CPU_NUMBER+2][CPU_NUMBER+2];
#elif DIM == 3
int table[CPU_NUMBER+2][CPU_NUMBER+2][CPU_NUMBER+2];
#endif
int perform_rank[CPU_NUMBER];
int X_div,Y_div,Z_div;
int x_mesh_size[CPU_NUMBER],y_mesh_size[CPU_NUMBER],z_mesh_size[CPU_NUMBER];
int flag = 1;
int x_store,y_store,z_store;
/* Declaration of FILE Pointer */
FILE *filePnt1;
double time_interval[CPU_NUMBER];
double time_diff,min_shift_time;
double total;
#if DIM == 2
double Test1[IMAX+1][JMAX+1]; /* Variable1 for Commnication Test */
double Test2[IMAX+1][JMAX+1]; /* Variable2 for Commnication Test */
#elif DIM == 3
double Test1[IMAX+1][JMAX+1][KMAX+1]; /* Variable1 for Commnication Test */
double Test2[IMAX+1][JMAX+1][KMAX+1]; /* Variable2 for Commnication Test */
#endif
typedef time_t TIME;
typedef clock_t CLOCK;
int main(int argc,char **argv)
{
int i,j,k;
filePnt1 = fopen("performance.inf", "w"); ファイルを開く
MPIinit(argc,argv); MPIを起動する
/* CPU performance measure */
CPU_Measure(); /* Floating point calc. & time measure */ プロセッサの処理能力を測る
Data_Gather(); /* Gather measure data to rank=0 */ 測定データを集計する
if(myrank==0) {
Data_Standard(); /*Data normalization */ データの規格化
Data_Ranking(); /*Data Ranking */ データのランク付け
Output(); /* Output Performance Value & Speed Rank */ パフォーマンスファイルへの出力
}
Data_ALLGather(); /* Send parameter to each rank */ 各プロセッサへ測定したデータを送信する
/* ----------------------- */
/* Data Comunication Time measure */
通信時間の測定
#if DIM == 2
for(i = 1; i <= CPU_NUMBER; i++){ プロセッサ数から考えられるすべての分割形状のパターンについてループする
for(j = 1; j <= CPU_NUMBER; j++){
if((i*j) == CPU_NUMBER){
X_div = i;
Y_div = j;
if(_debug_){
printf("X_div = %d Y_div = %d \n",X_div,Y_div);
}
Set_Parameter(); 並列計算に必要なパラメータの設定
Data_Shift_Measure(); /* Data Communication Measure */ プロセッサ間通信時間の測定
if(myrank == 0){
Data_Shift_Ranking(); /*Data Ranking */ 測定データのランク付け
}
}
}
}
#elif DIM == 3
for(i = 1; i <= CPU_NUMBER; i++){
for(j = 1; j <= CPU_NUMBER; j++){
for(k = 1; k <= CPU_NUMBER; k++){
if((i*j*k) == CPU_NUMBER){
X_div = i;
Y_div = j;
Z_div = k;
if(_debug_){
printf("X_div = %d Y_div = %d Z_div \n",X_div,Y_div,Z_div);
}
Set_Parameter();
Data_Shift_Measure(); /* Data Communication Measure */
if(myrank == 0){
Data_Shift_Ranking(); /*Data Ranking */
}
}
}
}
}
#endif
/*---------------------------------------*/
if(myrank == 0){
Output2(); /*Output Best Division Number */ パフォーマンスファイルへの出力
}
CPU_Measure_Domain(); 測定したプロセッサ値、分割形状を利用して実際に計算を行う
Data_Gather(); 測定データの集計
if(myrank == 0){
Output3(); パフォーマンスファイルへの出力
}
/* ----------------------- */
MPIfinish(); MPIの終了
fclose(filePnt1); ファイルクローズ
return(0); 終了
}
void CPU_Measure_Domain() 測定したプロセッサ値、分割形状を利用して実際に領域分割をし計算を行う。このプログラムで測定したデータが妥当であるか検証するために作成
{
int i,j,k,count;
int int_data = 100;
double double_data = 1.0E+8;
TIME start_time,end_time; /* TIME = time_t type*/ 実時間変数
CLOCK start_clock,end_clock; /* CLOCK = clock_t type*/ クロック変数
MPI_Barrier(MPI_COMM_WORLD); /* douki */ 各プロセッサで同期を取る
start_clock = clock();
time(&start_time); /* Start */ 時間測定開始
#if DIM == 2
for(count=0; count<=COUNT4; count++) { COUNT4回繰り返す
for(i=istart; i<=iend; i++) { 領域分割された領域を計算する
for(j=jstart; j<=jend; j++) {
Test1[i][j] = Test1[i][j]+Test1[i][j];
Test2[i][j] = Test2[i][j]+Test2[i][j];
Test1[i][j] = Test1[i][j]*Test1[i][j];
Test2[i][j] = Test2[i][j]*Test2[i][j];
Test1[i][j] = Test1[i][j]/Test1[i][j];
Test2[i][j] = Test2[i][j]/Test2[i][j];
}
}
}
#elif DIM == 3
for(count=0; count<=COUNT4; count++) {
for(i=istart; i<=iend; i++) {
for(j=jstart; j<=jend; j++) {
for(k=kstart; k<=kend; k++) {
Test1[i][j][k] = Test1[i][j][k]+Test1[i][j][k];
Test2[i][j][k] = Test2[i][j][k]+Test2[i][j][k];
Test1[i][j][k] = Test1[i][j][k]*Test1[i][j][k];
Test2[i][j][k] = Test2[i][j][k]*Test2[i][j][k];
Test1[i][j][k] = Test1[i][j][k]/Test1[i][j][k];
Test2[i][j][k] = Test2[i][j][k]/Test2[i][j][k];
}
}
}
}
#endif
end_clock = clock();
time(&end_time); /*end*/ 測定終了
/*
time_diff = difftime(end_time,start_time);
*/ /*calc.time*/
/*
time_diff = (end_clock - start_clock)/(double)CLOCKS_PER_SEC;
*/
time_diff = difftime(end_time,start_time); 実行時間
time_interval[myrank] = time_diff; 各プロセスの実行時間をtime_interval[]へ格納する
/*
if(_debug_){
printf("rank = %d time = %f \n",myrank,time_diff);
printf("rank = %d clock = %ld \n"
,myrank,end_clock-start_clock);
}
*/
}
void Output3() パフォーマンスファイルへのデータ出力
{
int rank;
fprintf(filePnt1,"\n--- DOMAIN CALC --- \n");
for(rank=0; rank <= CPU_NUMBER-1; rank++){
fprintf(filePnt1,"RANK NO %d %f [sec] \n",rank,time_interval[rank]);
各プロセスの実行時間を出力
}
}
void CPU_Measure() プロセッサの処理能力値を測定する
{
int i,j;
int int_data = 100;
double double_data = 1.0E+8;
TIME start_time,end_time; /* TIME = time_t type*/
CLOCK start_clock,end_clock; /* CLOCK = clock_t type*/
MPI_Barrier(MPI_COMM_WORLD); /* douki */同期
start_clock = clock();
time(&start_time); /* Start */ 測定開始
for(i=0; i<=COUNT1; i++) { COUNT1 × COUNT2回浮動小数点計算を繰り返すことでプロセッサの処理能力を測定する
for(j=0; j<=COUNT2; j++) {
int_data = int_data + int_data;
double_data = double_data + double_data;
int_data = int_data * int_data;
double_data = double_data * double_data;
int_data = int_data / int_data;
double_data = double_data / double_data;
}
}
end_clock = clock();
time(&end_time); /*end*/ 測定終了
/*
time_diff = difftime(end_time,start_time);
*/ /*calc.time*/
time_diff = (end_clock - start_clock)/(double)CLOCKS_PER_SEC; クロック実時間
time_diff = difftime(end_time,start_time) / time_diff; 負荷も考慮した実行時間
if(_debug_){
printf("rank = %d clock = %f \n",myrank,time_diff);
/**/
printf("rank = %d time = %f \n"
,myrank,difftime(end_time,start_time));
/**/
}
}
void Data_Gather() 各プロセスで測定したデータを親プロセス(プロセス0)へ送信する関数
{
int rank;
if(myrank==0) {
for(rank=1; rank<=CPU_NUMBER-1; rank++) {
MPI_Irecv(&time_interval[rank],1,MPI_DOUBLE,rank,1,MPI_COMM_WORLD,&data_recv[rank]); 各プロセスから送られてくるデータをtime_interval[各プロセス番号]へ格納する
}
for(rank=1; rank<=CPU_NUMBER-1; rank++) {
MPI_Wait(&data_recv[rank],&status); データ通信の同期
}
} else {
MPI_Isend(&time_diff,1,MPI_DOUBLE,0,1,MPI_COMM_WORLD,&data_send);
MPI_Wait(&data_send,&status); プロセス0以外のプロセスはプロセス0へtime_diffをデータ送信する
}
/*
if(_debug_){
printf("Gather_finish\n");
}
*/
}
void Data_ALLGather() プロセス0のデータを各プロセスへ送信する
{
MPI_Bcast(time_interval,CPU_NUMBER,MPI_DOUBLE,0,MPI_COMM_WORLD); time_interval[]を送信する
MPI_Bcast(perform_rank,CPU_NUMBER,MPI_DOUBLE,0,MPI_COMM_WORLD); perform_rank[]を送信する
/*
if(_debug_){
printf("time_interval[%d] = %f\n",myrank,time_interval[myrank]);
}
*/
}
void Data_Standard() 配列のデータを規格化する プロセス0のみが実行する関数
{
int rank;
double time_max;
time_interval[0] = time_diff;
time_max = time_interval[0]; 最初の最大値
if(_debug_){
for(rank=0; rank <= CPU_NUMBER-1; rank++){
printf("time_interval[%d] = %f \n"
,rank,time_interval[rank]);
}
}
/*Store the most value in time_interval(=calc.time)*/
for(rank=1; rank<= CPU_NUMBER-1; rank++){ 最大値の検索
if(time_max < time_interval[rank]){
time_max = time_interval[rank];
}
}
/*Normalization*/
for(rank=0; rank <= CPU_NUMBER-1; rank++){ 最大値を使用してデータを規格化
time_interval[rank] = time_max / time_interval[rank];
}
}
void Data_Ranking() 配列のデータを参照してランク付けをおこなう
{
int i,j,k,JUMP;
int speed_rank,equal_number;
int equal_rank[CPU_NUMBER];
double perform,work;
if(_debug_){
printf("Data_Ranking\n");
}
/* Speed no hayai jynn ni rankno wo naraberu */
for(i = 0; i <= CPU_NUMBER-1; i++){ 値の大きい順にランクNOを並べるループ
JUMP = FALSE;
speed_rank = 0;
equal_number = 0; 初期値の設定
perform = time_interval[i]; 比較するデータ
for(j = 0; j <= CPU_NUMBER-1; j++){ 比較するデータとtime_intrval[]のデータ比較
if(i == j) continue; 同一データなら
if(perform < time_interval[j]){ 小さいなら
speed_rank++;
}else if(perform == time_interval[j]){ 等しい値のデータなら
if(i > j){
JUMP = TRUE;
break;
}
equal_rank[0] = i;
equal_number++;
equal_rank[equal_number] = j;
}
}
if(!JUMP){ 等しいデータがあるときの処理
if(equal_number == 0){
perform_rank[speed_rank] = i;
}else{
for(k=0; k <= equal_number; k++){
perform_rank[speed_rank+k] = equal_rank[k];
}
}
}
}
/*
if(_debug_){
for(i=0; i<=CPU_NUMBER-1; i++){
printf("perform_rank[%d] = %d\n",i,perform_rank[i]);
}
}
*/
}
void Output() パフォーマンスファイルへのデータ出力
{
int rank;
fprintf(filePnt1,"CPU_NUMBER %d\n",CPU_NUMBER); プロセッサ数
for(rank=0; rank <= CPU_NUMBER-1; rank++){
fprintf(filePnt1,"RANKNO %d %f\n",rank,time_interval[rank]); プロセッサ能力値の出力
}
for(rank=0; rank <= CPU_NUMBER-1; rank++){
fprintf(filePnt1,"SPEED %d %d\n",rank,perform_rank[rank]); 処理能力値の速いプロセス順の列挙
}
}
void MPIinit(int char_num,char **char_str) MPIの起動
{
MPI_Init(&char_num,&char_str);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
if(nprocs!=CPU_NUMBER) { コンパイルオプションの分割数とプログラム内のプロセッサ数が一致しているかどうか
printf("ERROR: It is difference between nprocs(on MPI environment) and CPU number\n"); 一致していなければエラー出力
MPI_Finalize(); MPIの終了
exit(-1);
}
}
void MPIfinish()
{
MPI_Finalize(); MPIの終了
}
void Set_Parameter() 並列計算するためのパラメータ設定 IBM青山さんのMPI参考書を参照してください
{
#if DIM == 2
int i, j, rank, c;
c = 1;
for(j=-1; j<=Y_div; j++) { テーブル配列の初期化
for(i=-1; i<=X_div; i++) {
table[i+c][j+c] = MPI_PROC_NULL;
}
}
rank = 0;
for(j=0; j<=Y_div-1; j++) { テーブル配列の設定
for(i=0; i<=X_div-1; i++) {
table[i+c][j+c] = rank;
if(myrank==rank) {
myranki = i;
myrankj = j;
}
rank = rank+1;
}
}
if(X_div != 1){ x方向の分割数が1以上ならば
/* Change Domain Area by performance value*/ x方向の分割領域の変数設定
Para_Range_Static(X_MIN,X_MAX,X_div,myranki,&istart,&iend,0,x_mesh_size);
}else{ x方向の分割数が1ならば
Para_Range(X_MIN,X_MAX,X_div,myranki,&istart,&iend);
}
if(Y_div != 1){ y方向の分割数が1以上ならば
/* Change Domain Area by performance value*/ y方向の分割領域の変数設定
Para_Range_Static(Y_MIN,Y_MAX,Y_div,myrankj,&jstart,&jend,1,y_mesh_size);
}else{ y方向の分割数が1ならば
Para_Range(Y_MIN,Y_MAX,Y_div,myrankj,&jstart,&jend);
}
ilen = iend-istart+1; x方向の領域のメッシュ数
jlen = jend-jstart+1; y方向の
Set_Range(istart,iend,myranki,X_div,&istart2,&iend2); istart2,iend2を設定
Set_Range(jstart,jend,myrankj,Y_div,&jstart2,&jend2);
iup = table[myranki+1+c][myrankj+c]; 上に位置するプロセス番号
idown = table[myranki-1+c][myrankj+c]; 左に位置するプロセス番号
jup = table[myranki+c][myrankj+1+c]; 右に位置するプロセス番号
jdown = table[myranki+c][myrankj-1+c]; 下に位置するプロセス番号
if(_debug_){
printf("myrank = %d istart = %d iend = %d jstart = %d jend = %d\n",myrank,istart,iend,jstart,jend);
printf("myrank = %d iup = %d idown = %d jup = %d jdown = %d\n",myrank,iup,idown,jup,jdown);
}
#elif DIM == 3
int i, j, k, rank, c;
c = 1;
for(k=-1; k<=Z_div; k++) {
for(j=-1; j<=Y_div; j++) {
for(i=-1; i<=X_div; i++) {
table[i+c][j+c][k+c] = MPI_PROC_NULL;
}
}
}
rank = 0;
for(k=0; k<=Z_div-1; k++) {
for(j=0; j<=Y_div-1; j++) {
for(i=0; i<=X_div-1; i++) {
table[i+c][j+c][k+c] = rank;
if(myrank==rank) {
myranki = i;
myrankj = j;
myrankk = k;
}
rank = rank+1;
}
}
}
if(X_div !=1){
Para_Range_Static(X_MIN,X_MAX,X_div,myranki,&istart,&iend,0,x_mesh_size);
}else{
Para_Range(X_MIN,X_MAX,X_div,myranki,&istart,&iend);
}
if(Y_div !=1){
Para_Range_Static(Y_MIN,Y_MAX,Y_div,myrankj,&jstart,&jend,1,y_mesh_size);
}else{
Para_Range(Y_MIN,Y_MAX,Y_div,myrankj,&jstart,&jend);
}
if(Z_div !=1){
Para_Range_Static(Z_MIN,Z_MAX,Z_div,myrankk,&kstart,&kend,2,z_mesh_size);
}else{
Para_Range(Z_MIN,Z_MAX,Z_div,myrankk,&kstart,&kend);
}
ilen = iend-istart+1;
jlen = jend-jstart+1;
klen = kend-kstart+1;
Set_Range(istart,iend,myranki,X_div,&istart2,&iend2);
Set_Range(jstart,jend,myrankj,Y_div,&jstart2,&jend2);
Set_Range(kstart,kend,myrankk,Z_div,&kstart2,&kend2);
iup = table[myranki+1+c][myrankj+c][myrankk+c];
idown = table[myranki-1+c][myrankj+c][myrankk+c];
jup = table[myranki+c][myrankj+1+c][myrankk+c];
jdown = table[myranki+c][myrankj-1+c][myrankk+c];
kup = table[myranki+c][myrankj+c][myrankk+1+c];
kdown = table[myranki+c][myrankj+c][myrankk-1+c];
#endif
}
void Set_Range(int start,int end,int axis_rank,int axis_div,int *p_start2,int *p_end2)
{
*p_start2 = start;
*p_end2 = end;
if(axis_rank==0) { 下端に位置するプロセスは計算領域を拡張
*p_start2 = start+1;
}
if(axis_rank==axis_div-1) { 上端に位置するプロセスは計算領域を縮小
*p_end2 = end-1;
}
}
void Para_Range(int min_mesh,int max_mesh,int proc_num,int rank_num,int *p_start,int *p_end)
{ 全メッシュ数、分割数から各プロセスが担当するメッシュ範囲を計算する。最終的にはp_start,p_endが担当する範囲となる
int work1, work2, dummy, min;
work1 = (max_mesh-min_mesh+1)/(proc_num);
work2 = (max_mesh-min_mesh+1)%proc_num;
if(work2>=rank_num) {
min = rank_num;
} else {
min = work2;
}
*p_start = rank_num*work1+min_mesh+min;
dummy = *p_start;
*p_end = dummy+work1-1;
dummy = *p_end;
if(work2>rank_num) {
*p_end = dummy+1;
}
}
/*new function*/
void Perform_Total()
{ 配列time_interval[]を総計する関数
/* performance total */
int i;
total = 0.0;
for(i = 0; i <= CPU_NUMBER-1; i++){
/* performance total calc.*/
total += time_interval[i];
}
}
/*new function*/
void Mesh_Resize(double min_mesh,double max_mesh,int proc_num,int axis_sw,int mesh_size[CPU_NUMBER])
{ 各軸の担当するメッシュ範囲を変更する関数
#if DIM == 2
/* axis_sw if 0 --> X axis calc. */ 変更する軸
/* axis_sw if 1 --> Y axis calc. */
int i,i_store,j_store;
int total_mesh,amari,rank;
int axis_rank,irank,jrank,against_proc_num;
double axis_perform;
total_mesh = 0;
if(axis_sw == 0){
against_proc_num = Y_div;
}else if(axis_sw == 1){
against_proc_num = X_div;
}
/*
if(_debug_){
for(i=0; i<= CPU_NUMBER-1; i++){
printf("time_interval[%d] = %f\n",i,time_interval[i]);
}
}
*/
for(i=0; i<=proc_num-1;i++){
axis_perform = 0.0;
for(axis_rank = 1; axis_rank <= against_proc_num; axis_rank++){ 変更したい軸方向のパフォーマンス値を総計する
/* aru jiku no performance no souwa */
if(axis_sw == 0){
axis_perform += time_interval[table[i+1][axis_rank]];
}else if(axis_sw == 1){
axis_perform += time_interval[table[axis_rank][i+1]];
}
}
mesh_size[i] = (max_mesh-min_mesh+1.0)*(axis_perform/total); パフォーマンスに応じてメッシュを割り当てる
total_mesh = total_mesh + mesh_size[i];
}
/* Case of Warikirenai */
if(total_mesh != (max_mesh-min_mesh+1)){ 全メッシュ数と割り当てれらたメッシュ数の確認
amari = (max_mesh-min_mesh+1) - total_mesh;
for(i = 0; i <= amari-1; i++){ メッシュ数に余りがある場合は、パフォーマンスの高いプロセスに順にメッシュを割り当てていく
rank = perform_rank[i];
irank = 1;
jrank = 1;
/*Speed hayai jyunn Amari wo wariate*/
for(irank = 1; irank <= X_div; irank++){
for(jrank = 1; jrank <= Y_div; jrank++){
if(rank == table[irank][jrank]){
i_store = irank;
j_store = jrank;
}
}
}
if(axis_sw == 0){
mesh_size[i_store-1] = mesh_size[i_store-1] + 1; 計算領域の増加
}else if(axis_sw == 1){
mesh_size[j_store-1] = mesh_size[j_store-1] + 1;
}
}
}
/*
if(_debug_){
for(i=0; i<=proc_num-1;i++){
printf("mesh_size[%d] = %d \n",i,mesh_size[i]);
}
}
*/
#elif DIM == 3
int i,irank,jrank,krank,i_store,j_store,k_store;
int total_mesh,amari,rank;
int axis_rank,axis_rank2,against_proc_num,vert_proc_num;
double axis_perform;
total_mesh = 0;
if(axis_sw == 0){
against_proc_num = Y_div;
vert_proc_num = Z_div;
}else if(axis_sw == 1){
against_proc_num = Z_div;
vert_proc_num = X_div;
}else if(axis_sw == 2){
against_proc_num = X_div;
vert_proc_num = Y_div;
}
for(i=0; i<=proc_num-1;i++){
axis_perform = 0.0;
for(axis_rank = 1; axis_rank <= against_proc_num; axis_rank++){
for(axis_rank2 = 1; axis_rank2 <= vert_proc_num; axis_rank2++){
/* aru jiku no performance no souwa */
if(axis_sw == 0){
axis_perform = axis_perform + time_interval[table[i+1][axis_rank][axis_rank2]];
}else if(axis_sw == 1){
axis_perform = axis_perform + time_interval[table[axis_rank2][i+1][axis_rank]];
}else if(axis_sw == 2){
axis_perform = axis_perform + time_interval[table[axis_rank][axis_rank2][i+1]];
}
}
}
mesh_size[i] = (max_mesh-min_mesh+1.0)*(axis_perform/total);
total_mesh = total_mesh + mesh_size[i];
}
/* Case of Warikirenai */
if(total_mesh != (max_mesh-min_mesh+1)){
amari = (max_mesh-min_mesh+1) - total_mesh;
for(i = 0; i <= amari-1; i++){
rank = perform_rank[i];
/*Speed hayai jyunn Amari wo wariate*/
for(irank = 1; irank <= X_div; irank++){
for(jrank = 1; jrank <= Y_div; jrank++){
for(krank = 1; krank <= Z_div; krank++){
if(rank == table[irank][jrank][krank]){
i_store = irank;
j_store = jrank;
k_store = krank;
}
}
}
}
if(axis_sw == 0){
mesh_size[i_store-1] = mesh_size[i_store-1] + 1;
}else if(axis_sw == 1){
mesh_size[j_store-1] = mesh_size[j_store-1] + 1;
}else if(axis_sw == 2){
mesh_size[k_store-1] = mesh_size[k_store-1] + 1;
}
}
}
/*
if(_debug_){
for(i=0; i<=proc_num-1;i++){
printf("mesh_size = %d \n",mesh_size[i]);
}
}
*/
#endif
}
/* new function */
void Para_Range_Static(int min_mesh,int max_mesh,int proc_num,int rank_num,int *p_start,int *p_end,int axis_sw,int axis_mesh_size[CPU_NUMBER])
{ 各軸のメッシュ範囲を設定する関数
int i,work1;
double total;
Perform_Total();
Mesh_Resize(min_mesh,max_mesh,proc_num,axis_sw,axis_mesh_size);
work1 = 0;
for(i = 0; i <= rank_num; i++){
work1 = axis_mesh_size[i] + work1;
}
*p_start = work1 - (axis_mesh_size[rank_num]-1);
*p_end = work1;
/*
if(_debug_){
printf("start = %d end = %d \n",*p_start,*p_end);
}
*/
}
void Data_Shift_Measure()
{ 各領域の境界データの通信速度を測定する関数
int i;
TIME start_time,end_time;
CLOCK start_clock,end_clock;
MPI_Barrier(MPI_COMM_WORLD); /*douki*/ 同期
start_clock = clock();
time(&start_time); /*start*/ 測定開始
for(i = 0; i <= COUNT3; i++){ 境界データ通信をCOUNT3回繰り返す
#if DIM == 2
Data_Shift(Test1,ilen,jlen); ilen×jlenの大きさのTest1配列の境界データを送信する
Data_Shift(Test2,ilen,jlen);
#elif DIM == 3
Data_Shift(Test1,ilen,jlen,klen);
Data_Shift(Test2,ilen,jlen,klen);
#endif
}
MPI_Barrier(MPI_COMM_WORLD); /*douki*/ 同期
time(&end_time); /*end*/
end_clock = clock(); 測定終了
time_diff = difftime(end_time,start_time); /* Comm.time*/ 測定時間
if(_debug_){
printf("Data_Shift time = %f \n",time_diff);
}
}
#if DIM == 2
void Data_Shift(double Send_Var[IMAX+1][JMAX+1],int i_length,int j_length)
{ 境界データを通信する関数
int i, j;
double Send_Left[JMAX+1], Send_Right[JMAX+1]; 送信データ配列
double Send_Top[IMAX+1], Send_Bttm[IMAX+1];
double Recv_Left[JMAX+1], Recv_Right[JMAX+1]; 受信データ配列
double Recv_Top[IMAX+1], Recv_Bttm[IMAX+1];
if(myrankj!=Y_div-1) {
for(i=istart; i<=iend; i++) { 領域の上端の境界をパック
Send_Top[i] = Send_Var[i][jend];
}
}
if(myrankj!=0) {
for(i=istart; i<=iend; i++) { 領域の下端の境界をパック
Send_Bttm[i] = Send_Var[i][jstart];
}
}
MPI_Isend(&Send_Var[iend][jstart],j_length,MPI_DOUBLE,iup,1,MPI_COMM_WORLD,&isend1); 領域の右端の境界を、iupプロセス(右端へ位置するプロセス)へ送信する
MPI_Isend(&Send_Var[istart][jstart],j_length,MPI_DOUBLE,idown,1,MPI_COMM_WORLD,&isend2); 領域の左端の境界を、idownプロセス(左端へ位置するプロセス)へ送信する
MPI_Isend(&Send_Top[istart],i_length,MPI_DOUBLE,jup,1,MPI_COMM_WORLD,&jsend1); 領域の上端データをjupプロセスへ送信する
MPI_Isend(&Send_Bttm[istart],i_length,MPI_DOUBLE,jdown,1,MPI_COMM_WORLD,&jsend2); 領域の下端データをjdownプロセスへ送信する
MPI_Irecv(&Send_Var[istart-1][jstart],j_length,MPI_DOUBLE,idown,1,MPI_COMM_WORLD,&irecv1); idownプロセス(左端に位置するプロセス)から送られてくる境界データをSend_Var配列へ受け取る
MPI_Irecv(&Send_Var[iend+1][jstart],j_length,MPI_DOUBLE,iup,1,MPI_COMM_WORLD,&irecv2); iupプロセス(右端に位置するプロセス)から送られてくる境界データをSend_Var配列へ受け取る
MPI_Irecv(&Recv_Bttm[istart],i_length,MPI_DOUBLE,jdown,1,MPI_COMM_WORLD,&jrecv1); jdownプロセス(下端に位置するプロセス)から送られてくる境界データをRecv_Bttm配列へ受け取る
MPI_Irecv(&Recv_Top[istart],i_length,MPI_DOUBLE,jup,1,MPI_COMM_WORLD,&jrecv2); jupプロセス(上端に位置するプロセス)から送られてくる境界データをRecv_Top配列へ受け取る
MPI_Wait(&isend1,&status); 同期
MPI_Wait(&isend2,&status);
MPI_Wait(&jsend1,&status);
MPI_Wait(&jsend2,&status);
MPI_Wait(&irecv1,&status);
MPI_Wait(&irecv2,&status);
MPI_Wait(&jrecv1,&status);
MPI_Wait(&jrecv2,&status);
if(myrankj!=0) {
for(i=istart; i<=iend; i++) { 受信データのアンパック、下端境界のデータ
Send_Var[i][jstart-1] = Recv_Bttm[i];
}
}
if(myrankj!=Y_div-1) {
for(i=istart; i<=iend; i++) { 受信データのアンパック、上端境界のデータ
Send_Var[i][jend+1] = Recv_Top[i];
}
}
}
#elif DIM == 3
void Data_Shift(double Send_Var[IMAX+1][JMAX+1][KMAX+1],int i_length,int j_length,int k_length)
{
int i, j, k, cnt, i_face, j_face, k_face;
double Send_Left[JMAX*KMAX+1], Send_Right[JMAX*KMAX+1];
double Send_Top[IMAX*KMAX+1], Send_Bttm[IMAX*KMAX+1];
double Send_Frnt[IMAX*JMAX+1], Send_Rear[IMAX*JMAX+1];
double Recv_Left[JMAX*KMAX+1], Recv_Right[JMAX*KMAX+1];
double Recv_Top[IMAX*KMAX+1], Recv_Bttm[IMAX*KMAX+1];
double Recv_Frnt[IMAX*JMAX+1], Recv_Rear[IMAX*JMAX+1];
if(myranki!=X_div-1) {
cnt = 0;
for(j=jstart; j<=jend; j++) {
for(k=kstart; k<=kend; k++) {
Send_Right[cnt] = Send_Var[iend][j][k];
cnt = cnt+1;
}
}
}
if(myranki!=0) {
cnt = 0;
for(j=jstart; j<=jend; j++) {
for(k=kstart; k<=kend; k++) {
Send_Left[cnt] = Send_Var[istart][j][k];
cnt = cnt+1;
}
}
}
if(myrankj!=Y_div-1) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(k=kstart; k<=kend; k++) {
Send_Top[cnt] = Send_Var[i][jend][k];
cnt = cnt+1;
}
}
}
if(myrankj!=0) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(k=kstart; k<=kend; k++) {
Send_Bttm[cnt] = Send_Var[i][jstart][k];
cnt = cnt+1;
}
}
}
if(myrankk!=Z_div-1) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(j=jstart; j<=jend; j++) {
Send_Rear[cnt] = Send_Var[i][j][kend];
cnt = cnt+1;
}
}
}
if(myrankk!=0) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(j=jstart; j<=jend; j++) {
Send_Frnt[cnt] = Send_Var[i][j][kstart];
cnt = cnt+1;
}
}
}
cnt = 0;
i_face = j_length*k_length;
j_face = k_length*i_length;
k_face = i_length*j_length;
MPI_Isend(&Send_Right[cnt],i_face,MPI_DOUBLE,iup,1,MPI_COMM_WORLD,&isend1);
MPI_Isend(&Send_Left[cnt],i_face,MPI_DOUBLE,idown,1,MPI_COMM_WORLD,&isend2);
MPI_Isend(&Send_Top[cnt],j_face,MPI_DOUBLE,jup,1,MPI_COMM_WORLD,&jsend1);
MPI_Isend(&Send_Bttm[cnt],j_face,MPI_DOUBLE,jdown,1,MPI_COMM_WORLD,&jsend2);
MPI_Isend(&Send_Rear[cnt],k_face,MPI_DOUBLE,kup,1,MPI_COMM_WORLD,&ksend1);
MPI_Isend(&Send_Frnt[cnt],k_face,MPI_DOUBLE,kdown,1,MPI_COMM_WORLD,&ksend2);
MPI_Irecv(&Recv_Left[cnt],i_face,MPI_DOUBLE,idown,1,MPI_COMM_WORLD,&irecv1);
MPI_Irecv(&Recv_Right[cnt],i_face,MPI_DOUBLE,iup,1,MPI_COMM_WORLD,&irecv2);
MPI_Irecv(&Recv_Bttm[cnt],j_face,MPI_DOUBLE,jdown,1,MPI_COMM_WORLD,&jrecv1);
MPI_Irecv(&Recv_Top[cnt],j_face,MPI_DOUBLE,jup,1,MPI_COMM_WORLD,&jrecv2);
MPI_Irecv(&Recv_Frnt[cnt],k_face,MPI_DOUBLE,kdown,1,MPI_COMM_WORLD,&krecv1);
MPI_Irecv(&Recv_Rear[cnt],k_face,MPI_DOUBLE,kup,1,MPI_COMM_WORLD,&krecv2);
MPI_Wait(&isend1,&status);
MPI_Wait(&isend2,&status);
MPI_Wait(&jsend1,&status);
MPI_Wait(&jsend2,&status);
MPI_Wait(&ksend1,&status);
MPI_Wait(&ksend2,&status);
MPI_Wait(&irecv1,&status);
MPI_Wait(&irecv2,&status);
MPI_Wait(&jrecv1,&status);
MPI_Wait(&jrecv2,&status);
MPI_Wait(&krecv1,&status);
MPI_Wait(&krecv2,&status);
if(myranki!=0) {
cnt = 0;
for(j=jstart; j<=jend; j++) {
for(k=kstart; k<=kend; k++) {
Send_Var[istart-1][j][k] = Recv_Left[cnt];
cnt = cnt+1;
}
}
}
if(myranki!=X_div-1) {
cnt = 0;
for(j=jstart; j<=jend; j++) {
for(k=kstart; k<=kend; k++) {
Send_Var[iend+1][j][k] = Recv_Right[cnt];
cnt = cnt+1;
}
}
}
if(myrankj!=0) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(k=kstart; k<=kend; k++) {
Send_Var[i][jstart-1][k] = Recv_Bttm[cnt];
cnt = cnt+1;
}
}
}
if(myrankj!=Y_div-1) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(k=kstart; k<=kend; k++) {
Send_Var[i][jend+1][k] = Recv_Top[cnt];
cnt = cnt+1;
}
}
}
if(myrankk!=0) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(j=jstart; j<=jend; j++) {
Send_Var[i][j][kstart-1] = Recv_Frnt[cnt];
cnt = cnt+1;
}
}
}
if(myrankk!=Z_div-1) {
cnt = 0;
for(i=istart; i<=iend; i++) {
for(j=jstart; j<=jend; j++) {
Send_Var[i][j][kend+1] = Recv_Rear[cnt];
cnt = cnt+1;
}
}
}
}
#endif
void init() テスト変数1,2の初期化
{
#if DIM == 2
int i, j;
for(i=X_MIN; i<=X_MAX; i++) {
for(j=Y_MIN; j<=Y_MAX; j++) {
Test1[i][j] = 1.000000;
Test2[i][j] = 2.000000;
}
}
#elif DIM == 3
int i, j, k;
for(i=X_MIN; i<=X_MAX; i++) {
for(j=Y_MIN; j<=Y_MAX; j++) {
for(k=Z_MIN; k<=Z_MAX; k++) {
Test1[i][j][k] = 1.000000;
Test2[i][j][k] = 2.000000;
}
}
}
#endif
}
void Data_Shift_Ranking() 通信時間の最も速い、分割数の確保
{
#if DIM == 2
if(flag == 1){
min_shift_time = time_diff;
x_store = X_div;
y_store = Y_div;
flag = 0;
}
if(min_shift_time >= time_diff){
min_shift_time = time_diff;
x_store = X_div;
y_store = Y_div;
}
#elif DIM == 3
if(flag == 1){
min_shift_time = time_diff;
x_store = X_div;
y_store = Y_div;
z_store = Z_div;
flag = 0;
}
if(min_shift_time >= time_diff){
min_shift_time = time_diff;
x_store = X_div;
y_store = Y_div;
z_store = Z_div;
}
#endif
}
void Output2() 通信時間最小データの出力
{
#if DIM == 2
fprintf(filePnt1,"X_DIV %d \n",x_store);
fprintf(filePnt1,"Y_DIV %d \n",y_store);
#elif DIM == 3
fprintf(filePnt1,"X_DIV %d \n",x_store);
fprintf(filePnt1,"Y_DIV %d \n",y_store);
fprintf(filePnt1,"Z_DIV %d \n",z_store);
#endif
}