In this assignment you will write, and compare, several sorting programs. You will write two sequential sorting programs and two parallel sorting programs.
This assignment is due Tuesday, April 20.
First, write a single threaded C program that implements insertion sort. The main() function of your program should take a command line parameter n and allocate an array of n integers. Then the function should enter a loop that generates n random integers (using the full range of the C Standard Library's rand() function, that is, from 0 to RAND_MAX ) and "inserts" each random integer into the array so that the array is always sorted. This program will be a baseline that you can compare other sorting programs with.
Write a second single threaded C program that uses the C Standard Library's qsort()
function to sort an array of integers. This program's main() function should take a command line parameter n and allocate an array of n integers. Then the function should fill the array with n random integers (using the full range of the C Standard Library's rand() function). Then call the qsort() function to sort the array.
Now write a parallel version of insertion sort. Write an MPI program that runs with p processes. The MPI program has a single command line parameter n . When the program finishes, it will have sorted n randomly generated integers and each of the p processes will hold n/p of the integers. Here is a description of the algorithm.
Each process should allocate a buffer that can hold n/p integers (assume that p divides n ).
The process with rank 0 should have a loop that generates n random integers (using the full range of the C Standard Library's rand() function). For the first n/p integers, the root process should just insert them into its buffer (of size n/p ) so that the buffer is always sorted. For the next n-n/p integers, the root process should insert the new random integer in its buffer, if the number is less than the current maximum number in the buffer, and the root process should also send one integer to the process with rank 1.
The process with rank 1 should have a loop that iterates n-n/p times. For each iterate of the loop, the process should receive one integer from the process with rank 0. For the first n/p iterates, the process with rank 1 should insert the received integer in its buffer (of size n/p ) so that the buffer is always sorted. For the next n-2(n/p) integers, the process with rank 1 should insert the received integer in its buffer, if the number is less than the current maximum number in the buffer, and the process should also send one integer to the process with rank 2.
The processes with ranks 2 through p-2 should behave similarly to the process with rank 1.
The processes with rank p-1 should have a loop that iterates n/p times. For each iterate of the loop, the process should receive one integer from the process with rank p-2 and the process should insert the integer in its buffer (of size n/p ) so that the buffer is always sorted.
|
Write a parallel version of quicksort. Write an MPI program that runs with p processes. For this algorithm we will assume that p is a power of 2. The MPI program has a single command line parameter n . When the program finishes, it will have sorted n randomly generated integers and each of the p processes will hold approximately n/p of the integers. Here is an outline of the algorithm.
Each process should allocate a buffer that can hold n/p integers and each process should begin by filling its buffer with n/p random integers.
The algorithm does a series of log(p) rounds of choosing a pivot and exchanging data between processes.
For the first round, one pivot is needed and it should be RAND_MAX/2 . In the first round, each of the p processes use the pivot value to partition the integers from its buffer into two subsets, one subset of integers less than or equal to the pivot, and one subset of integers greater than the pivot. After this partitioning, processes with ranks greater than or equal to p/2 will send their lower subset to processes with ranks less than p/2 . And processes with ranks less than p/2 will send their higher subset to processes with ranks greater than or equal to p/2 .
For the second round, two pivots are needed. Use pivots RAND_MAX/4 and 3*RAND_MAX/4 . Process with ranks less than p/2 will use pivot RAND_MAX/4 , and processes with ranks greater than or equal to p/2 will use pivot RAND_MAX/4 . After each process uses a pivot to partition its buffer, the process with ranks less than p/2 will exchange data, and the process with ranks greater than or equal to p/2 will exchange data.
For the k 'th round, 2^(k-1) pivots are needed. You get the 2^(k-1) pivots by adding and subtracting RAND_MAX/(2^k) from each of the 2^(k-2) pivots from the k-1 'th round. (This is not the usual way to choose pivots in quicksort. But since our unsorted data are random integers uniformly distributed between 0 and RAND_MAX , it seems like a good idea to have the pivots be uniformly spaced between 0 and RAND_MAX .)
After the log(p) rounds of pivoting and exchanging data, each process holds an unsorted array of random integers that are disjoint from all of the other processes. That is, all the integers held by process k are larger than the integers held by process k-1 and less than the integers held by process k+1 . (NOTE: Unfortunately, not all of the processes will hold the same number of integers, some will hold more than n/p and some will hold less.) To complete the sorting of all of the integers, each process calls the C Standard Library function qsort() to sort its buffer of integers.
|
After you have written these four sorting programs, run them on the Falcon cluster to see how they scale. For the two sequential programs, see how they scale as a function of n . For the two parallel programs, see how they scale both as a function of n and as a function of p .
Turn in a zip file containing your four sorting programs along with your analysis of their scaling properties.
This assignment is due Tuesday, April 20.
|