diff --git a/README.md b/README.md index f77e0e810edfc34916acba1e68f804cc665adacd..1577b54bc39e270f3c26bed272b0e23984ac83fc 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,89 @@ -# Announcement +<h1 align="center"> + <b> + <br> + # Tugas Besar 2 IF3230 Sistem Paralel dan Terdistribusi + <br> + </b> +</h1> -Beberapa file yang harus ada dalam repositori tersebut diantaranya: -* Direktori src yang berisi source code yang anda buat. -* File output yang berisi hasil uji dijkstra algorithm pada data uji. -* Makefile. Buatlah sehingga kompilasi program dapat dilakukan hanya dengan pemanggilan command ’make’ saja. -* File README.md yang berisi: - * Petunjuk penggunaan program. - * Pembagian tugas. Sampaikan dalam list pengerjaan untuk setiap mahasiswa. Sebagai contoh: XXXX mengerjakan fungsi YYYY, ZZZZ, dan YYZZ. - * Laporan pengerjaan, dengan struktur laporan sesuai dengan deskripsi pada bagian sebelumnya. +<h2 align="center"> + <b> + <br> + OpenMP - Dijkstra Algorithm + <br> + <br> + </b> +</h2> +## Petunjuk Penggunaan Program +* Compile: <br> + ketikan ```make``` pada direktori tempat ```makefile``` berada +* Run: <br> + ketikan ```run``` pada direktori tempat ```makefile``` berada + +## Laporan Pengerjaan +### Deskripsi Solusi Paralel +Solusi paralel yang dilakukan adalah data parallelism karena data yang ada dibagi-bagi ke *thread* yang ada, sehingga *thread* pusat hanya bertugas untuk menerima hasil dari pemrosesan algoritma dijkstra yang dilakukan oleh *thread* lain. Hasil pemrosesan algoritma dijkstra merupakan satu baris dari matriks jarak antar node. <br> +<div align="center"> + <img src="./assets/data_task_parallelism.png" width="300" height="200"/> +</div> + +Cara kerja program: +1. Program menginisiasi graf dalam bentuk matriks berukuran N x N +2. Untuk setiap baris dan kolom, program mengisi nilai *random* yang didapat dari funsi ```rand()``` dengan seed ```13517020``` atau ```13517137``` +3. Program mulai menjalankan algoritma dijkstra untuk mencari nilai cost minimum yang dibutuhkan dari node-x untuk mencapai node-y + * Jika jumlah *thread* yang digunakan hanya 1, program akan menjalankan algoritma dijkstra secara serial + * Jika jumlah *thread* yang digunakan lebih dari 1, program akan menjalankan algoritma dijkstra secara paralel + * *thread* dengan nilai ```rank = 0``` menerima hasil pemrosesan graf menggunakan algoritma dijkstra dari *thread-thread* lain + * *thread* dengan nilai ```rank ≠0``` melakukan pemrosesan graf menggunakan algoritma dijkstra untuk dikirimkan ke *thread* dengan nilai ```rank = 0``` + +### Analisis Solusi +* Kelebihan: + * Setiap *thread* membaca dari satu memory yang sama + * Jika *thread* yang digunakan hanya 1 program akan langsung menjalankan algoritma dijkstra secara serial + * Lebih hemat *memory space* karena alokasi *memory* menyesuaikan input jumlah nodes +* Kelemahan: + * Karena menggunakan satu server, perbedaan waktu yang dibutuhkan antara 1 *thread*, 2 *thread*, 3 *thread*, dst. tidak berbeda jauh +* Solusi yang lebih baik: + * Dapat menggunakan beberapa server tetapi disaat yang bersamaan masih dapat mengakses *memory* yang sama + +### Jumlah Thread yang Digunakan +6 *thread* karena dari hasil percobaan kami, waktu yang dibutuhkan untuk mendapatkan solusi dengan menggunakan 6 thread jauh lebih cepat dibandingkan jika menggunakan 5 thread, 4 thread, 3 thread, 2 thread dan 1 thread (serial). Hal ini disebabkan oleh jumlah data yang dibagi untuk setiap thread menurun sesuai dengan banyaknya thread yang digunakan sehingga thread dapat menyelesaikan tugasnya lebih cepat. +<div align="center"> + <img src="./assets/data_parallelism.png" width="300" height="200"/> +</div> + +### Pengukuran Kinerja Algoritma Paralel dengan Serial +| Jumlah Thread | Jumlah Node | Waktu 1 (μs) | Waktu 2 (μs) | Waktu 3 (μs) | +|:-------------:|:-----------:|:-------------:|:-------------:|:-------------:| +| 1 (Serial) | 100 | 11809.000 | 11341.000 | 11738.000 | +| 1 (Serial) | 500 | 1330483.000 | 1336266.000 | 1346888.000 | +| 1 (Serial) | 1000 | 11306142.000 | 11269185.000 | 11353796.000 | +| 1 (Serial) | 3000 | 328869828.000 | 322524927.000 | 320788807.000 | +| 2 (Paralel) | 100 | 8630.000 | 8863.000 | 9170.000 | +| 2 (Paralel) | 500 | 1344506.000 | 1341028.000 | 1353119.000 | +| 2 (Paralel) | 1000 | 11188346.000 | 11266470.000 | 11314343.000 | +| 2 (Paralel) | 3000 | 326371659.000 | 322214533.000 | 324375813.000 | +| 3 (Paralel) | 100 | 11494.000 | 12541.000 | 13622.000 | +| 3 (Paralel) | 500 | 1315593.000 | 1350490.000 | 1337863.000 | +| 3 (Paralel) | 1000 | 11335433.000 | 11406718.000 | 11197439.000 | +| 3 (Paralel) | 3000 | 329445759.000 | 323444526.000 | 379086253.000 | +| 4 (Paralel) | 100 | 11883.000 | 11533.000 | 12161.000 | +| 4 (Paralel) | 500 | 1339848.000 | 1339332.000 | 1344472.000 | +| 4 (Paralel) | 1000 | 11513116.000 | 11305632.000 | 11336602.000 | +| 4 (Paralel) | 3000 | 328357001.000 | 324471460.000 | 323581156.000 | +| 5 (Paralel) | 100 | 12112.000 | 11359.000 | 11571.000 | +| 5 (Paralel) | 500 | 1335812.000 | 1341126.000 | 1363780.000 | +| 5 (Paralel) | 1000 | 11310832.000 | 11268102.000 | 11176265.000 | +| 5 (Paralel) | 3000 | 323646028.000 | 328808488.000 | 383983323.000 | +| 6 (Paralel) | 100 | 11432.000 | 11358.000 | 11560.000 | +| 6 (Paralel) | 500 | 1342867.000 | 1371984.000 | 1333992.000 | +| 6 (Paralel) | 1000 | 11332027.000 | 11301639.000 | 11337420.000 | +| 6 (Paralel) | 3000 | 321272669.000 | 324136484.000 | 323526201.000 | + +### Analisis Perbandingan Kinerja Serial dan Paralel +Algoritma dijkstra yang dijalankan secara serial memakan waktu tidak jauh berbeda dibandingkan dengan algoritma dijkstra yang dijalankan secara paralel karena jumlah server yang digunakan sama antara serial dengan paralel. + +## Pembagian Tugas +* 13517020 mengerjakan convert fungsi algoritma dijkstra openMPI to openMP, makefile dan laporan +* 13517137 mengerjakan convert fungsi algoritma dijkstra openMPI to openMP, makefile dan laporan \ No newline at end of file diff --git a/assets/data_parallelism.png b/assets/data_parallelism.png new file mode 100644 index 0000000000000000000000000000000000000000..9285b180897c59461cf96ac1aeb6924c3e8611dd Binary files /dev/null and b/assets/data_parallelism.png differ diff --git a/assets/data_task_parallelism.png b/assets/data_task_parallelism.png new file mode 100644 index 0000000000000000000000000000000000000000..53b0e1cf654a3260b244a4c6f164416be8f1b2d6 Binary files /dev/null and b/assets/data_task_parallelism.png differ diff --git a/copy.sh b/copy.sh new file mode 100644 index 0000000000000000000000000000000000000000..2fda7219f9dbb1a5a41a35f9cd4d1176a4289294 --- /dev/null +++ b/copy.sh @@ -0,0 +1,4 @@ +ssh 13517020@167.205.37.150 'mkdir -p src' +ssh 13517137@167.205.37.150 'mkdir -p src' +scp $1 13517020@167.205.35.150:~/src +scp $1 13517137@167.205.35.150:~/src diff --git a/makefile b/makefile new file mode 100644 index 0000000000000000000000000000000000000000..09ca8c21f4dfb26329e9fcdb1bb780662344ae69 --- /dev/null +++ b/makefile @@ -0,0 +1,7 @@ +_OBJ = omp_dijkstra + +make: + gcc -g -Wall -o $(_OBJ) src/$(_OBJ).c -fopenmp + +run: + ./$(_OBJ) 100 6 \ No newline at end of file diff --git a/out/matrix3000.txt b/out/matrix3000.txt new file mode 100644 index 0000000000000000000000000000000000000000..45863454b88c1007b9c96fd265de5ea75952cb0d Binary files /dev/null and b/out/matrix3000.txt differ diff --git a/out/result3000.txt b/out/result3000.txt new file mode 100644 index 0000000000000000000000000000000000000000..49f256d17b3d98658d9ccd02d5e6ac6ce85a89ed Binary files /dev/null and b/out/result3000.txt differ diff --git a/src/omp_dijkstra.c b/src/omp_dijkstra.c new file mode 100644 index 0000000000000000000000000000000000000000..9b5fe8ae768d51826a3cc9e687034af7462bb289 --- /dev/null +++ b/src/omp_dijkstra.c @@ -0,0 +1,207 @@ +// Copyright www.computing.llnl.gov +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <limits.h> +#include <omp.h> +#include <assert.h> +#include <time.h> + +int minDistance(long dist[], bool sptSet[], long V) +{ + // Initialize min value + int min = INT_MAX, min_index; + + for (int v = 0; v < V; v++) + { + if ((sptSet[v] == false) && (dist[v] <= min)) + { + min = dist[v], min_index = v; + } + } + + return min_index; +} + +void dijkstra(long src, long V, long **graph, long *dist) +{ + // sptSet[i] will be true if vertex i is included in shortest path tree or shortest distance from src to i is finalized + bool sptSet[V]; + + // Initialize all distances as INFINITE and stpSet[] as false + for (int i = 0; i < V; i++) + { + dist[i] = INT_MAX, sptSet[i] = false; + } + + // Distance of source vertex from itself is always 0 + dist[src] = 0; + + // Find shortest path for all vertices + for (int count = 0; count < V - 1; count++) + { + // Pick the minimum distance vertex from the set of vertices not yet processed. u is always equal to src in the first iteration. + int u = minDistance(dist, sptSet, V); + + // Mark the picked vertex as processed + sptSet[u] = true; + + // Update dist value of the adjacent vertices of the picked vertex. + for (int v = 0; v < V; v++) + { + // Update dist[v] only if is not in sptSet, there is an edge from u to v, and total weight of path from src to v through u is smaller than current value of dist[v] + if (!sptSet[v] && graph[u][v] && (dist[u] != INT_MAX) && (dist[u] + graph[u][v] < dist[v])) + { + dist[v] = dist[u] + graph[u][v]; + } + } + } +} + +void solution(long **matrix, long **newmatrix, long nodes); + +int main(int argc, char *argv[]) +{ + // Set rand() seed + srand(13517020); + /* total cost == 0 + size | total + 100 | 0 + 500 | 4 + 1000 | 18 + 3000 | 135 + 5000 | 380 + */ + // srand(13517137); + /* total cost == 0 + size | total + 100 | 0 + 500 | 2 + 1000 | 13 + 3000 | 126 + 5000 | 360 + */ + + if (argc < 3) + { + fprintf(stderr, "error: missing command line arguments\n"); + exit(1); + } + else + { + // Inititate graph + long nodes = atoi(argv[1]); + int thread_count = strtol(argv[2], NULL, 10); + long **matrix = (long **)malloc(nodes * sizeof(long *)); + + for (int i = 0; i < nodes; i++) + { + matrix[i] = (long *)malloc(nodes * sizeof(long)); + } + + assert(matrix != NULL); + + // Build graph + for (int i = 0; i < nodes; i++) + { + for (int j = 0; j < nodes; j++) + { + if (i == j) + { + matrix[i][j] = 0; + } + else + { + matrix[i][j] = rand(); + } + } + } + + long **newmatrix = (long **)malloc(nodes * sizeof(long *)); + + for (int i = 0; i < nodes; i++) + { + newmatrix[i] = (long *)malloc(nodes * sizeof(long)); + } + +// Dijkstra Algorithm +// MPI_Status Stat; +// MPI_Init(NULL, NULL); +// MPI_Comm_size(MPI_COMM_WORLD, &numtasks); +// MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#pragma omp parallel num_threads(thread_count) + solution(matrix, newmatrix, nodes); + + // Dealocation + for (int i = 0; i < nodes; i++) + { + free(matrix[i]); + } + + free(matrix); + + for (int i = 0; i < nodes; i++) + { + free(newmatrix[i]); + } + + free(newmatrix); + } + return 0; +} + +void solution(long **matrix, long **newmatrix, long nodes) +{ + clock_t begin = clock(); + int numtasks, rank = 1; + rank = omp_get_thread_num(); + numtasks = omp_get_num_threads(); + + for (int i = rank; i < nodes; i += numtasks) + { + dijkstra(i, nodes, matrix, newmatrix[i]); + // printf("Completing part %d with processor %d\n", i, rank); + // MPI_Send(newmatrix[i], nodes, MPI_INT, 0, i, MPI_COMM_WORLD); + } + +#pragma omp barrier + + if (rank == 0) + { + clock_t end = clock(); + // printf("Printing to file"); + // Write to file + FILE *fp; + fp = fopen("old_matrix.txt", "w"); + fprintf(fp, "Old matrix:\n"); + + for (int i = 0; i < nodes; i++) + { + for (int j = 0; j < nodes; j++) + { + fprintf(fp, "%ld ", matrix[i][j]); + } + + fprintf(fp, "\n"); + } + + fclose(fp); + + fp = fopen("result.txt", "w"); + fprintf(fp, "New matrix:\n"); + + for (int i = 0; i < nodes; i++) + { + for (int j = 0; j < nodes; j++) + { + fprintf(fp, "%ld ", newmatrix[i][j]); + } + + fprintf(fp, "\n"); + } + + fprintf(fp, "Solution found in: %.3f microseconds\n", ((double)(end - begin) / CLOCKS_PER_SEC) * 1000000); + printf("Solution found in: %.3f microseconds\n", ((double)(end - begin) / CLOCKS_PER_SEC) * 1000000); + fclose(fp); + } +} \ No newline at end of file