|
| 1 | +/* |
| 2 | + * This file contains code that is the parallelized version of |
| 3 | + * Floyd Warshall: All-Pair-Shortest-Path algorithm, written in C using |
| 4 | + * OpenMP. Floyd Warshall algorithm basically finds all pair shortest |
| 5 | + * paths in a weighted graph and use dynamic programming technique to |
| 6 | + * solve the problem. |
| 7 | + * |
| 8 | + * Compiling: via 1) GNU |
| 9 | + * 2) Oracle Solaris |
| 10 | + * |
| 11 | + * 1) gcc -o floyd_warshal_omp -fopenmp floyd_warshal_omp.c |
| 12 | + * |
| 13 | + * - or - |
| 14 | + * |
| 15 | + * 2) cc -o floyd_warshal_omp -xopenmp floyd_warshal_omp.c |
| 16 | + * |
| 17 | + * Running: |
| 18 | + * |
| 19 | + * ./floyd_warshal_omp [DATA_FILE_NAME] [NUMBER_OF_THREADS] |
| 20 | + * |
| 21 | + * Example: ./floyd_warshal_omp test_data_1000.dat 4 |
| 22 | + * |
| 23 | + * |
| 24 | + * File: floyd_warshal_omp.c Author: Inteasar Haider |
| 25 | + * Date: January 01, 2017 Version: V1.0 |
| 26 | + * |
| 27 | + */ |
| 28 | + |
| 29 | +#include <omp.h> |
| 30 | +#include <string.h> |
| 31 | +#include <stdio.h> |
| 32 | +#include <stdlib.h> |
| 33 | +#include <limits.h> |
| 34 | +#include <sys/time.h> |
| 35 | + |
| 36 | +/* Print matrix after initialization and calculating shortest path |
| 37 | + * 1 = Print matrix |
| 38 | + * 0 = Do not print matrix |
| 39 | + * |
| 40 | + */ |
| 41 | +#define PRINT_MATRIX 0 |
| 42 | +#define MIN_NODES 4 /* Minimun nodes in graph */ |
| 43 | +#define DATA_FOLDER "../test_data/" |
| 44 | + |
| 45 | +static void calculate_all_pair_shortest_path (void); |
| 46 | +static void print_distance_adjacency_matrix (void); |
| 47 | +static void calculate_execution_time (struct timeval time_start, |
| 48 | + struct timeval time_end); |
| 49 | +static int read_data_from_file (char data_file_name[]); |
| 50 | + |
| 51 | +/* adjacency matrix to store distance between nodes of directed graph */ |
| 52 | +int **nodes_distance; |
| 53 | +int num_nodes; |
| 54 | + |
| 55 | +int main (int argc, char *argv[]) |
| 56 | +{ |
| 57 | + int num_threads; /* threads to start upon execution */ |
| 58 | + struct timeval time_start, time_end; /* to hold start & end time */ |
| 59 | + |
| 60 | + /* File name and number of threads to spawn will be passed via |
| 61 | + * command line as CLI parameter |
| 62 | + * First param (argv[1]) will be file name |
| 63 | + * Second param (argv[2]) will be number of threads to spawn |
| 64 | + */ |
| 65 | + if( argc == 3 ) { |
| 66 | + read_data_from_file (argv[1]); |
| 67 | + num_threads = atoi(argv[2]); |
| 68 | + } else { |
| 69 | + printf ("==> Error: Data file name (e.g: test_data_10.dat) as 1st " |
| 70 | + "and number of threads as 2nd parameter is not passed " |
| 71 | + "from command line\n\n"); |
| 72 | + return EXIT_FAILURE; |
| 73 | + } |
| 74 | + |
| 75 | + printf ("==> Spawning %d threads to calculate shortest paths between" |
| 76 | + " %d nodes..\n\n", num_threads, num_nodes); |
| 77 | + |
| 78 | + print_distance_adjacency_matrix (); |
| 79 | + |
| 80 | + gettimeofday (&time_start, NULL); |
| 81 | + |
| 82 | + /* entering into the parallel region */ |
| 83 | + #pragma omp parallel num_threads(num_threads) shared(nodes_distance) |
| 84 | + calculate_all_pair_shortest_path (); |
| 85 | + /* exiting from the parallel region */ |
| 86 | + |
| 87 | + gettimeofday (&time_end, NULL); |
| 88 | + |
| 89 | + calculate_execution_time (time_start, time_end); |
| 90 | + |
| 91 | + print_distance_adjacency_matrix (); |
| 92 | + |
| 93 | + free(nodes_distance); |
| 94 | + return EXIT_SUCCESS; |
| 95 | +} |
| 96 | + |
| 97 | +/* This routine will be executed in parallel region and it's |
| 98 | + * responsibility is to calculate shortest path and update shorter |
| 99 | + * path distance in nodes_distance matrix. |
| 100 | + * |
| 101 | + * num_nodes will be evenly distributed among all threads and each |
| 102 | + * thread will perform calculation simultaneously on given dataset to |
| 103 | + * find the shortest distance between two nodes i and j via one |
| 104 | + * intermediate node i.e K at a time and update, if found, shortest |
| 105 | + * path in the nodes_distance matrix. |
| 106 | + * |
| 107 | + * Once an iteration of an intermediate node i.e 'K' is done, all the |
| 108 | + * threads will wait for others before starting the next iteration of |
| 109 | + * intermediate node and that iteration will run (num_nodes-1) times. |
| 110 | + * |
| 111 | + * input parameters: none |
| 112 | + * output parameters: nodes_distance will have all shortest paths |
| 113 | + * return value: none |
| 114 | + * |
| 115 | + */ |
| 116 | +void calculate_all_pair_shortest_path(void) |
| 117 | +{ |
| 118 | + int possible_short_dist; /* to hold distance between i and j via k */ |
| 119 | + |
| 120 | + for (int k = 0; k < num_nodes; ++k) |
| 121 | + { |
| 122 | + /* |
| 123 | + * Wait for all threads to complete the iteration before we do |
| 124 | + * shortest path calculations on the adjacency matrix for next |
| 125 | + * intermediate node |
| 126 | + * |
| 127 | + */ |
| 128 | + # pragma omp barrier |
| 129 | + |
| 130 | + # pragma omp for |
| 131 | + for (int i = 0; i < num_nodes; ++i) |
| 132 | + { |
| 133 | + for (int j = 0; j < num_nodes; ++j) |
| 134 | + { |
| 135 | + /* if both nodes (i & j) are not same and path between node_i |
| 136 | + * and Node_j via node_k exists (i.e. anything except 0) |
| 137 | + * |
| 138 | + */ |
| 139 | + if ( (nodes_distance[i][k] * nodes_distance[k][j] != 0) |
| 140 | + && (i != j) ) |
| 141 | + { |
| 142 | + possible_short_dist = nodes_distance[i][k] + |
| 143 | + nodes_distance[k][j]; |
| 144 | + |
| 145 | + /* If path exists between i and j and that path distance |
| 146 | + * is already lesser than newly calculated distance |
| 147 | + * (via Node_k) do not update anything and continue with |
| 148 | + * other possibilities |
| 149 | + * |
| 150 | + */ |
| 151 | + if ( (nodes_distance[i][j] <= possible_short_dist) && |
| 152 | + (nodes_distance[i][j] != 0) ) |
| 153 | + { |
| 154 | + continue; |
| 155 | + } |
| 156 | + |
| 157 | + /* Replace the current distance with new shortest distance */ |
| 158 | + nodes_distance[i][j] = possible_short_dist; |
| 159 | + } |
| 160 | + } |
| 161 | + } |
| 162 | + } |
| 163 | +} |
| 164 | + |
| 165 | +/* Responsibility of this routine is to calculate final execution time |
| 166 | + * of the program |
| 167 | + * |
| 168 | + * input parameters: Two params of timeval struct |
| 169 | + * a) time_start: time when program entered in to |
| 170 | + * parallel regions and threads were spawned |
| 171 | + * b) time_end: when all threads completed working |
| 172 | + * |
| 173 | + * output parameters: Printing time spent on the console |
| 174 | + * return value: none |
| 175 | + * |
| 176 | + */ |
| 177 | +void calculate_execution_time (struct timeval time_start, |
| 178 | + struct timeval time_end) |
| 179 | +{ |
| 180 | + long long execution_time = 1000000LL |
| 181 | +* (time_end.tv_sec - time_start.tv_sec) |
| 182 | ++ (time_end.tv_usec - time_start.tv_usec); |
| 183 | + |
| 184 | + double time_spent = (double) execution_time / 1000000; |
| 185 | + printf ("==> Finished calculating shortest path in %f seconds.\n\n", |
| 186 | + time_spent ); |
| 187 | +} |
| 188 | + |
| 189 | +/* Responsibility of this routine is to print two dimensional matrix |
| 190 | + * that contains the distance between the nodes of given graph |
| 191 | + * |
| 192 | + * input parameters: none |
| 193 | + * output: distance matrix printed on the console |
| 194 | + * return value: none |
| 195 | + * side effects: could crash console if a huge matrix is being |
| 196 | + * printed |
| 197 | + * |
| 198 | + */ |
| 199 | +void print_distance_adjacency_matrix (void) |
| 200 | +{ |
| 201 | + if(PRINT_MATRIX==1) |
| 202 | + { |
| 203 | + int i, j; |
| 204 | + printf(" "); |
| 205 | + |
| 206 | + for (i = 0; i < num_nodes; ++i) |
| 207 | + { |
| 208 | + printf("%4c", 'A' + i); |
| 209 | + } |
| 210 | + |
| 211 | + printf("\n"); |
| 212 | + |
| 213 | + for (i = 0; i < num_nodes; ++i) |
| 214 | + { |
| 215 | + printf("%4c", 'A' + i); |
| 216 | + for (j = 0; j < num_nodes; ++j) |
| 217 | + { |
| 218 | + printf("%4d", nodes_distance[i][j]); |
| 219 | + } |
| 220 | + printf("\n"); |
| 221 | + } |
| 222 | + |
| 223 | + printf("\n"); |
| 224 | + } |
| 225 | +} |
| 226 | + |
| 227 | +/* Responsibility of this routine is to populate the distance matrix |
| 228 | + * with the test data being read from file |
| 229 | + * |
| 230 | + * input parameters: File name passed as a CLI Parameter |
| 231 | + * output: distance matrix with test data |
| 232 | + * return value: 1 if unable to populate data |
| 233 | + * 0 if data is populated successfully |
| 234 | + * side effects: could crash program if test data file is |
| 235 | + * missing or contain in un-appropriate data |
| 236 | + * |
| 237 | + */ |
| 238 | +int read_data_from_file (char data_file_name[]) |
| 239 | +{ |
| 240 | + FILE *data_file; |
| 241 | + int temp = 0; /* hold data read from file temporarily */ |
| 242 | + int mem_size; /* memory to allocate for adjacency matrix */ |
| 243 | + |
| 244 | + char final_path[40]; |
| 245 | + |
| 246 | + strcpy( final_path, DATA_FOLDER ); /* copy data folder path */ |
| 247 | + strcat( final_path, data_file_name ); /* create file path */ |
| 248 | + |
| 249 | + data_file = fopen (final_path, "r"); |
| 250 | + |
| 251 | + if(data_file == NULL) |
| 252 | + { |
| 253 | + printf ("==> Cannot proceed, unable to find data file ..\n\n"); |
| 254 | + exit(EXIT_FAILURE); |
| 255 | + } |
| 256 | + |
| 257 | + /* The first line will be the number of vertices */ |
| 258 | + fscanf (data_file, "%d", &num_nodes); |
| 259 | + |
| 260 | + if(num_nodes <= MIN_NODES) /* graph should not be empty */ |
| 261 | + { |
| 262 | + printf ("==> Cannot proceed, invalid graph size given ..\n\n"); |
| 263 | + exit(EXIT_FAILURE); |
| 264 | + } |
| 265 | + |
| 266 | + /* Calculating memory needed for adjacency matrix */ |
| 267 | + mem_size = (num_nodes * sizeof(int*)) + |
| 268 | + (num_nodes * num_nodes * sizeof(int)); |
| 269 | + |
| 270 | + /* Dynamically allocating memory for the adjacency matrix */ |
| 271 | + nodes_distance = malloc (mem_size); |
| 272 | + |
| 273 | + /* Set the row indexes as pointers to the columns */ |
| 274 | + for (int i = 0; i < num_nodes; ++i) |
| 275 | + { |
| 276 | + nodes_distance[i] = (int*)(nodes_distance + num_nodes + 1) + |
| 277 | + (i * num_nodes); |
| 278 | + } |
| 279 | + |
| 280 | + printf("%d num_nodes being read from data file... \n", num_nodes); |
| 281 | + |
| 282 | + for (int i = 0; i < num_nodes; i++) |
| 283 | + { |
| 284 | + for (int j = 0; j < num_nodes; j++) |
| 285 | + { |
| 286 | + if (fscanf (data_file, "%d", &temp) == EOF) |
| 287 | + { |
| 288 | +break; |
| 289 | + } |
| 290 | + else |
| 291 | + { |
| 292 | + if (i == j) |
| 293 | +{ |
| 294 | + /* distance between same node should be set zero */ |
| 295 | + nodes_distance[i][j] = 0; |
| 296 | +} |
| 297 | +else |
| 298 | +{ |
| 299 | + /* reading data from file */ |
| 300 | + nodes_distance[i][j]= temp; |
| 301 | +} |
| 302 | + } |
| 303 | + } |
| 304 | + } |
| 305 | + fclose (data_file); |
| 306 | + |
| 307 | + return EXIT_SUCCESS; |
| 308 | +} |
0 commit comments