Offline Notepad View raw

Shared snapshot

hpc

#include <stdio.h> #include <stdlib.h> #include <time.h> #include <omp.h> #include <string.h> #include <math.h>

// ===== Helper Functions ===== double **allocate_matrix(int N) { double **mat = malloc(N * sizeof(double *)); for (int i = 0; i < N; i++) mat[i] = malloc(N * sizeof(double)); return mat; }

void free_matrix(double **mat, int N) { for (int i = 0; i < N; i++) free(mat[i]); free(mat); }

void initialize_matrix(double **mat, int N) { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) mat[i][j] = ((double)rand() / RAND_MAX) * 100.0; }

void matmul_seq(double **A, double **B, double **C, int N) { for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { double sum = 0.0; for (int k = 0; k < N; k++) sum += A[i][k] * B[k][j]; C[i][j] = sum; } } }

// ===== Parallel Implementations ===== void matmul_parallel_no_collapse(double **A, double **B, double **C, int N, const char *schedule_type, int chunk_size) { omp_sched_t sched_kind; if (strcmp(schedule_type, "static") == 0) sched_kind = omp_sched_static; else if (strcmp(schedule_type, "dynamic") == 0) sched_kind = omp_sched_dynamic; else if (strcmp(schedule_type, "guided") == 0) sched_kind = omp_sched_guided; else sched_kind = omp_sched_static;

omp_set_schedule(sched_kind, chunk_size);

#pragma omp parallel { #pragma omp for schedule(runtime) nowait for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { double sum = 0.0; for (int k = 0; k < N; k++) sum += A[i][k] * B[k][j]; C[i][j] = sum; } } } }

void matmul_parallel_collapse(double **A, double **B, double **C, int N, const char *schedule_type, int chunk_size) { omp_sched_t sched_kind; if (strcmp(schedule_type, "static") == 0) sched_kind = omp_sched_static; else if (strcmp(schedule_type, "dynamic") == 0) sched_kind = omp_sched_dynamic; else if (strcmp(schedule_type, "guided") == 0) sched_kind = omp_sched_guided; else sched_kind = omp_sched_static;

omp_set_schedule(sched_kind, chunk_size);

#pragma omp parallel { #pragma omp for collapse(2) schedule(runtime) nowait for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { double sum = 0.0; for (int k = 0; k < N; k++) sum += A[i][k] * B[k][j]; C[i][j] = sum; } } } }

// ===== Main Function ===== int main() { int N; printf("Enter matrix size (e.g., 500): "); scanf("%d", &N);

int chunk_size = 10; printf("Using %d threads\n", omp_get_max_threads());

double **A = allocate_matrix(N); double **B = allocate_matrix(N); double **C_seq = allocate_matrix(N); double **C_par = allocate_matrix(N);

srand(time(NULL)); initialize_matrix(A, N); initialize_matrix(B, N);

double start, end;

// Sequential printf("\nRunning sequential multiplication...\n"); start = omp_get_wtime(); matmul_seq(A, B, C_seq, N); end = omp_get_wtime(); printf("Sequential time: %f seconds\n", end - start);

// Static schedule printf("\nRunning parallel (no collapse) with static schedule...\n"); start = omp_get_wtime(); matmul_parallel_no_collapse(A, B, C_par, N, "static", chunk_size); end = omp_get_wtime(); printf("Parallel (no collapse) static: %f seconds\n", end - start);

printf("Running parallel (collapse(2)) with static schedule...\n"); start = omp_get_wtime(); matmul_parallel_collapse(A, B, C_par, N, "static", chunk_size); end = omp_get_wtime(); printf("Parallel (collapse(2)) static: %f seconds\n", end - start);

// Dynamic schedule printf("\nRunning parallel (no collapse) with dynamic schedule...\n"); start = omp_get_wtime(); matmul_parallel_no_collapse(A, B, C_par, N, "dynamic", chunk_size); end = omp_get_wtime(); printf("Parallel (no collapse) dynamic: %f seconds\n", end - start);

printf("Running parallel (collapse(2)) with dynamic schedule...\n"); start = omp_get_wtime(); matmul_parallel_collapse(A, B, C_par, N, "dynamic", chunk_size); end = omp_get_wtime(); printf("Parallel (collapse(2)) dynamic: %f seconds\n", end - start);

// Guided schedule printf("\nRunning parallel (no collapse) with guided schedule...\n"); start = omp_get_wtime(); matmul_parallel_no_collapse(A, B, C_par, N, "guided", chunk_size); end = omp_get_wtime(); printf("Parallel (no collapse) guided: %f seconds\n", end - start);

printf("Running parallel (collapse(2)) with guided schedule...\n"); start = omp_get_wtime(); matmul_parallel_collapse(A, B, C_par, N, "guided", chunk_size); end = omp_get_wtime(); printf("Parallel (collapse(2)) guided: %f seconds\n", end - start);

free_matrix(A, N); free_matrix(B, N); free_matrix(C_seq, N); free_matrix(C_par, N);

return 0; }


