diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c8a4e6465edbb955cc465e35f1c7340cfb2ed9bb --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +serial: ./src/serial.c ./src/dijkstra.* ./src/util.* + gcc ./src/serial.c ./src/dijkstra.c ./src/util.c -o ./bin/serial + ./bin/serial $(n) + +parallel: ./src/paralel.c ./src/util.* ./src/dijkstra.* + mpicc ./src/paralel.c ./src/util.c ./src/dijkstra.c -o ./bin/parallel + mpirun -np $(np) --hostfile mpi_hostfile ./bin/parallel $(np) $(nv) + +run_par: ./bin/parallel + mpirun -np $(np) --hostfile mpi_hostfile ./bin/parallel $(np) $(nv) + +hello_omp: ./src/hello_openmp.c + gcc -g -Wall -fopenmp -o ./bin/hello_omp ./src/hello_openmp.c + ./bin/hello_omp $(nt) + +parallel_omp: ./src/paralel_openmp.c + gcc -g -Wall -fopenmp -o ./bin/parallel_omp ./src/paralel_openmp.c ./src/util.c ./src/dijkstra.c + ./bin/parallel_omp $(nt) $(nv) \ No newline at end of file diff --git a/src/boolean.h b/src/boolean.h new file mode 100644 index 0000000000000000000000000000000000000000..652f1a7460078e4fbea6ecaae9eb8923553ea768 --- /dev/null +++ b/src/boolean.h @@ -0,0 +1,8 @@ +#ifndef _BOOLEAN_h +#define _BOOLEAN_h + +#define bool unsigned char +#define true 1 +#define false 0 + +#endif \ No newline at end of file diff --git a/src/dijkstra.c b/src/dijkstra.c new file mode 100644 index 0000000000000000000000000000000000000000..7662d2c56f457ecc5cd96940b09267e49eedbce3 --- /dev/null +++ b/src/dijkstra.c @@ -0,0 +1,117 @@ +#include "dijkstra.h" + + +/** + * Get vertex index with minimum distance which not yet included + * in spt_set + * @param dist distance from origin vertex to vertex with that index + * @param spt_set a set denoting vertices included in spt_set + * @param n number of vertices in the graph + * @return index of minimum distance not yet included in spt_set + */ +int min_distance_idx(long dist[], bool spt_set[], int n) { + // Initialize min value + int min = INT_MAX, min_index; + + for (int i = 0; i < n; i++) { + if (spt_set[i] == false && dist[i] <= min) { + min = dist[i]; + min_index = i; + } + } + + + return min_index; +} + + +/** + * generate a graph with n vertices + * @param n number of vertices + * @return 2D array, graph[i][j] = graph[j][i] = distance from vertex i to j + */ +long **gen_graph(int n) { + // alokasi memori untuk matriks yang merepresentasikan graf + long **result = (long **)malloc(n * sizeof(long *)); + for (int i = 0; i < n; i++) { + result[i] = (long *)malloc(n * sizeof(long)); + } + + // isi matriks dengan bilangan random + srand(13517122); + + for (int i = 0; i < n; i++) { + for (int j = i; j < n; j++) { + if (i == j) { + result[i][j] = 0; + } else { + result[i][j] = result[j][i] = rand(); + } + + } + } + + return result; +} + +long **gen_temp(int r, int c) { + // alokasi memori untuk matriks yang merepresentasikan graf + long **result = (long **)malloc(r * sizeof(long *)); + // printf("[gen_temp] initiate temp\n"); + for (int i = 0; i < r; i++) { + result[i] = (long *)malloc(c * sizeof(long)); + // printf("[gen_temp] initiate each row in temp\n"); + } + + for (int i = 0; i < r; i++) { + for (int j = 0; j < c; j++) { + // printf("[gen_temp] filling temp\n"); + result[i][j] = 0; + } + } + + return result; +} + + +long *dijkstra(long **graph, int n, int src) { + + // output array, contains shortest distance from src to every vertices + long *dist = (long *) malloc (sizeof(long) * n); + // spt_set[i] is true if vertex i already included in the shortest path tree + bool spt_set[n]; + + // initialize dist and spt_set + for (int i = 0; i < n; i++) { + dist[i] = INT_MAX; + spt_set[i] = false; + } + + // initiate path searching + dist[src] = 0; + + + // find the shortest path for all vertices + for (int i = 0; i < n; i++) { + + // pick vertex with minimum distance from src from spt_set not yet + // processed + int processed_vertex = min_distance_idx(dist, spt_set, n); + + // mark vertex as processed + spt_set[processed_vertex] = true; + + for (int j = 0; j < n; j++) { + // check vertices connected to processed_vertex not yet processed + if (!spt_set[j] + && graph[processed_vertex][j] != 0 + && dist[processed_vertex] != INT_MAX + && dist[processed_vertex] + graph[processed_vertex][j] < dist[j]) { + + dist[j] = dist[processed_vertex] + graph[processed_vertex][j]; + } + } + } + + return dist; +} \ No newline at end of file diff --git a/src/dijkstra.h b/src/dijkstra.h new file mode 100644 index 0000000000000000000000000000000000000000..00a7aca177e1a11036ba31fc848d36cd817a2e2c --- /dev/null +++ b/src/dijkstra.h @@ -0,0 +1,43 @@ +#ifndef DIJKSTRA_H +#define DIJKSTRA_H +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> +#include "boolean.h" + +/** + * Get vertex index with minimum distance which not yet included + * in spt_set + * @param dist distance from origin vertex to vertex with that index + * @param spt_set a set denoting vertices included in spt_set + * @return index of minimum distance not yet included in spt_set + */ +int min_distance_idx(long dist[], bool spt_set[], int n); + + +/** + * generate a graph with n vertices + * @param n number of vertices + * @return 2D array, graph[i][j] = graph[j][i] = distance from vertex i to j + */ +long **gen_graph(int n); + + +/** + * generate 2D array with dimension of r x c + * @param r number of rows + * @param c number of columns + * @return 2D array, all filled with zero + */ +long **gen_temp(int r, int c); + +/** + * + * @param graph [description] + * @param n [description] + * @param src [description] + */ +long *dijkstra(long **graph, int n, int src); + + +#endif \ No newline at end of file diff --git a/src/hello_openmp.c b/src/hello_openmp.c new file mode 100644 index 0000000000000000000000000000000000000000..904804a7ab8d2658b6e70ffcfc6366bd78b519ae --- /dev/null +++ b/src/hello_openmp.c @@ -0,0 +1,20 @@ +#include <omp.h> +#include <stdio.h> +#include <stdlib.h> + +int main (int argc, char *argv[]) { + int nthreads = atoi(argv[1]), t_id; + int i; + #pragma omp parallel for private(t_id) + for (i = 0; i < 10; i++) { + t_id = omp_get_thread_num(); // get thread if for each thread + printf("i : %d, by the way i'm thread %d\n", i, t_id); + } + + // printf("Hello from thead number %d of %d\n", t_id, nthreads); + + + + + return 0; +} \ No newline at end of file diff --git a/src/hellompi.c b/src/hellompi.c new file mode 100644 index 0000000000000000000000000000000000000000..4753d877043ff48859456bccb6ca9e3bc36e0bf7 --- /dev/null +++ b/src/hellompi.c @@ -0,0 +1,103 @@ +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int main(int argc,char *argv[]) { + int numtasks, rank; + char processor_name[MPI_MAX_PROCESSOR_NAME]; + int name_len; + int arr_size = 3; + + + MPI_Status Stat; + MPI_Init(&argc,&argv); + MPI_Comm_size(MPI_COMM_WORLD, &numtasks); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Get_processor_name(processor_name, &name_len); + // printf("Hello from processor %s, task %d of %d, argv[1]: %s\n", + // processor_name, rank, numtasks, argv[1]); + // + + int *result_arr = (int *) malloc(arr_size * numtasks * sizeof(int)); + // int **local_mat = (int **) malloc(arr_size * sizeof(int*)); + int *local_arr = (int *) malloc(arr_size * sizeof(int)); + + // for (int i = 0; i < arr_size; i++) { + // local_mat = (int*) malloc(5 *sizeof(int)); + // } + + // for (int i = 0; i < r; i++) { + // for (int j = i; j < c; j++) { + // local_mat[i][j] = local_mat[j][i] = 0; + // } + // } + + for (int i = 0; i < arr_size; i++) { + local_arr[i] = i*rank*3; + } + + if (rank == 0) { + // int **local_mat = (int **) malloc(arr_size * sizeof(int*)); + + int *temp = (int *) malloc(arr_size * sizeof(int)); + + + + // initiate result arr + for (int i = 0; i < arr_size; i++) { + result_arr[i] = local_arr[i]; + } + + // terima array dari tiap node + for (int i = 1; i < numtasks; i++) { + MPI_Recv( temp, + arr_size*sizeof(int), + MPI_INT, + i, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE + ); + // salin array ke result_arr + // result_arr[i*arr_size] = temp; + memcpy(result_arr+(arr_size*i), + temp, + arr_size* sizeof(int) + ); + + + + // for (int j = 0; j < arr_size && j+(rank*arr_size); j++) { + // result_arr[j+i*arr_size] = temp[j]; + // } + // + // printf("array from node %d\n", i); + // for(int j = 0; j < arr_size; j++) { + // printf("%d ", temp[j]); + // } + // printf("\n"); + } + } else { + MPI_Send( local_arr, + arr_size*sizeof(int), + MPI_INT, + 0, + 0, + MPI_COMM_WORLD + ); + } + + if (rank == 0) { + printf("here is the array you ordered\n"); + for (int i=0; i<arr_size*numtasks; i++){ + printf("%d ", result_arr[i]); + } + printf("\n"); + } + + free(local_arr); + free(result_arr); + + MPI_Finalize(); +} diff --git a/src/paralel.c b/src/paralel.c new file mode 100644 index 0000000000000000000000000000000000000000..0dea0f60ea42163534396360e9082d71f660e1fb --- /dev/null +++ b/src/paralel.c @@ -0,0 +1,186 @@ +#include "dijkstra.h" +#include "util.h" +#include <stdio.h> +#include <mpi.h> +#include <math.h> +#include <string.h> + + +int main(int argc, char *argv[]) +{ + int numprocs, rank; + char processor_name[MPI_MAX_PROCESSOR_NAME]; + int name_len; + + int np = atoi(argv[1]); + int numvertices = atoi(argv[2]); + int chunk_size = ceil(numvertices/np); + // printf("chunk_size : %d\n", chunk_size); + // printf("np : %d\n", np); + // printf("numvertices : %d\n", numvertices); + + + MPI_Status Stat; + MPI_Init(&argc,&argv); + MPI_Comm_size(MPI_COMM_WORLD, &numprocs); + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Get_processor_name(processor_name, &name_len); + + + double start_time, finish_time; + + // generate graph + // printf("about to generate our graph\n"); + long **graph = gen_graph(numvertices); + + // start the timer + MPI_Barrier(MPI_COMM_WORLD); + start_time = MPI_Wtime(); + + + // set chunk size and local src + // int my_first_src = rank * ceil(numvertices/numprocs); + // int my_last_src = my_first_src + chunk_size; + int my_first_src = rank * chunk_size; + // int my_last_src = if (my_first_src+chunk_size < numvertices)? my_first_src+chunk_size:; + + if (rank == 0) { + printf("chunk_size : %d\n", chunk_size); + } + printf("i'm node %d, my_first_src: %d\n", rank, my_first_src); + // printf("i'm node %d, my_last_src: %d\n", rank, my_last_src); + + + + // long **my_results = (long **) malloc(chunk_size * sizeof(long*)); + // allocate 2D array for local result + // printf("initiate my result\n"); + long **my_results = gen_temp(chunk_size, numvertices); + // printf("done initiating my result\n"); + + // find shortest path from each src + for (int i = 0; i+my_first_src < numvertices && i < chunk_size; i++) { + // printf("i'm node %d and currently working on row %d \n", rank, i+my_first_src); + long *dist = dijkstra(graph, numvertices, i+my_first_src); + my_results[i] = dist; + } + // printf("hi i'm node %d and i'm done searching\n", rank); + + + // TBD gathering data from these processes + if ( rank == 0 ) { // gather data from other nodes + long **result = gen_temp(numvertices, numvertices); + // printf("generated empty result matrix\n"); + // long **temp = gen_temp(chunk_size, numvertices); + long *temp = (long*) malloc(numvertices * sizeof(long)); + // printf("generated temp\n"); + + memcpy(result, + my_results, + chunk_size*sizeof(long*)); + printf("copying temp to result\n"); + + for (int i = 1; i < numprocs; i++) { + printf("about to receive local result from node %d\n", i); + + for (int j = 0; j < chunk_size; j++) { // loop buat nerima tiap baris dari node lain + MPI_Recv(temp, + numvertices*sizeof(long), + MPI_LONG, + i, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + // for (int i=0;i<numvertices;i++) { + // printf("%d ", temp[i]); + // } + // printf("\n"); + // printf("alamat result yang mau ditulis: result+ %d\n", (i*chunk_size)+(j*numvertices)); + // memcpy(result+((i*chunk_size)+(j*numvertices)), + // temp, + // chunk_size*sizeof(long)); + for (int k = 0; k < numvertices; k++) { + result[i*chunk_size+j][k] = temp[k]; + } + + + } + + printf("done receiving local result from node %d\n", i); + + // for (int i =0; i < chunk_size; i++) { + // for (int j= 0 ; j < numvertices; j++){ + // printf("%ld ", temp[i][j]); + // } + // printf("\n"); + // } + printf("copying local result from node %d to result\n", i); + + + } + + // for (int i=0; i < numvertices; i++) { + // printf("row %d\n", i); + // for (int j = 0; j < numvertices; j++) { + // printf("%d ", result[i][j]); + // } + // printf("\n"); + // } + // + + char filename[20]; + sprintf(filename, "./output_parallel_%d", numvertices); + printf("about to write output file\n"); + write_result(result, numvertices, filename); + printf("done writing\n"); + + //free result (2d arr) + for(int i = 0; i < numvertices; i++){ + free(result[i]); + } + printf("freeing result\n"); + //free temp (1d arr) + free(temp); + printf("freeing temp\n"); + + + } else { // send my_results to master node + printf("i'm node %d and i'm going to send my result to master\n", rank); + for(int i = 0; i < chunk_size; i++) { + MPI_Send(my_results[i], + chunk_size*sizeof(long), + MPI_LONG, + 0, + 0, + MPI_COMM_WORLD + ); + + } + printf("i'm node %d and i'm just sent my result to master\n", rank); + } + + + // printf("I'm process %d and the distance from vertex 1 to 2 is %d\n", + // rank, + // graph[0][1]); + // + MPI_Barrier(MPI_COMM_WORLD); + finish_time = MPI_Wtime(); + + if (rank == 0) { + printf("elapsed time : %.lf ms\n", (finish_time-start_time)*1000000); + } + + + //free my_results (2d arr) + free(my_results); + printf("freed my_results\n"); + //free graph (2d arr) + free(graph); + printf("freed graph\n"); + + MPI_Finalize(); + + + return 0; +} \ No newline at end of file diff --git a/src/paralel_openmp.c b/src/paralel_openmp.c new file mode 100644 index 0000000000000000000000000000000000000000..cdfc6fd1fc8a8e793d0ac3ce113356125c56694a --- /dev/null +++ b/src/paralel_openmp.c @@ -0,0 +1,77 @@ +#include <omp.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include "util.h" +#include "dijkstra.h" +#include "boolean.h" + + +static double get_micros(void) { + struct timespec ts; + timespec_get(&ts, TIME_UTC); + return ((double)((long)ts.tv_sec * 1000000000L + ts.tv_nsec)/1000); +} + + +int main(int argc, char const *argv[]) +{ + // int thread_count = strtol(argv[1], NULL, 10); + int num_vertices = atoi(argv[2]); + // int tid; + + // time + double start_time, end_time, total_time; + + // generate graph and result matrix + long **result = gen_temp(num_vertices, num_vertices); + long **graph = gen_graph(num_vertices); + + long *temp = (long*) malloc(sizeof(long)*num_vertices); + + // init time + total_time = 0; + + #pragma omp barrier + + // start time + start_time = get_micros(); + + // share the work to all the threads + #pragma omp parallel for private(temp) + for (int i = 0; i < num_vertices; i++) { + // tid = omp_get_thread_num(); + // printf("i: %d, by the way i'm thread %d\n", i, tid); + + // get the shortest path from each vertex + // get time execution + + + temp = dijkstra(graph, num_vertices, i); + + // kalo barrier nya disini error + end_time = get_micros(); + + + // put it in result + // #pragma omp critical(result) + // { + for (int j = 0; j < num_vertices; j++) { + result[i][j] = temp[j]; + } + // } + + total_time += end_time - start_time; + } + // #pragma omp barrier + // total_time += end_time - start_time; + + char filename[20]; + sprintf(filename, "./output_parallel_%d", num_vertices); + printf("about to write output file\n"); + write_result(result, num_vertices, filename); + printf("done writing\n"); + printf("processing time: %0.04lf us ...\n",total_time); + + return 0; +} \ No newline at end of file diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 0000000000000000000000000000000000000000..ec3acbbc4eb004484b8f960f2ba2e5447418e611 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include "dijkstra.h" +#include "util.h" + + + + + +int main(int argc, char const *argv[]) +{ + time_t start,end; + + if (argc > 1) { + + int n = atoi(argv[1]); + printf("n: %d\n", n); + + // start timer + start=clock(); + // generate graph + long **graph = gen_graph(n); + + // result matrix + long **result = gen_temp(n, n); + + for (int i = 0; i < n; i++) { + long *dist = dijkstra(graph, n, i); + result[i] = dist; + } + //end timer + end=clock(); + + //elapsed time + float t = (float)(end-start)/CLOCKS_PER_SEC; + printf("Elapsed time (in millisecond): %f", t*1000000); + + char filename[20]; + sprintf(filename, "./output_serial_%d", n); + + write_result(result, n, filename); + + free(result); + free(graph); + + } else { + printf("usage : serial [n]\n"); + } + + return 0; +} + diff --git a/src/test b/src/test new file mode 100755 index 0000000000000000000000000000000000000000..465cd19b9177f81e395688fb030a90603f419852 Binary files /dev/null and b/src/test differ diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000000000000000000000000000000000000..f5bda7e30a701fd0172c92445434e8108198a763 --- /dev/null +++ b/src/test.c @@ -0,0 +1,37 @@ +#include "dijkstra.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +int main(int argc, char const *argv[]) +{ + long **result = gen_temp(10,5); + long **first = gen_temp(5,5); + long **second = gen_temp(5,5); + + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 5; j++) { + first[i][j] = 1 * i * j; + second[i][j] = 2 * i * j; + } + } + + memcpy(result, + first, + 5 * sizeof(int*) + ); + + memcpy(result+5, + second, + 5 * sizeof(int*) + ); + + for (int i =0; i < 10; i++) { + for (int j =0; j < 5; j++) { + printf("%d ", result[i][j]); + } + printf("\n"); + } + + return 0; +} \ No newline at end of file diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000000000000000000000000000000000000..f3fece500221c440128976be80341a5e3655e11d --- /dev/null +++ b/src/util.c @@ -0,0 +1,32 @@ +#include "util.h" + + +/** + * write matrix of shortest distance from vertex i to j + * @param graph 2D array + */ +void write_result(long **m, int n, char filename[]) { + + FILE *outfile; + + printf("here we go, writing file again\n"); + outfile = fopen(filename,"w"); + printf("file %s opened\n", filename); + if (outfile == NULL) { + printf("Error!\n"); + exit(1); + } + + printf("Writing output...\n"); + for (int i = 0; i < n; i++) { + // printf("about to write row %d\n", i); + for (int j = 0; j < n; j++) { + fprintf(outfile, "%ld ", m[i][j]); + } + // printf("just write row %d\n", i); + fprintf(outfile, "\n"); + } + + printf("Done.\n"); + +} \ No newline at end of file diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000000000000000000000000000000000000..f58a1b1730ed5f8d0df8ce8a133f202baeba7e30 --- /dev/null +++ b/src/util.h @@ -0,0 +1,14 @@ +#ifndef UTIL_H +#define UTIL_H +#include <stdio.h> +#include <stdlib.h> + +/** + * write matrix of shortest distance from vertex i to j + * @param m 2D array, m[i][j] = m[j][i] = shortest distance from vertex i to j + * @param n dimension of matrix m + */ +void write_result(long **m, int n, char filename[]); + + +#endif \ No newline at end of file