diff --git a/assignments/02/.clangd b/assignments/02/.clangd index 26c50d3..d81ad1a 100644 --- a/assignments/02/.clangd +++ b/assignments/02/.clangd @@ -1,2 +1,2 @@ CompileFlags: - Add: -I/usr/lib/aarch64-linux-gnu/openmpi/include -I/usr/lib/aarch64-linux-gnu/openmpi/include/openmpi \ No newline at end of file + Add: -I/usr/lib/aarch64-linux-gnu/openmpi/include -I/usr/lib/aarch64-linux-gnu/openmpi/include/openmpi diff --git a/assignments/02/.gitignore b/assignments/02/.gitignore index 63654be..acc2ba1 100644 --- a/assignments/02/.gitignore +++ b/assignments/02/.gitignore @@ -1,2 +1,4 @@ qs_mpi -*.o \ No newline at end of file +*.o +compile_commands.json +.cache \ No newline at end of file diff --git a/assignments/02/Makefile b/assignments/02/Makefile index 2053b2b..d6919cd 100644 --- a/assignments/02/Makefile +++ b/assignments/02/Makefile @@ -11,7 +11,7 @@ LDFLAGS += $(shell pkg-config --libs mpi) all: qs_mpi qs_mpi: qs_mpi.o - $(CC) $(LDFLAGS) -o $@ $^ + $(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@ qs_mpi.o: qs_mpi.c $(CC) $(CFLAGS) -c -o $@ $^ diff --git a/assignments/02/output.txt b/assignments/02/output.txt new file mode 100644 index 0000000..e69de29 diff --git a/assignments/02/qs_mpi.c b/assignments/02/qs_mpi.c index bb8adaf..01a66fd 100644 --- a/assignments/02/qs_mpi.c +++ b/assignments/02/qs_mpi.c @@ -1,6 +1,134 @@ #include +#include +#include + +void local_quicksort(int *arr, int lo, int hi); +char *string_of_list(int *arr, int len); int main(int argc, char **argv) { - // + int rank, p; MPI_Init(&argc, &argv); + + int n = atoi(argv[1]); + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &p); + + // Generate integers + int n_over_p = n / p; + int integers[n_over_p]; + + // Important implementation detail: srand(0) is specially handled by glibc to + // behave as if it was called with srand(1). To get around this, I'm seeding + // with rank + 1 + // + // See more: https://stackoverflow.com/a/27386563 + srand(rank + 1); + + for (int i = 0; i < n_over_p; ++i) { + // TODO: For readability during debugging, I'm capping this + integers[i] = rand() % 101; + // printf(" - %d\n", integers[i]); + } + + int group_root = 0; + + // Locally sort + printf("[%d] Numbers before: %s\n", rank, + string_of_list(integers, n_over_p)); + local_quicksort(integers, 0, n_over_p); + printf("[%d] Numbers after first sort: %s\n", rank, + string_of_list(integers, n_over_p)); + + // Select a pivot. + // This pivot is broadcasted to all nodes + int pivot; + + // The pivot is selected as the median (see chp. 9.4.4) + // Not the real median though, need an existing element of the array + pivot = integers[n_over_p / 2]; + MPI_Bcast(&pivot, 1, MPI_INT, 0, MPI_COMM_WORLD); + + printf("Median: %d\n", pivot); + + // Determine where the boundary between S (lower) and L (higher) lies + int boundary; + for (int i = 0; i < n_over_p; ++i) { + if (integers[i] >= pivot) { + boundary = i; + break; + } + } + int S_lo = 0, S_hi = boundary - 1; + int L_lo = boundary, L_hi = n_over_p - 1; + int S_size = S_hi - S_lo + 1, L_size = L_hi - L_lo + 1; + // printf("[%d] S: [%d - %d] (%d), L: [%d - %d] (%d)\n", rank, S_lo, S_hi, + // S_size, L_lo, L_hi, L_size); + + // Perform global arrangement + int S_global_end, L_global_end; + MPI_Scan(&S_size, &S_global_end, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + MPI_Scan(&L_size, &L_global_end, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + + int S_global_start = S_global_end - S_size, + L_global_start = L_global_end - L_size; + printf("[%d] S: [%d - %d], L: [%d - %d]\n", rank, S_global_start, + S_global_end - 1, L_global_start, L_global_end - 1); + + // Send it to the correct target + + // The first node is responsible for collecting all the data and then printing + // it out to the file + // MPI_Gather(const void *sendbuf, int sendcount, MPI_INT, void *recvbuf, + // int recvcount, MPI_INT, 0, MPI_COMM_WORLD); + if (rank == 0) { + FILE *f = fopen(argv[2], "w"); + fclose(f); + } + + MPI_Finalize(); + return 0; } + +// hi not inclusive +void local_quicksort(int *arr, int lo, int hi) { + int temp; + + if (lo >= hi || lo < 0) + return; + + int pivot = arr[hi - 1]; + int pivot_idx = lo - 1; + for (int j = lo; j < hi; ++j) { + if (arr[j] < pivot) { + pivot_idx += 1; + + temp = arr[j]; + arr[j] = arr[pivot_idx]; + arr[pivot_idx] = temp; + } + } + + pivot_idx += 1; + temp = arr[hi - 1]; + arr[hi - 1] = arr[pivot_idx]; + arr[pivot_idx] = temp; + + // Recursive call + local_quicksort(arr, lo, pivot_idx); + local_quicksort(arr, pivot_idx + 1, hi); +} + +char *string_of_list(int *arr, int len) { + char *buffer = malloc(1000); + int offset = 0; // Keep track of the current position in the buffer + for (int i = 0; i < len; i++) { + offset += sprintf(buffer + offset, "%d", arr[i]); + if (i < len - 1) { + // Add a separator (e.g., comma or space) if it's not the last element + offset += sprintf(buffer + offset, " "); + } + } + + return buffer; +} \ No newline at end of file