《并行程序设计导论》-MPI-教程05

《并行程序设计导论》第三章:

      用MPI进行分布式内存编程-教程05
              

并行归并排序参考答案:

/*	File:
 *		parallelMerge.c 
 *	
 *	Author:
 *		E2MCC 
 *
 *	Discription:
 *		implement merge sort by using parallel program.
 *
 *	Input:
 *		in.txt 
 *
 *	Output:
 *		out.txt	
*/

#include <stdio.h>
#include <string.h>
#include <mpi.h>
#include <stdlib.h> 

/*---Set Global Variables below-------------------------------*/
int my_rank = 0;
int comm_sz = 0;
MPI_Comm comm;

int keys_n = 0;//the totall number of input keys
float* keys_p = NULL;//only can be set by proc 0

int local_keys_n = 0;//the local keys number
float* local_keys_p = NULL;//the local keys

double local_time_start = 0;
double local_time_finish = 0;
double local_time_elapsed = 0;
double time_elapsed = 0; //only can be set by proc 0
/*---Set Global Variables above-------------------------------*/


void readKeys(void);
void scatterKeys(void);
void mergeSort(float* array, int l, int mid, int h);
void merge(float* array, int l, int h);
void pMergeSort(float* recv_keys_p,int recv_keys_n);
void getDestAndSource(int* dest_p,int* source_p,int local_peralleled);
void getSendOrRecv(int* send_or_recv_p,int proc_n,int new_rank);
void parallelMerge(void);
void output(void);

int main(int argc,int** argv){
	/*init MPI and proc relativable variable*/
	MPI_Init(NULL,NULL);
	comm = MPI_COMM_WORLD;
	MPI_Comm_size(comm,&comm_sz);
	MPI_Comm_rank(comm,&my_rank);
	/*--------------------------------------*/
	
	//input keys
	readKeys();
	
	/*---start time-------------------------*/
	MPI_Barrier(comm);
	local_time_start = MPI_Wtime();
	
	
	/*---------Scatter keys-----------------*/  
	scatterKeys();
	
	/*---------Merge------------------------*/
	parallelMerge();
	
	/*----------time----------------------*/
	local_time_finish = MPI_Wtime();
	local_time_elapsed = local_time_finish-local_time_start; 
	MPI_Reduce(&local_time_elapsed,&time_elapsed,1,MPI_DOUBLE,MPI_MAX,0,comm);
	if(my_rank==0){
		printf("the elapsed time is %e\n",time_elapsed);
	} 
	output();
	MPI_Finalize();
	return 0;	
}

/*input the original keys*/
void readKeys(void){
	if(my_rank==0){
		printf("RANK-%d of %d--->I will input keys from in.txt right now!\n",my_rank,comm_sz);
		FILE* file_p = NULL;
		file_p = fopen("in.txt","r");
		fscanf(file_p,"%d",&keys_n);
		keys_p = malloc(keys_n*sizeof(float));
		printf("Successfully set the keys_n = %d:\n",keys_n);
		int i = 0;
		for(i=0;i<keys_n;i++){
			fscanf(file_p,"%f",&(keys_p[i]));
		}
		fclose(file_p);
		printf("Read Keys Finished!\n");
	}
	MPI_Bcast(&keys_n,1,MPI_INT,0,comm);//let every process konw 
} 

//Scatter keys to all procs that is the in communicator
void scatterKeys(void){
	
	int quotient = keys_n/comm_sz;
	int remainder = keys_n%comm_sz;
	
	if(my_rank<remainder){
		local_keys_n = quotient+1;
	}else{
		local_keys_n = quotient;
	}
	local_keys_p = malloc(local_keys_n*sizeof(float));
	
	int* send_count_p = NULL;//array of send_count
	int* displs_p = NULL;//array of displs
	
	if(my_rank==0){
		send_count_p = malloc(comm_sz*sizeof(int));
		displs_p = malloc(comm_sz*sizeof(int));
		int offset = 0;
		int i = 0;
		for(i=0;i<comm_sz;i++){
			if(i<remainder){
				send_count_p[i] = quotient+1;
			}else{
				send_count_p[i] = quotient;
			}
			displs_p[i] = offset;
			offset = offset+send_count_p[i];	
		}		
	}
	MPI_Scatterv(keys_p,send_count_p,displs_p,MPI_FLOAT,
				local_keys_p,local_keys_n,MPI_FLOAT,0,comm);
	if(my_rank==0){
		free(send_count_p);
		free(displs_p);
	}
}

void mergeSort(float* array, int l, int mid, int h){
    //create 2 temp arrays to store keys 
	int	temp1_n = mid - l + 1;
    int temp2_n = h - mid;
    float* temp1 = malloc(temp1_n*sizeof(float));
    float* temp2 = malloc(temp2_n*sizeof(float));
    int i = 0;
    int j = 0;
    int k = l;
 	for(i=0; i < temp1_n; i++){
 		temp1[i] = array[l+i];
	}
	        
    for(j=0; j < temp2_n; j++){
    	temp2[j] = array[mid+1+j];
 	}
 	i=0;
 	j=0;
    while(i<temp1_n&& j<temp2_n){   
        //copy the miner one
        if(temp1[i] <= temp2[j]){
        	array[k] = temp1[i];
        	i++;
        	k++;
		}else{
        	array[k] = temp2[j];
        	j++;
        	k++;
		}
    }
    /*if there still are keys,just put them into array[] one by one*/
    while(i < temp1_n){
    	array[k] = temp1[i];
    	i++;
    	k++;
	}
    while(j < temp2_n){
    	array[k] = temp2[j];
    	j++;
    	k++;
	}    
    // free temp1 and temp2
    if (temp1!=NULL){
    	free(temp1);
    }
    if(temp2!=NULL){
    	free(temp2);
    }   
}

