/****************************************************************** * * Uebungen zu "Parallele und verteilte Algorithmen" * SS 2007 * * Zu Aufgabe 5.3: Odd-Even-Transposition Sort * *******************************************************************/ #include "mpi.h" #include // INT_MAX #include #include #include #define LIMIT 1023 // Message-Tags #define FROMLEFT 1 #define FROMRIGHT 2 // debugging: #ifdef OUTPUT # define DEBUG(s, arg) printf("%d" s "\n",rank, arg) #else # define DEBUG(s,arg) /* Nothing */ #endif // Globale Variablen: int size; // MPI int rank; // MPI // shutdown in case of errors void error_exit(char* message) { fprintf(stderr,"[%x] Fehler: %s\n", rank, message); MPI_Finalize(); // MPI verlassen exit(-1); // mit Fehler terminieren } // Exchange the contents of * X and * Y . void Swap (int* X, int* Y) { int Save; Save = * X; * X = * Y; * Y = Save; return; } // Swap // Sort array A [0 .. (N-1)] with bubblesort void Sort (int* A, int N) { int i, j; for (i = 0; i < N - 1; i ++) for (j = 0; j < N - i - 1; j ++) if (A [j] > A [j + 1]) // wrong order Swap (& A [j], & A [j + 1]); return; } // Sort // merge sorted arrays A and B into result (must be allocated!) void Merge(int* A, int a_size, int* B, int b_size, int* result) { int ai=0,bi=0,ri=0; while (ai < a_size && bi < b_size) { if (A[ai] < B[bi]) result[ri++] = A[ai++]; else result[ri++] = B[bi++]; } if (ai==a_size) memcpy(result+ri, B+bi, sizeof(int)*(b_size-bi)); else memcpy(result+ri, A+ai, sizeof(int)*(a_size-ai)); return; } // fill array with n random elements between 0 and LIMIT void fillRnd(int* array, int n) { srand((unsigned) array); // :-) while (n) { array[--n] = rand() & LIMIT; } return; } void ArrayOutput(int* array, int size) { int j; printf("array:["); for ( j = 0; j < size; j++) { printf("%d%s", array[j], j==size-1?"]\n":", "); } } int main(int argc, char** argv) { int nElements; int addElements; int* numbers, *numbers2; int iteration; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); DEBUG("Process starting, size is %d",size); nElements = argc>1? atoi(argv[1]): // arg. 1 gives no. of elements size*20; // or use default if (!rank) { printf("Sorting %d random numbers with OET-Sort\n", nElements); } // ensure that nElements can be divided without problems addElements = nElements % size; if (addElements) // need correction? addElements = size - addElements; nElements += addElements; // additional elements could be initialized LIMIT+1, and removed // from last process after sorting (here: random values anyway) // now start nElements /= size; // local no. of elements // allocate additional space for exchange numbers = (int*) malloc(sizeof(int)*2*nElements); // fill with values (only first half) fillRnd(numbers, nElements); DEBUG("array created", NULL); #ifdef OUTPUT if (!rank) { numbers2 = (int*) malloc(sizeof(int)*size*nElements); } MPI_Gather(numbers, nElements, MPI_INT, numbers2, nElements, MPI_INT, 0, MPI_COMM_WORLD); if (!rank) { ArrayOutput(numbers2, size*nElements); free(numbers2); } #else // sync MPI_Barrier(MPI_COMM_WORLD); #endif // local sort Sort(numbers,nElements); DEBUG("array sorted", NULL); // allocate space to receive and merge numbers2 = (int*) malloc(sizeof(int)*2*nElements); // iterate OET iteration = 0; while (iteration < size) { DEBUG("Iteration %d",iteration); // send to left, receive from left if (((iteration++) + rank) & 1) { // odd iteration, or odd rank, not both if (rank-1 >=0) { // neighbour exists DEBUG("Sending/Receiving array", NULL); // send, then receive MPI_Send(numbers,nElements, MPI_INT, rank-1, FROMLEFT, MPI_COMM_WORLD); MPI_Recv(numbers, nElements, MPI_INT, rank-1, FROMRIGHT, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } } else { if (rank+1 < size) { // neighbour exists int* pointer; DEBUG("Receiving/Merging/Sending array", NULL); // receive (smaller values from neighbour) MPI_Recv(numbers+nElements, nElements, MPI_INT, rank+1, FROMLEFT, MPI_COMM_WORLD, MPI_STATUS_IGNORE); // merge into own list Merge(numbers,nElements,numbers+nElements,nElements, numbers2); // send back higher half MPI_Send(numbers2+nElements, nElements, MPI_INT, rank+1, FROMRIGHT, MPI_COMM_WORLD); // swap array roles pointer = numbers2; numbers2 = numbers; numbers = pointer; } } } printf("%d: done\n", rank); #ifdef OUTPUT if (!rank) { realloc(numbers2, sizeof(int)*nElements*size); } MPI_Gather(numbers,nElements, MPI_INT, numbers2, nElements, MPI_INT, 0, MPI_COMM_WORLD); if (!rank) { ArrayOutput(numbers2, size*nElements); } #endif // free allocated memory free(numbers); free(numbers2); MPI_Finalize(); }