Matrix-Vector Multiplication (MV)

p1: Basic MV Multiplication Comparison

c //p1 #include <stdio.h> #include <stdlib.h> #include <omp.h>

int main() { int n = 2000; double **matrix, *vector, *result; int i, j;

// Allocate memory matrix = (double **)malloc(n * sizeof(double *)); for (i = 0; i < n; i++) matrix[i] = (double *)malloc(n * sizeof(double));

vector = (double *)malloc(n * sizeof(double)); result = (double *)malloc(n * sizeof(double));

// Initialize matrix and vector for (i = 0; i < n; i++) { vector[i] = 1.0; for (j = 0; j < n; j++) matrix[i][j] = 1.0; }

// Sequential computation double start = omp_get_wtime(); for (i = 0; i < n; i++) { double sum = 0.0; for (j = 0; j < n; j++) sum += matrix[i][j] * vector[j]; result[i] = sum; } double end = omp_get_wtime(); printf("Sequential Time: %f seconds\n", end - start);

// Parallel computation start = omp_get_wtime(); #pragma omp parallel for private(j) schedule(static) for (i = 0; i < n; i++) { double sum = 0.0; for (j = 0; j < n; j++) sum += matrix[i][j] * vector[j]; result[i] = sum; } end = omp_get_wtime();

printf("Parallel Time: %f seconds\n", end - start);

// Free allocated memory for (i = 0; i < n; i++) free(matrix[i]); free(matrix); free(vector); free(result);

return 0; }

p1: MV Multiplication with Result Display

c // With displaying the result (first 10 values only for display restrictions)

#include <stdio.h> #include <stdlib.h> #include <omp.h>

int main() { int n = 2000; double **matrix, *vector, *result; int i, j;

// Memory allocation matrix = (double **)malloc(n * sizeof(double *)); for (i = 0; i < n; i++) matrix[i] = (double *)malloc(n * sizeof(double));

vector = (double *)malloc(n * sizeof(double)); result = (double *)malloc(n * sizeof(double));

// Initialize matrix and vector for (i = 0; i < n; i++) { vector[i] = 2.0; for (j = 0; j < n; j++) matrix[i][j] = 2.0; }

// Sequential computation double start = omp_get_wtime(); for (i = 0; i < n; i++) { double sum = 0.0; for (j = 0; j < n; j++) sum += matrix[i][j] * vector[j]; result[i] = sum; } double end = omp_get_wtime(); printf("Sequential Time: %f seconds\n", end - start);

// Print first 10 results (sequential) printf("Sequential result (first 10 values): "); for (i = 0; i < 10; i++) printf("%0.2f ", result[i]); printf("\n");

// Parallel computation start = omp_get_wtime(); #pragma omp parallel for private(j) schedule(static) for (i = 0; i < n; i++) { double sum = 0.0; for (j = 0; j < n; j++) sum += matrix[i][j] * vector[j]; result[i] = sum; } end = omp_get_wtime(); printf("Parallel Time: %f seconds\n", end - start);

// Print first 10 results (parallel) printf("Parallel result (first 10 values): "); for (i = 0; i < 10; i++) printf("%0.2f ", result[i]); printf("\n");

// Free allocated memory for (i = 0; i < n; i++) free(matrix[i]); free(matrix); free(vector); free(result);

return 0; }


