diff --git a/.vscode/settings.json b/.vscode/settings.json index 0978fad..962c8f9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,6 @@ "[python]": { "editor.defaultFormatter": "ms-python.black-formatter" }, - "python.formatting.provider": "none" + "python.formatting.provider": "none", + "discord.enabled": true } diff --git a/assignments/02/Makefile b/assignments/02/Makefile index cc44f17..3922381 100644 --- a/assignments/02/Makefile +++ b/assignments/02/Makefile @@ -1,4 +1,4 @@ -.PHONY: all clean +.PHONY: all clean run-example CC := cc @@ -10,6 +10,9 @@ LDFLAGS += $(shell pkg-config --libs mpi) all: qs_mpi +run-example: qs_mpi + mpirun --allow-run-as-root -np 4 ./qs_mpi 32 output.txt + qs_mpi: qs_mpi.o $(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@ diff --git a/assignments/02/qs_mpi.c b/assignments/02/qs_mpi.c index 4a053e8..69d6644 100644 --- a/assignments/02/qs_mpi.c +++ b/assignments/02/qs_mpi.c @@ -18,7 +18,7 @@ void local_quicksort(int *arr, int lo, int hi); char *string_of_list(int *arr, int len); -void recursive_quicksort(int *integers, int n, MPI_Comm comm); +void recursive_quicksort(int *integers, int n, int root, MPI_Comm comm); int main(int argc, char **argv) { int rank, p; @@ -33,7 +33,7 @@ int main(int argc, char **argv) { int n_over_p = n / p; int integers[n_over_p]; - // Important implementation detail: srand(0) is specially handled by glibc to + // Minor 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 // @@ -46,17 +46,26 @@ int main(int argc, char **argv) { // printf(" - %d\n", integers[i]); } - recursive_quicksort(integers, n, MPI_COMM_WORLD); + recursive_quicksort(integers, n, 0, MPI_COMM_WORLD); - sleep(1); - printf("[%d] after: %s\n", rank, string_of_list(integers, n_over_p)); + // sleep(1); + // printf("[%d] after: %s\n", rank, string_of_list(integers, n_over_p)); // 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); + int recvbuf[n]; + MPI_Allgather(integers, n_over_p, MPI_INT, recvbuf, n_over_p, MPI_INT, + MPI_COMM_WORLD); + if (rank == 0) { FILE *f = fopen(argv[2], "w"); + // printf("integers: %s\n", string_of_list(recvbuf, n)); + for (int i = 0; i < p; i += 1) { + printf("[%d] integers: %s\n", rank, + string_of_list(&recvbuf[i * n_over_p], n_over_p)); + } fclose(f); } @@ -108,7 +117,7 @@ char *string_of_list(int *arr, int len) { return buffer; } -void recursive_quicksort(int *integers, int n, MPI_Comm comm) { +void recursive_quicksort(int *integers, int n, int root, MPI_Comm comm) { int rank, p; MPI_Comm_size(comm, &p); MPI_Comm_rank(comm, &rank); @@ -116,10 +125,19 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { if (p == 1) { // Recursion base case: just sort it serially local_quicksort(integers, 0, n); + printf("Quicksorted: %s\n", string_of_list(integers, n)); return; } + sleep(1); + printf("\n\n"); + int n_over_p_max = (n + p - 1) / p; int n_over_p = n / p; + if (rank == root) + n_over_p += n - p * n_over_p; + printf( + "[%d] :::::::::::::::::::::::::::: RECURSIVE QUICKSORT (n=%d, n/p=%d)\n", + rank, n, n_over_p); // Locally sort // printf("[%d] Numbers before: %s\n", rank, @@ -131,12 +149,26 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { // Select a pivot. // This pivot is broadcasted to all nodes int pivot; + { + // First, select a random element + int rand_el = integers[rand() % n_over_p]; - // 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("--- Broadcasted pivot: %d ---\n", pivot); + // Gather it + int rand_els[p]; + MPI_Gather(&rand_el, 1, MPI_INT, rand_els, 1, MPI_INT, root, comm); + + // Get the median + if (rank == root) { + // Sort + local_quicksort(rand_els, 0, p); + + // Get the middle element + pivot = rand_els[p / 2]; + } + + MPI_Bcast(&pivot, 1, MPI_INT, root, comm); + } + printf("[%d] Broadcasted pivot: %d\n", rank, pivot); // Determine where the boundary between S (lower) and L (higher) lies int boundary; @@ -154,12 +186,12 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { // Perform global arrangement int S_global_end, L_reverse_end, S_global_max_end; - MPI_Scan(&S_size, &S_global_end, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); - MPI_Scan(&L_size, &L_reverse_end, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); + MPI_Scan(&S_size, &S_global_end, 1, MPI_INT, MPI_SUM, comm); + MPI_Scan(&L_size, &L_reverse_end, 1, MPI_INT, MPI_SUM, comm); // printf("[%d] bruh %d\n", rank, S_global_end); - MPI_Reduce(&S_global_end, &S_global_max_end, 1, MPI_INT, MPI_MAX, 0, - MPI_COMM_WORLD); + // Get the boundary element between S and L + MPI_Allreduce(&S_global_end, &S_global_max_end, 1, MPI_INT, MPI_MAX, comm); int S_global_start = S_global_end - S_size, L_reverse_start = L_reverse_end - L_size, @@ -240,7 +272,7 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { } MPI_Alltoallv(send_ctl, ctl_send_counts, ctl_send_displs, MPI_INT, S_ctl, - recv_counts, recv_displs, MPI_INT, MPI_COMM_WORLD); + recv_counts, recv_displs, MPI_INT, comm); } // Send L to the correct target @@ -282,7 +314,7 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { } MPI_Alltoallv(send_ctl, ctl_send_counts, ctl_send_displs, MPI_INT, L_ctl, - recv_counts, recv_displs, MPI_INT, MPI_COMM_WORLD); + recv_counts, recv_displs, MPI_INT, comm); } // After sending S and L information @@ -296,9 +328,12 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { // integers_recv_buf, // recv_counts, recv_displs, MPI_INT, MPI_COMM_WORLD); MPI_Allgather(integers, n_over_p, MPI_INT, integers_recv_buf, n_over_p, - MPI_INT, MPI_COMM_WORLD); + MPI_INT, comm); // printf("[%d] ints: %s\n", rank, string_of_list(integers_recv_buf, n)); + for (int i = 0; i < p; ++i) { + } + for (int i = 0; i < p; ++i) { int count = S_ctl[i * CTL_SIZE]; int from_global_start = S_ctl[i * CTL_SIZE + 1]; @@ -306,7 +341,7 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { if (count > 0) { printf( - "[%d] <<- S received (%d) from processor %d {%d..%d} to [%d..%d]\n", + "[%d] <<- S received (%d) from processor %d {%d..%d} to [% d..% d]\n", rank, count, i, from_global_start, from_global_start + count, to_local_start, to_local_start + count); for (int j = 0; j < count; ++j) { @@ -322,7 +357,7 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { if (count > 0) { printf( - "[%d] <<- S received (%d) from processor %d {%d..%d} to [%d..%d]\n", + "[%d] <<- S received (%d) from processor %d {%d..%d} to [% d..% d]\n", rank, count, i, from_global_start, from_global_start + count, to_local_start, to_local_start + count); for (int j = 0; j < count; ++j) { @@ -331,37 +366,59 @@ void recursive_quicksort(int *integers, int n, MPI_Comm comm) { } } + printf("[%d] after: %s\n", rank, string_of_list(integers, n_over_p)); + // Now, determine which processes should be responsible for taking the S and L // arrays // Specifically, the part where it's split, break the tie to see if it goes // down or up int colors[p]; - if (rank == 0) { - int p_of_split = S_global_max_end / n_over_p; - int split_point = S_global_max_end % n_over_p; - printf("[%d] shiet %d\n", rank, p_of_split); + int p_of_split = S_global_max_end / n_over_p; + int split_point = S_global_max_end % n_over_p; + // printf("[%d] p_of_split = %d / %d = %d\n", rank, S_global_max_end, + // n_over_p, + // p_of_split); + int S_split_add = split_point, L_split_sub = n_over_p - split_point; - int lo_start = 0, lo_end; - int hi_start, hi_end = p; - if (split_point > n_over_p / 2) { - // Belongs to the lower group - lo_end = hi_start = p_of_split + 1; - } else { - // Belongs to the higher group - lo_end = hi_start = p_of_split; - } + int lo_start = 0, lo_end; + int hi_start, hi_end = p; + if (split_point > n_over_p / 2) { + // Belongs to the lower group + lo_end = hi_start = p_of_split + 1; + } else { + // Belongs to the higher group + lo_end = hi_start = p_of_split; + } - for (int i = 0; i < p; ++i) { - if (i < lo_end) - colors[i] = 100; - else - colors[i] = 200; + int child_root = -1; + for (int i = 0; i < p; ++i) { + if (i < lo_end) + colors[i] = 100; + else { + colors[i] = 200; + if (child_root == -1) + child_root = i; } } - MPI_Comm child; - MPI_Comm_split(comm, colors[rank], rank, &child); - printf("[%d] Recursing...\n", rank); - MPI_Comm_free(&child); + // MPI_Comm child; + // MPI_Comm_split(comm, colors[rank], rank, &child); + // printf("[%d] Recursing...\n", rank); + + // int child_size; + // MPI_Comm_size(child, &child_size); + + // int start_at = 0, new_n = child_size * n_over_p; + // if (colors[rank] == 100) { + // new_n += S_split_add; + // } else { + // new_n -= L_split_sub; + // if (rank == p_of_split) + // start_at = split_point; + // } + // recursive_quicksort(integers, n, child_root, child); + + // printf("[%d] Done recursing.\n", rank); + // MPI_Comm_free(&child); } \ No newline at end of file