#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FILEPATH "/home/mpiuser/myprojects/mydata/sort_round.txt"
#define length 50000000
int isFileExisted(const char *pathname){
if(access(pathname,F_OK) == 0){
return true;
}
return false;
}
void makeDirectory(const char *path){
if((strcmp(path,".") == 0) || (strcmp(path,"/")==0))
return ;
if(isFileExisted(path))
return ;
else{
char *duppath = strdup(path);
const char *dir_name = dirname(duppath);
makeDirectory(dir_name);
free(duppath);
}
if(mkdir(path,0766) < 0){
perror("mkdir");
exit(1);
}
return;
}
int isFileNull(const char *filename){
FILE *fp = fopen(filename,"r");
if(fp == NULL)
return -1;
int val = 0;
char ch = fgetc(fp);
if(ch == EOF)
val = 1;
fclose(fp);
return val;
}
void swap(int *data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
int partition(int *data, int start, int end) {
if (start >= end) return 0;
int pivotValue = data[start];
int low = start;
int high = end - 1;
while (low < high) {
while (data[low] <= pivotValue && low < end) low++;
while (data[high] > pivotValue && high > start) high--;
if (low < high) swap(data, low, high);
}
swap(data, start, high);
return high;
}
void quicksort(int *data, int start, int end) {
if (end-start+1 < 2) return;
int pivot = partition(data, start, end);
quicksort(data, start, pivot);
quicksort(data, pivot+1, end);
}
void mergesort(int *data, int blocklen,int len){
int *tmp = (int*)malloc(sizeof(int)*len);
int left = 0;
int right = blocklen;
int i = 0;
while(left < blocklen&&right < len){
if(data[left] < data[right]){
tmp[i++] = data[left++];
}
else{
tmp[i++] = data[right++];
}
}
while(left < blocklen){
tmp[i++] = data[left++];
}
while(right < len){
tmp[i++] = data[right++];
}
for(int j = 0; j < len; j++){
data[j] = tmp[j];
}
}
void saveData(int *data,int blocklen,int len,int roundID){
char openfile[100];
sprintf(openfile,"/home/mpiuser/myprojects/mydata/sort_round.txt");
printf("正在将排序结果保存到%s中\n",openfile);
FILE *fpWrite = fopen(openfile,"w");
if(fpWrite==NULL)
{
return;
}
int k = 0;
fprintf(fpWrite,"%d ", blocklen);
for(int i = 0; i < len; i++){
fprintf(fpWrite,"%d ",data[i]);
k++;
}
printf("总共保存了%d条数据\n",k);
fclose(fpWrite);
printf("已成功保存第%d轮的排序结果\n",roundID);
}
int loadLastStatus(int * data,int* blocklen){
FILE *fpRead = fopen(FILEPATH,"r");
int i = -1;
int tmp = 0;
*blocklen = 0;
if(fpRead==NULL)
{
return 0;
}
else
{
while(!feof(fpRead)){
char c = fgetc(fpRead);
if(c == '\n'|| c == ' '){
if(i != -1){
data[i] = tmp;
tmp = 0;
}
i++;
continue;
}
if(i == -1){
*blocklen *= 10;
*blocklen += c - '0';
}
else{
tmp *= 10;
tmp += c - '0';
}
}
}
fclose(fpRead);
printf("总共读到了%d条数据\n",i);
return 0;
}
int main(int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int rank, size;
int namelen;
MPI_Request handle;
char processor_name[MPI_MAX_PROCESSOR_NAME];
double startwtime,endwtime;
MPI_Comm_rank (MPI_COMM_WORLD, &rank);
MPI_Comm_size (MPI_COMM_WORLD, &size);
MPI_Get_processor_name(processor_name, &namelen);
fprintf(stdout, "Process %d of %d is on %s\n", rank, size, processor_name);
fflush(stdout);
srand(time(0));
int *data = (int*)malloc(sizeof(int)*length);
int i;
int blocklen = length/(size-1);
int isContinue_last = 0;
if(rank != size-1){
char openfile[100];
sprintf(openfile,"/home/mpiuser/myprojects/mydata/sort_round.txt");
if(isFileExisted(openfile)){
printf("%s文件已存在(%s)\n",openfile,processor_name);
isContinue_last = 1;
}
else{
printf("%s文件不存在(%s)\n",openfile,processor_name);
}
}
MPI_Status status;
if (rank == 0) {
int readID = -1;
int localread = 0;
if(isContinue_last == 1){
localread = 1;
}
printf("Processor %d 开始接收其它进程的检查结果,验证上一轮程序是否发生异常\n",rank);
for(int i = 1; i < size-1; i++){
int tmp_last = 0;
MPI_Recv(&tmp_last,1,MPI_INT,i, 0, MPI_COMM_WORLD,&status);
if(tmp_last > isContinue_last){
isContinue_last = tmp_last;
readID = i;
}
}
if(isContinue_last == 1){
printf("上一轮程序存在异常,需要重启\n");
}
else{
printf("上一轮程序不存在异常,不需要重启\n");
}
if(localread == 1){
if(isContinue_last == 0)
readID = -1;
else
readID = 0;
}
printf("Processor %d 广播读取上一轮程序中间结果的进程ID\n",rank);
for(int i = 1; i < size-1; i++){
MPI_Send(&readID,1,MPI_INT,i,0,MPI_COMM_WORLD);
}
int nextstart = blocklen;
if(localread == 1){
printf("Processor %d 开始加载上一轮程序的中间结果\n",rank);
loadLastStatus(data,&blocklen);
printf("Processor %d 已成功加载上一轮程序的中间结果\n",rank);
nextstart = blocklen;
for(int i = 0; i < size-1; i++){
if(i != rank){
MPI_Send(&blocklen,1,MPI_INT,i,0,MPI_COMM_WORLD);
printf("Processor %d 已成功分发上一轮程序的中间结果给Processor %d \n",rank,i);
nextstart += blocklen;
}
}
}
else if(readID != -1){
MPI_Recv(&blocklen,1,MPI_INT,readID,0,MPI_COMM_WORLD,&status);
MPI_Recv(data,length,MPI_INT,readID,0,MPI_COMM_WORLD,&status);
}
else{
printf("上一轮程序无异常,%d正在重新生成数据\n",rank);
for (i=0; i<blocklen; i++)
data[i] = rand()%length;
}
int maxSendNum = (int)log2(size-1);
startwtime = MPI_Wtime();
if(isContinue_last == 0){
quicksort(data, 0, blocklen);
printf("*********************************\n当前总进程数为:%d\n排序的数据量为:%d\n*********************************\n",size,length);
for (i=1; i < size-1; i++)
MPI_Recv(data+i*blocklen, blocklen, MPI_INT, i, 0, MPI_COMM_WORLD, &status);
printf("局部快排之后:\n");
for(int i = 0; i < length; i += 500000){
printf("%d ",data[i]);
}
printf("\n");
printf("当前主进程需要循环发送%d次\n",maxSendNum);
for(int i = 1; i < size; i++){
MPI_Send(&maxSendNum, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
}
}
else{
printf("*********************************\n当前总进程数为:%d\n排序的数据量为:%d\n*********************************\n",size,length);
printf("读取异常程序的中间数据之后,blocklen = %d:\n",blocklen);
for(int i = 0; i < length; i++){
if(i % 50000 == 0)
printf("%d ",data[i]);
if(i > 0 && data[i] < data[i-1])
printf("\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$出现一次断点:data[%d]=%d < data[%d]=%d$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n",i,data[i],i-1,data[i-1]);
}
printf("\n");
maxSendNum -= log2(blocklen/(length/(size-1)));
printf("当前主进程需要循环发送%d次\n",maxSendNum);
for(int i = 1; i < size; i++){
MPI_Send(&maxSendNum, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
}
}
int t = 0;
while(maxSendNum--){
blocklen *= 2;
nextstart = 0;
int sendNUM = length / blocklen;
printf("当前需要%d个子进程进行归并排序\n",sendNUM);
for(int j = 1; j < size-1; j++){
MPI_Send(&sendNUM, 1, MPI_INT, j, 2, MPI_COMM_WORLD);
}
for(int i = 1; i < size-1; i++){
printf("主进程正在发送数据给%d进程...\n",i);
MPI_Send(data+nextstart, blocklen, MPI_INT, i, 3, MPI_COMM_WORLD);
printf("主进程已发送数据给%d进程!!!\n",i);
nextstart += blocklen;
if(nextstart >= length){
break;
}
}
for (i=0; i<sendNUM; i++)
MPI_Recv(data+i*blocklen, blocklen, MPI_INT, i+1, 4, MPI_COMM_WORLD, &status);
printf("-----------------------\n已完成一轮归并,告知进程%d...\n",size-1);
saveData(data, blocklen, length, t+1);
t++;
int flag = 1;
MPI_Send(&flag,1,MPI_INT,size-1,5,MPI_COMM_WORLD);
printf("进程%d已重新计时,开启下一轮排序...\n-----------------------\n",size-1);
}
printf("主进程进行最后的归并排序...\n");
if(blocklen < length){
mergesort(data,blocklen,length);
}
}
else if(rank == size-1){
printf("*********************************\nProcessor %d 用于计时\n*********************************\n",rank);
int maxRecvNUM,flag2 = 0;
MPI_Request request2;
MPI_Recv(&maxRecvNUM, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
double startwtime = MPI_Wtime();
double endwtime;
int flag = 0;
int secondtime = 0;
while(maxRecvNUM--){
flag = 0;
flag2 = 0;
MPI_Irecv(&flag2, 1, MPI_INT, 0, 5, MPI_COMM_WORLD, &request2);
while(flag == 0 || flag2 == 0){
printf("*********************************\n正在等待进程完成当前轮次的归并排序...%d s\n*********************************\n",secondtime);
sleep(2);
secondtime+=2;
MPI_Test(&request2, &flag, &status);
if(secondtime > 120){
printf("执行超时,退出运行!\n");
MPI_Abort(MPI_COMM_WORLD,1);
}
}
secondtime = 0;
endwtime = MPI_Wtime();
}
}
else {
int readID = -1;
MPI_Send(&isContinue_last,1,MPI_INT,0,0,MPI_COMM_WORLD);
MPI_Recv(&readID,1,MPI_INT, 0, 0, MPI_COMM_WORLD,&status);
printf("Processor %d 已接收到需要读取上一轮程序的进程ID为:%d\n",rank,readID);
if(readID == rank){
printf("Processor %d 开始加载上一轮程序的中间结果并分发程序状态\n",rank);
int nextstart = blocklen;
loadLastStatus(data,&blocklen);
printf("Processor %d 已成功加载上一轮程序的中间结果\n",rank);
for(int i = 0; i < size-1; i++){
if(i != rank){
MPI_Send(&blocklen,1,MPI_INT,i,0,MPI_COMM_WORLD);
}
}
MPI_Send(data, length, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
else if(readID != -1){
printf("Processor %d 正在接收来自Processor %d分发的上一轮异常程序状态\n",rank,readID);
MPI_Recv(&blocklen,1,MPI_INT,readID,0,MPI_COMM_WORLD,&status);
}
else{
printf("上一轮程序无异常,%d正在重新生成数据\n",rank);
for (i=0; i<blocklen; i++)
data[i] = rand()%length;
quicksort(data, 0, blocklen);
MPI_Send(data, blocklen, MPI_INT, 0, 0, MPI_COMM_WORLD);
}
int maxRecvNUM,maxRunID;
MPI_Recv(&maxRecvNUM, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
printf("子进程%d得知需要循环%d次\n",rank,maxRecvNUM);
while(maxRecvNUM--){
MPI_Recv(&maxRunID, 1, MPI_INT, 0, 2, MPI_COMM_WORLD, &status);
if(maxRunID >= rank){
printf("子进程%d得知自己有任务,准备接收数据...\n",rank);
MPI_Recv(data, blocklen*2, MPI_INT, 0, 3, MPI_COMM_WORLD, &status);
printf("子进程%d已接受数据,开始归并排序...\n",rank);
double starttime = MPI_Wtime();
mergesort(data,blocklen,blocklen*2);
double endtime = MPI_Wtime();
blocklen*=2;
printf("子进程%d归并排序完毕,用时%f s,将数据发回主进程...\n",rank,endtime-starttime);
MPI_Send(data, blocklen, MPI_INT, 0, 4, MPI_COMM_WORLD);
}
else{
printf("子进程%d已收到通知,但不是自己的任务\n",rank);
}
}
}
if (rank == 0)
{
int jud = 1;
endwtime = MPI_Wtime();
for(int i = 0; i < length; i++){
if(i > 0&&data[i]<data[i-1]){
printf("data[%d] = %d < data[%d] = %d排序失败!!!\n",i,data[i],i-1,data[i-1]);
jud = 0;
}
if(i % 500000 == 0){
printf("%d ",data[i]);
}
}
double time = endwtime - startwtime;
if(jud == 1){
printf("\n*********************************\n排序成功!!!\nTime: %f s\n*********************************\n", time);
remove(FILEPATH);
printf("已成功删除中间结果文件\n");
}
}
MPI_Finalize();
return 0;
}