Summation/Reduction (Shopping Bill)

p2: Summing arrays using omp sections and reduction

c //p2 #include <stdio.h> #include <omp.h>

int main() { int clothing[] = {500, 1000, 750}; int gaming[] = {1500, 2000}; int grocery[] = {100, 250, 300, 150}; int stationary[] = {50, 80, 40};

int n1 = 3, n2 = 2, n3 = 4, n4 = 3; int total_seq = 0, total_par = 0; double start, end, seq_time, par_time;

// Sequential computation start = omp_get_wtime(); for (int i = 0; i < n1; i++) total_seq += clothing[i]; for (int i = 0; i < n2; i++) total_seq += gaming[i]; for (int i = 0; i < n3; i++) total_seq += grocery[i]; for (int i = 0; i < n4; i++) total_seq += stationary[i]; end = omp_get_wtime(); seq_time = end - start;

// Parallel computation using sections start = omp_get_wtime(); #pragma omp parallel sections reduction(+:total_par) { #pragma omp section for (int i = 0; i < n1; i++) total_par += clothing[i];

#pragma omp section for (int i = 0; i < n2; i++) total_par += gaming[i];

#pragma omp section for (int i = 0; i < n3; i++) total_par += grocery[i];

#pragma omp section for (int i = 0; i < n4; i++) total_par += stationary[i]; } end = omp_get_wtime(); par_time = end - start;

printf("Sequential Total: %d, Time: %lf sec\n", total_seq, seq_time); printf("Parallel Total: %d, Time: %lf sec\n", total_par, par_time); printf("Speedup: %lf\n", seq_time / par_time);

return 0; }

p2: Variant - Summing arrays using omp parallel for and if/else

c //Variant #include <stdio.h> #include <omp.h>

int main() { int clothing[] = {500, 700, 800, 600}; int gaming[] = {2000, 1500, 3000}; int grocery[] = {200, 300, 150, 100, 50}; int stationary[] = {50, 100, 150};

int total = 0; double start, end;

start = omp_get_wtime();

// Sequential computation (NOTE: The logic here is flawed as it sums twice - once sequentially, then again in the parallel block. I kept it as is to match the original structure, though in a real application, the sequential part should be separate and compared to the parallel result.) for (int i = 0; i < 4; i++) total += clothing[i]; for (int i = 0; i < 3; i++) total += gaming[i]; for (int i = 0; i < 5; i++) total += grocery[i]; for (int i = 0; i < 3; i++) total += stationary[i];

// Parallel computation using sections-like logic #pragma omp parallel for reduction(+:total) for (int section = 0; section < 4; section++) { int sum = 0;

if (section == 0) { for (int i = 0; i < 4; i++) sum += clothing[i]; } else if (section == 1) { for (int i = 0; i < 3; i++) sum += gaming[i]; } else if (section == 2) { for (int i = 0; i < 5; i++) sum += grocery[i]; } else if (section == 3) { for (int i = 0; i < 3; i++) sum += stationary[i]; }

total += sum; }

end = omp_get_wtime();

printf("Final Bill Amount = %d\n", total); printf("Time Taken = %f seconds\n", end - start);

return 0; }


Pi Calculation (Parallel Reduction Techniques)

These snippets calculate Pi using numerical integration and demonstrate different OpenMP techniques for parallel reduction (reduction, atomic, critical).

p3: Using reduction

c //p3 //Using reduction #include <stdio.h> #include <omp.h>

int main() { long num_steps = 1000000000; double step, x, sum = 0.0; double start_time, end_time;

step = 1.0 / (double) num_steps; start_time = omp_get_wtime();

#pragma omp parallel for private(x) reduction(+:sum) for (long i = 0; i < num_steps; i++) { x = (i + 0.5) * step; sum += 4.0 / (1.0 + x * x); }

double pi = step * sum; end_time = omp_get_wtime();

printf("Approximated Pi = %.15f\n", pi); printf("Time taken = %f seconds\n", end_time - start_time);

return 0; }