void merge(float* array, int l, int h){
    if(l<h){
        int mid = (l+h)/2;
        merge(array,l,mid);
        merge(array,mid+1,h);
        mergeSort(array,l,mid,h);
    }
}

void pMergeSort(float* recv_keys_p,int recv_keys_n){
	
	int temp_n = local_keys_n+recv_keys_n;
	float* temp_p = malloc(temp_n*sizeof(float));
	 
	int i = 0;
	int j = 0;
	int k = 0;
	
	while(i<local_keys_n&&j<recv_keys_n){
		if(local_keys_p[i]<=recv_keys_p[j]){
			temp_p[k] = local_keys_p[i];
			i++;
			k++;
		}else{
			temp_p[k] = recv_keys_p[j];
			j++;
			k++;
		}
	}
	
	while(i<local_keys_n){
		temp_p[k] = local_keys_p[i];
		i++;
		k++;
	}
	while(j<recv_keys_n){
		temp_p[k] = recv_keys_p[j];
		j++;
		k++;
	}
	
	//update local_keys
	local_keys_n = temp_n;
	float* f = local_keys_p;
	local_keys_p = temp_p;
	free(f);
}
/*----------------------------------------------------------------*/

/*the process who calls this function get his partner rank including dest and source partner rank*/
void getDestAndSource(int* dest_p			/*out*/,
					int* source_p			/*out*/,
					int local_peralleled	/*in*/){
	
	*source_p = MPI_ANY_SOURCE; 
	int interval = 1;//set the interval between 2 adjacent process
	interval<<=local_peralleled;
	*dest_p = my_rank-interval;
	if(*dest_p<0){ 
		if(my_rank!=0){
			*dest_p = 0;
		}else{
			*dest_p = MPI_PROC_NULL;
		} 
	} 
} 
/*---------------------------------------------------------------*/

/*--------------------------------------------------------------*/
/*function:should this proc send or recieve data?	0 means recv;1 means send*/
void getSendOrRecv(int* send_or_recv_p		/*out*/,
					int proc_n				/*in*/,
					int new_rank			/*in*/){
	if(proc_n%2==0){//if communicator has even process
		if(new_rank%2==1){//if new_rank is odd
			*send_or_recv_p = 1;//this process should send
		}else{ 
			send_or_recv_p = 0;//this process should recv
		}
	}else{
		if(new_rank%2==1){
			*send_or_recv_p = 0;//should recv
		}else{
			*send_or_recv_p = 1;//should send
		}
	}
} 
/*------------------------------------------------------------*/

void parallelMerge(void){	
	
	int recv_keys_n = 0;
	float* recv_keys_p = NULL;
	
	/*func:At first , merge process's local-keys*/
	merge(local_keys_p,0,local_keys_n-1);

	int dest = 0;
	int source = 0; 
	int send_or_recv = 0;//0 means recv;1 means send 
	
	//how many times this process who calls parallelMerge has paralleled
	int local_paralleled = 0;
	
	/*--set new rank--*/
	int new_rank = my_rank;
	int quotient = 0;
	int remainder = 0;
	
	int sleep = 0; 
	int proc_n = comm_sz;
	while(proc_n>1){
		if(my_rank==0){
			if(proc_n%2==0){
				sleep=0;
			}else{
				sleep=1;
			}
		} 
		
		if(sleep==0){ 
			getSendOrRecv(&send_or_recv,proc_n,new_rank);	 
			getDestAndSource(&dest,&source,local_paralleled);
			if(send_or_recv==1){
				MPI_Send(&local_keys_n,1,MPI_INT,dest,0,comm);
				MPI_Send(local_keys_p,local_keys_n,MPI_FLOAT,dest,1,comm);
				sleep = 1;	
			}else{
				MPI_Recv(&recv_keys_n,1,MPI_INT,source,0,comm,MPI_STATUS_IGNORE);
				recv_keys_p = malloc(recv_keys_n*sizeof(float));
				MPI_Recv(recv_keys_p,recv_keys_n,MPI_FLOAT,source,1,comm,MPI_STATUS_IGNORE);
				pMergeSort(recv_keys_p,recv_keys_n);	
				free(recv_keys_p);
				local_paralleled++;			
			}
		}
		
		if(my_rank==0){
			if(proc_n%2==0){
				proc_n = proc_n/2;
			}else{
				proc_n = (proc_n-1)/2+1;
			}			
		}
		MPI_Bcast(&proc_n,1,MPI_INT,0,comm);
				
		/*it's time to renew the new_rank after we just renew the proc_n*/
		quotient = new_rank/2;
		remainder = new_rank%2;
		new_rank = quotient+remainder;
	}	
}

void output(void){
	if(my_rank==0){
		FILE* fp = NULL;
		fp = fopen("out.txt","w+");
		int i  = 0;
		for(i=0;i<local_keys_n;i++){
			fprintf(fp,"%.1f ",local_keys_p[i]);			
		}
		fclose(fp);
	}	 
}



  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值