diff --git a/bucket.c b/bucket.c new file mode 100644 index 0000000000000000000000000000000000000000..559c3eb21d9a4a04ff57c050f0d291d7802ae2f9 --- /dev/null +++ b/bucket.c @@ -0,0 +1,164 @@ +#include <stdio.h> +#include <stdint.h> +#include <mpi.h> +#include <time.h> +#include <stdlib.h> +#include <assert.h> + + +int *create_rand_nums(int num_elements, int max_value) { + int *rand_nums = malloc(sizeof(int) * num_elements); + assert(rand_nums != NULL); + int i; + for (i = 0; i < num_elements; ++i) { + rand_nums[i] = (rand() % (max_value+1)); + } + return rand_nums; +} + +void swap(int *a, int *b) { + int c = *a; + *a = *b; + *b = c; +} + +void sort(int *arr, int arr_size) { + int i, j; + for (i = 0; i < arr_size; ++i) { + for (j = i+1; j < arr_size; ++j) { + if (arr[i] > arr[j]) swap(arr+i, arr+j); + } + } +} + +int main(int argc, char *argv[]) { + int send_tag = 0, head_tag = 1, done_tag = 2, root = 0; + if (argc != 2) { + fprintf(stderr, "Usage: ./bucket [NUM_ELEMENTS]"); + exit(1); + } + + int num_elements = atoi(argv[1]); + int min_value = 0; + int max_value = num_elements; + srand(time(NULL)); + + MPI_Init(NULL, NULL); + + int world_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + double start_time = 0.0, end_time = 0.0; + if (world_rank == root) { + fprintf(stderr, "Starting root process\n"); + int i; + int *arr = create_rand_nums(num_elements, max_value); + assert(world_size > 0); + int range = max_value/world_size+1; + assert(range > 0); + + fprintf(stdout, "Original Array\n"); + for (i = 0 ; i < num_elements; ++i) { + fprintf(stdout, "%d ", arr[i]); + } + fprintf(stdout, "\n"); + + start_time = MPI_Wtime(); + int *quantity = malloc(sizeof(int) * world_size); + for (i = 0; i < world_size; ++i) quantity[i] = 0; + for (i = 0; i < num_elements; ++i) { + int index = arr[i] / range; + quantity[index]++; + } + + for (i = 1; i < world_size; ++i) { + MPI_Send(quantity+i, 1, MPI_INT, i, head_tag, MPI_COMM_WORLD); + fprintf(stderr, "Sending header %d to process %d\n", quantity[i], i); + } + fprintf(stderr, "Done sending header\n"); + int *buck = malloc(sizeof(int) * quantity[root]); + int *recv_count = malloc(sizeof(int) * world_size); + recv_count[root] = 0; + for (i = 0; i+1 < world_size; ++i) { + recv_count[i+1] = recv_count[i] + quantity[i]; + } + + for (i = 0; i < num_elements; ++i) { + int index = arr[i] / range; + assert(index < world_size); + if (index > 0) { + MPI_Send(arr+i, 1, MPI_INT, index, send_tag, MPI_COMM_WORLD); + fprintf(stderr, "Sending value %d to process %d (%d/%d)\n", arr[i], index, i+1, num_elements); + } + else { + *(buck+recv_count[root]) = arr[i]; + recv_count[root]++; + } + } + fprintf(stderr, "Done sending array\n"); + sort(buck, quantity[root]); + + MPI_Status Stat; + for (i = 0; i < num_elements; ++i) { + if (i < quantity[root]) arr[i] = buck[i]; + else arr[i] = 0; + } + for (i = 0; i < num_elements-quantity[root]; ++i) { + int el; + fprintf(stderr, "Root waiting for messages (%d/%d)\n", i+1, num_elements); + MPI_Recv(&el, 1, MPI_INT, MPI_ANY_SOURCE, done_tag, MPI_COMM_WORLD, &Stat); + + int index = Stat.MPI_SOURCE; + assert(index > 0); + fprintf(stderr, "Received message %d from %d, put at %d\n", el, index, index*range+recv_count[index]); + arr[recv_count[index]] = el; + recv_count[index]++; + } + end_time = MPI_Wtime(); + + fprintf(stdout, "Sorted Array\n"); + for (i = 0; i < num_elements; ++i) { + fprintf(stdout, "%d", arr[i]); + if (i+1 < num_elements) + fprintf(stdout, " "); + } + fprintf(stdout, "\n"); + + fprintf(stdout, "Bucket Sort Done in %lfs\n", end_time - start_time); + free(arr); + free(buck); + free(quantity); + free(recv_count); + } + else { + int quantity; + int i; + MPI_Status Stat; + fprintf(stderr, "Starting process %d\n", world_rank); + fprintf(stderr, "Process %d is waiting for header\n", world_rank); + MPI_Recv(&quantity, 1, MPI_INT, 0, head_tag, MPI_COMM_WORLD, &Stat); + fprintf(stderr, "Process %d receive header %d\n", world_rank, quantity); + int *arr = malloc(sizeof(int) * quantity); + for (i = 0; i < quantity; ++i) { + fprintf(stderr, "Process %d waiting for value (%d/%d)\n", world_rank, i+1, quantity); + MPI_Recv(arr+i, 1, MPI_INT, 0, send_tag, MPI_COMM_WORLD, &Stat); + fprintf(stderr, "Process %d receive value %d\n", world_rank, arr[i]); + } + + // SORT + sort(arr, quantity); + // DONE SORT + fprintf(stderr, "Sorted array at process %d\n", world_rank); + for (i = 0; i < quantity; ++i) { + fprintf(stderr, "%d", arr[i]); + if (i+1 < quantity) fprintf(stderr, " "); + MPI_Send(arr+i, 1, MPI_INT, 0, done_tag, MPI_COMM_WORLD); + } + fprintf(stderr, "\n"); + free(arr); + } + + MPI_Finalize(); +} diff --git a/laporan.pdf b/laporan.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6a6162bebf7ae75e0beebf99dc6a4c07f95f0b7 Binary files /dev/null and b/laporan.pdf differ diff --git a/mpi_hostfile b/mpi_hostfile new file mode 100644 index 0000000000000000000000000000000000000000..0f5cc5d494715512210416a9a428a5ea459c4f1c --- /dev/null +++ b/mpi_hostfile @@ -0,0 +1,6 @@ +localhost +167.205.35.26 +167.205.35.28 +167.205.35.29 +167.205.35.30 +167.205.35.31