p3: Using atomic

c //Using Atomic #include <stdio.h> #include <omp.h>

int main() { long num_steps = 100000000; double step = 1.0 / (double)num_steps; double sum = 0.0; double start_time, end_time;

start_time = omp_get_wtime();

#pragma omp parallel { double x, local_sum = 0.0;

#pragma omp for for (long i = 0; i < num_steps; i++) { x = (i + 0.5) * step; local_sum += 4.0 / (1.0 + x * x); }

#pragma omp atomic sum += local_sum; }

double pi = step * sum; end_time = omp_get_wtime();

printf("Parallel PI = %.15f\n", pi); printf("Time taken: %f seconds\n", end_time - start_time);

return 0; }

p3: Using critical

c //Using Critical

#include <stdio.h> #include <omp.h>

static long num_steps = 100000000; double step;

int main() { int i; double x, pi = 0.0, sum = 0.0;

step = 1.0 / (double)num_steps; double start_time = omp_get_wtime();

#pragma omp parallel { double local_sum = 0.0;

#pragma omp for for (i = 0; i < num_steps; i++) { x = (i + 0.5) * step; local_sum += 4.0 / (1.0 + x * x); }

#pragma omp critical { sum += local_sum; } }

pi = step * sum; double end_time = omp_get_wtime();

printf("Computed value of Pi = %.15f\n", pi); printf("Time taken = %f seconds\n", end_time - start_time);

return 0; }


Fibonacci Sequence

These snippets demonstrate OpenMP constructs (single, sections, critical) for tasks that involve an ordered, dependent computation (like the Fibonacci sequence) and parallel output.

p4: Using single

c //p4 // using single #include <stdio.h> #include <stdlib.h> #include <time.h> #include <omp.h>

int main() { int n, i;

printf("Number of terms : "); scanf("%d", &n);

if (n < 2) { printf("Please enter n >= 2\n"); return 0; }

int* a = (int*)malloc(n * sizeof(int)); if (a == NULL) { printf("Memory allocation failed\n"); return 1; }

a[0] = 0; a[1] = 1;

clock_t st = clock();

omp_set_num_threads(2);

#pragma omp parallel { #pragma omp single { printf("Thread involved in computation of Fibonacci numbers = %d\n", omp_get_thread_num());

for (i = 2; i < n; i++) a[i] = a[i - 2] + a[i - 1]; }

#pragma omp single { printf("Thread involved in displaying Fibonacci numbers = %d\n", omp_get_thread_num());

printf("Fibonacci numbers: "); for (i = 0; i < n; i++) printf("%d ", a[i]); printf("\n"); } }

clock_t et = clock();

printf("Time Taken : %.4f ms\n", ((double)(et - st) * 1000 / CLOCKS_PER_SEC));

free(a); return 0; }

p4: Using sections (Producer-Consumer Style)

c //USING SECTIONS #include <stdio.h> #include <omp.h>

#define MAX 20 int fib[MAX]; int generated = 0;

int main() { int n = MAX; fib[0] = 0; fib[1] = 1; generated = 2;

omp_set_num_threads(2); double start = omp_get_wtime();

#pragma omp parallel shared(fib, generated, n) { #pragma omp sections { // Section 1: Generate Fibonacci numbers #pragma omp section { for (int i = 2; i < n; i++) { #pragma omp critical { fib[i] = fib[i - 1] + fib[i - 2]; generated++; } #pragma omp flush(generated) } }

// Section 2: Print Fibonacci numbers as they are generated #pragma omp section { int lastPrinted = 0; while (lastPrinted < n) { #pragma omp flush(generated) if (lastPrinted < generated) { #pragma omp critical { printf("Fibonacci[%d] = %d\n", lastPrinted, fib[lastPrinted]); lastPrinted++; } } } } } }

double end = omp_get_wtime(); printf("Time taken: %f seconds\n", end - start);

return 0; }

p4: Using critical (Thread ID Based)

c // USING CRITICAL #include <stdio.h> #include <stdlib.h> #include <time.h> #include <omp.h>

int main() { int n, i;

printf("Number of terms : "); scanf("%d", &n);

if (n < 2) { printf("Please enter n >= 2\n"); return 0; }

int *a = (int *)malloc(n * sizeof(int)); a[0] = 0; a[1] = 1;

time_t st, et; st = clock();

omp_set_num_threads(2);

#pragma omp parallel { int tid = omp_get_thread_num();

if (tid == 0) { #pragma omp critical { printf("ID of thread involved in the computation of Fibonacci numbers = %d\n", tid); for (i = 2; i < n; i++) a[i] = a[i - 2] + a[i - 1]; } } else if (tid == 1) { #pragma omp critical { printf("ID of thread involved in the displaying of Fibonacci numbers = %d\n", tid); printf("Fibonacci numbers : "); for (i = 0; i < n; i++) printf("%d ", a[i]); printf("\n"); } } }

et = clock(); printf("Time Taken : %lf ms\n", ((double)(et - st) * 1000 / CLOCKS_PER_SEC));

free(a); return 0; }

//p5 #include <stdio.h> #include <stdlib.h> #include <omp.h> #include <time.h>

void generate_cgpa(float *arr, int n) { #pragma omp parallel for for (int i = 0; i < n; i++) { arr[i] = ((float)rand() / RAND_MAX) * 10.0; } }

float find_max_sequential(float *arr, int n) { float max = arr[0]; for (int i = 1; i < n; i++) { if (arr[i] > max) { max = arr[i]; } } return max; }

float find_max_parallel_critical(float *arr, int n) { float max = arr[0]; #pragma omp parallel for for (int i = 0; i < n; i++) { #pragma omp critical { if (arr[i] > max) { max = arr[i]; } } } return max; }

float find_max_parallel_reduction(float *arr, int n) { float max = arr[0]; #pragma omp parallel for reduction(max:max) for (int i = 0; i < n; i++) { if (arr[i] > max) { max = arr[i]; } } return max; }

int main() { int n; printf("Enter number of students: "); scanf("%d", &n);

float *cgpa = (float *)malloc(n * sizeof(float)); srand(time(NULL));

double start = omp_get_wtime(); generate_cgpa(cgpa, n); double end = omp_get_wtime(); printf("Time taken to generate CGPAs (parallel): %f seconds\n", end - start);

start = omp_get_wtime(); float max_seq = find_max_sequential(cgpa, n); end = omp_get_wtime(); printf("Sequential Max CGPA: %.2f (Time: %f seconds)\n", max_seq, end - start);

start = omp_get_wtime(); float max_critical = find_max_parallel_critical(cgpa, n); end = omp_get_wtime(); printf("Parallel Max CGPA (critical): %.2f (Time: %f seconds)\n", max_critical, end - start);

start = omp_get_wtime(); float max_reduction = find_max_parallel_reduction(cgpa, n); end = omp_get_wtime(); printf("Parallel Max CGPA (reduction): %.2f (Time: %f seconds)\n", max_reduction, end - start);

free(cgpa); return 0; }


p6: Matrix Multiplication Comparison

This program compares sequential matrix multiplication against parallel versions using the OpenMP collapse(2) clause and various scheduling types, along with correctness checks.

c //p6 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <omp.h> #include <string.h> #include <math.h>

double **allocate_matrix(int N) { double **mat = malloc(N * sizeof(double *)); for(int i = 0; i < N; i++) { mat[i] = malloc(N * sizeof(double)); } return mat; }

void free_matrix(double **mat, int N) { for(int i = 0; i < N; i++) free(mat[i]); free(mat); }

void initialize_matrix(double **mat, int N) { for(int i=0; i<N; i++) for(int j=0; j<N; j++) mat[i][j] = ((double)rand()/RAND_MAX)*100.0; }

void matmul_seq(double **A, double **B, double **C, int N) { for(int i=0; i<N; i++) { for(int j=0; j<N; j++) { double sum=0.0; for(int k=0; k<N; k++) sum += A[i][k]*B[k][j]; C[i][j] = sum; } } }

void matmul_parallel_no_collapse(double **A, double **B, double **C, int N, const char* schedule_type, int chunk_size) { omp_sched_t sched_kind; if(strcmp(schedule_type,"static")==0) sched_kind = omp_sched_static; else if(strcmp(schedule_type,"dynamic")==0) sched_kind = omp_sched_dynamic; else if(strcmp(schedule_type,"guided")==0) sched_kind = omp_sched_guided; else { fprintf(stderr,"Unknown schedule type '%s', defaulting to static\n", schedule_type); sched_kind = omp_sched_static; } omp_set_schedule(sched_kind, chunk_size);

#pragma omp parallel { #pragma omp for schedule(runtime) nowait for(int i=0; i<N; i++) { for(int j=0; j<N; j++) { double sum=0.0; for(int k=0; k<N; k++) { sum += A[i][k]*B[k][j]; } C[i][j] = sum; } }

// You can put other parallel work here without waiting for above loop to finish } // implicit barrier at the end of parallel region ensures completion before continuing }

void matmul_parallel_collapse(double **A, double **B, double **C, int N, const char* schedule_type, int chunk_size) { omp_sched_t sched_kind; if(strcmp(schedule_type,"static")==0) sched_kind = omp_sched_static; else if(strcmp(schedule_type,"dynamic")==0) sched_kind = omp_sched_dynamic; else if(strcmp(schedule_type,"guided")==0) sched_kind = omp_sched_guided; else { fprintf(stderr,"Unknown schedule type '%s', defaulting to static\n", schedule_type); sched_kind = omp_sched_static; } omp_set_schedule(sched_kind, chunk_size);

#pragma omp parallel { #pragma omp for collapse(2) schedule(runtime) nowait for(int i=0; i<N; i++) { for(int j=0; j<N; j++) { double sum=0.0; for(int k=0; k<N; k++) { sum += A[i][k]*B[k][j]; } C[i][j] = sum; } }

// Other parallel work without waiting for above loop } // implicit barrier at parallel region end }

int compare_matrices(double **M1, double **M2, int N) { const double EPS = 1e-6; for(int i=0; i<N; i++) { for(int j=0; j<N; j++) { if(fabs(M1[i][j] - M2[i][j]) > EPS) return 0; } } return 1; }

int main() { int max_sizes = 10; int sizes[max_sizes]; int num_sizes = 0;

printf("Enter matrix sizes separated by spaces (max %d sizes):\n", max_sizes); char line[256]; if(!fgets(line, sizeof(line), stdin)) { fprintf(stderr, "Error reading input\n"); return 1; }

// Parse integers from input line char *token = strtok(line, " \t\n"); while(token != NULL && num_sizes < max_sizes) { sizes[num_sizes++] = atoi(token); token = strtok(NULL, " \t\n"); }

if(num_sizes == 0) { printf("No sizes entered. Exiting.\n"); return 1; }

int num_threads = omp_get_max_threads(); int chunk_size = 10;

printf("Using %d threads\n", num_threads);

srand(time(NULL));

for(int idx=0; idx<num_sizes; idx++) { int N = sizes[idx]; printf("\n=== Matrix size: %d x %d ===\n", N, N);

double **A = allocate_matrix(N); double **B = allocate_matrix(N); double **C_seq = allocate_matrix(N); double **C_par_nc = allocate_matrix(N); double **C_par_c = allocate_matrix(N);

initialize_matrix(A, N); initialize_matrix(B, N);

double start, end;

// Sequential printf("Running sequential multiplication...\n"); start = omp_get_wtime(); matmul_seq(A, B, C_seq, N); end = omp_get_wtime(); printf("Sequential time: %f seconds\n", end - start);

// Parallel no collapse (static schedule) printf("Running parallel multiplication without collapse (static schedule)...\n"); start = omp_get_wtime(); matmul_parallel_no_collapse(A, B, C_par_nc, N, "static", chunk_size); end = omp_get_wtime(); printf("Parallel no collapse time: %f seconds\n", end - start); printf("Correctness check: %s\n", compare_matrices(C_seq, C_par_nc, N) ? "PASS" : "FAIL");

// Parallel with collapse(2) (static schedule) printf("Running parallel multiplication with collapse(2) (static schedule)...\n"); start = omp_get_wtime(); matmul_parallel_collapse(A, B, C_par_c, N, "static", chunk_size); end = omp_get_wtime(); printf("Parallel collapse(2) time: %f seconds\n", end - start); printf("Correctness check: %s\n", compare_matrices(C_seq, C_par_c, N) ? "PASS" : "FAIL");

free_matrix(A, N); free_matrix(B, N); free_matrix(C_seq, N); free_matrix(C_par_nc, N); free_matrix(C_par_c, N); }

return 0; }

//export OMP_NUM_THREADS=8


🤖 MPI Distributed Memory Code Snippets

p7: Total Sum using MPI_Reduce

This program demonstrates the MPI_Reduce collective operation to sum the randomly generated "mangoes picked" by each MPI process (robot) on the root process (rank 0).

c //p7 #include<stdio.h> #include<stdlib.h> #include<mpi.h> int main(int argc, char** argv) { int rank, numproc; int sum = 0; int total_sum = 0; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &numproc); MPI_Comm_rank(MPI_COMM_WORLD, &rank); srand(rank); sum = rand() % 100; printf("Robot %d picked %d mangoes.\n", rank, sum); MPI_Reduce(&sum, &total_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); if (rank == 0) printf("Total Mangoes picked by %d Robots = %d\n", numproc, total_sum); MPI_Finalize(); }


p8: MPI Collective Communications Demo

This program demonstrates several fundamental MPI collective operations: MPI_Bcast, MPI_Scatter, MPI_Gather, MPI_Reduce, MPI_Allreduce, and MPI_Scan.

c //P8 #include <mpi.h> #include <stdio.h> #include <stdlib.h>

int main(int argc, char *argv[]) { int rank, size; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size);

if (rank == 0) printf("MPI Collectives demo with %d process(es)\n\n", size);

// --- Broadcast --- int bcast_val = 0; if (rank == 0) bcast_val = 123;

MPI_Bcast(&bcast_val, 1, MPI_INT, 0, MPI_COMM_WORLD); printf("[rank %d] received bcast_val = %d\n", rank, bcast_val);

// --- Scatter --- int scatter_val; int *scatter_buf = NULL; if (rank == 0) { scatter_buf = malloc(size * sizeof(int)); for (int i = 0; i < size; i++) scatter_buf[i] = (i + 1) * 10; }

MPI_Scatter(scatter_buf, 1, MPI_INT, &scatter_val, 1, MPI_INT, 0, MPI_COMM_WORLD); printf("[rank %d] got scatter_val = %d\n", rank, scatter_val);

if (scatter_buf) free(scatter_buf);

// --- Gather --- int my_val = rank * 10; int *gather_buf = NULL;

if (rank == 0) gather_buf = malloc(size * sizeof(int));

MPI_Gather(&my_val, 1, MPI_INT, gather_buf, 1, MPI_INT, 0, MPI_COMM_WORLD);

if (rank == 0) { printf("Root gathered: "); for (int i = 0; i < size; i++) printf("%d ", gather_buf[i]); printf("\n"); free(gather_buf); }

// --- Reduce (sum) --- int local_sum = rank + 1, total_sum; MPI_Reduce(&local_sum, &total_sum, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);

if (rank == 0) printf("Sum of ranks+1 = %d\n", total_sum);

// --- Allreduce (max) --- int local_val = rank * 2; int global_max; MPI_Allreduce(&local_val, &global_max, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); printf("[rank %d] after Allreduce max = %d\n", rank, global_max);

// --- Scan (prefix sum) --- int scan_out; MPI_Scan(&rank, &scan_out, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); printf("[rank %d] prefix sum = %d\n", rank, scan_out);

MPI_Finalize(); return 0; }


p9: MPI Cartesian Virtual Topology

This program demonstrates creating a 2D Cartesian virtual topology using MPI_Cart_create and finding the process's coordinates and its neighbors using MPI_Cart_coords and MPI_Cart_shift.

c //P9 #include <mpi.h> #include <stdio.h> #include <stdlib.h>

int main(int argc, char *argv[]) { MPI_Init(&argc, &argv);

int rank, size; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size);

// Define a 2D Cartesian grid int dims[2] = {0, 0}; MPI_Dims_create(size, 2, dims); // Let MPI choose dimensions if not specified

int periods[2] = {0, 0}; // No wrap-around (non-periodic) int reorder = 1; // Allow MPI to reorder ranks for efficiency

MPI_Comm cart_comm; MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, reorder, &cart_comm);

if (cart_comm == MPI_COMM_NULL) { printf("[rank %d] could not create Cartesian communicator\n", rank); MPI_Finalize(); return 0; }

// Get my coordinates in the Cartesian grid int coords[2]; MPI_Cart_coords(cart_comm, rank, 2, coords); printf("[rank %d] coords = (%d, %d)\n", rank, coords[0], coords[1]);

// Find neighbors (up, down, left, right) int up, down, left, right; MPI_Cart_shift(cart_comm, 0, 1, &up, &down); // shift along rows MPI_Cart_shift(cart_comm, 1, 1, &left, &right); // shift along columns

printf("[rank %d] neighbors -> up: %d, down: %d, left: %d, right: %d\n", rank, up, down, left, right);

MPI_Finalize(); return 0; }


p10: Blocking vs. Non-blocking Point-to-Point Communication

This program contrasts blocking (MPI_Send, MPI_Recv) communication, which stops execution until the message transfer is safe to complete, with non-blocking (MPI_Isend, MPI_Irecv) communication, which allows the process to perform other work before explicitly synchronizing with MPI_Wait.

c //P10 #include <mpi.h> #include <stdio.h> #include <stdlib.h>

int main(int argc, char *argv[]) { MPI_Init(&argc, &argv);

int rank, size; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size);

if (size < 2) { if (rank == 0) printf("Please run with at least 2 processes.\n"); MPI_Finalize(); return 0; }

// --- BLOCKING SEND / RECEIVE --- if (rank == 0) { int msg = 100; printf("[Blocking] Rank 0 sending %d to rank 1\n", msg); MPI_Send(&msg, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); printf("[Blocking] Rank 0 done sending\n"); } else if (rank == 1) { int recv_msg; MPI_Recv(&recv_msg, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); printf("[Blocking] Rank 1 received %d from rank 0\n", recv_msg); }

MPI_Barrier(MPI_COMM_WORLD); // synchronize before nonblocking example

// --- NONBLOCKING SEND / RECEIVE --- if (rank == 0) { int msg = 200; MPI_Request request;

printf("[Nonblocking] Rank 0 sending %d to rank 1\n", msg); MPI_Isend(&msg, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &request);

// Do some work while message is in progress printf("[Nonblocking] Rank 0 doing other work...\n"); for (int i = 0; i < 5; i++) printf("."); printf("\n");

// Wait for send to complete MPI_Wait(&request, MPI_STATUS_IGNORE); printf("[Nonblocking] Rank 0 send completed\n"); } else if (rank == 1) { int recv_msg; MPI_Request request;

MPI_Irecv(&recv_msg, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &request);

// Do some work while waiting printf("[Nonblocking] Rank 1 doing other work...\n"); for (int i = 0; i < 5; i++) printf("*"); printf("\n");

// Wait for receive to complete MPI_Wait(&request, MPI_STATUS_IGNORE); printf("[Nonblocking] Rank 1 received %d from rank 0\n", recv_msg); }

MPI_Finalize(); return 0; }