KMP-MPI/src/parallel.c

193 lines
5.4 KiB
C

#include <stdio.h>
#include <string.h>
#include "kmp.h"
#include "util.h"
#include <mpi.h>
#include <malloc.h>
#ifdef TIME
#include <papi.h>
#endif
#define MASTER 0
#define DEFAULT_TAG 17
void find_end(int, char *, char *, int **, int *);
void search_for_splitted_pattern(int *residue, int *match_number, int **matches);
void calculate_absolute_indices(int match_number, int *matches);
void collect_results(int *match_number, int *matches);
int rank, size;
int text_len; // length of all text
int private_text_len; // length of private text
int pattern_len; //length of the pattern
char *text;
char *pattern;
int remain = 0;
int *text_piece;
int *displacements;
char *private_text;
int *match_numbers;
int *total_matches;
int total_match_number;
int main(int argc, char **argv) {
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Barrier(MPI_COMM_WORLD);
#ifdef TIME
long_long start_time = PAPI_get_real_usec();
#endif
char *text_file_path = get_text_file(argc, argv);
private_text = read_file_portion(text_file_path, size, rank, &private_text_len, &remain);
pattern = read_file("data/pattern.txt", &pattern_len);
#ifdef LOG
printf("%d -> input: %s\n", rank, private_text);
printf("%d -> text len: %d\n", rank, private_text_len);
#endif
// create and build lps array
int lps[pattern_len];
create_lps(pattern, pattern_len, lps);
// search for matches
int match_number = 0;
int residue;
#ifdef TIME
long_long start_search = PAPI_get_real_usec();
#endif
int *matches = search_pattern(private_text, pattern, lps, &match_number, &residue);
search_for_splitted_pattern(&residue, &match_number, &matches);
#ifdef TIME
long_long stop_search = PAPI_get_real_usec();
#endif
//free(private_text);
calculate_absolute_indices(match_number, matches);
#ifdef LOG
printf("%d -> result number: %d\n", rank, match_number);
#endif
#ifdef TIME
long_long start_collect = PAPI_get_real_usec();
#endif
collect_results(&match_number, matches);
#ifdef TIME
long_long end_time = PAPI_get_real_usec();
#endif
MPI_Finalize();
if (rank == MASTER) {
printf("total matches: %d\n", total_match_number);
#ifdef LOG
printf("matches index: ");
print_array(total_matches, total_match_number);
#endif
#ifdef TIME
printf("total elapsed: %d\n", end_time - start_time);
printf("search elapsed: %d\n", stop_search - start_search);
printf("collect elapsed: %d\n", end_time - start_collect);
#endif
}
}
void find_end(int residue, char *pattern, char *text, int **matches, int *match_number) {
int pattern_index = residue;
int text_index = 0;
int text_len = strlen(text);
int pattern_len = strlen(pattern);
if (pattern_len - residue > text_len) return;
while (pattern_index < pattern_len && pattern[pattern_index] == text[text_index]) {
pattern_index++;
text_index++;
}
if (pattern_index != pattern_len) return;
*match_number = *match_number + 1;
*matches = (int *) realloc(*matches, *match_number * sizeof(int));
(*matches)[*match_number - 1] = -residue;
}
void search_for_splitted_pattern(int *residue, int *match_number, int **matches) {
// send the residue to the next process
if (rank + 1 != size) {
MPI_Request request;
MPI_Isend(residue, 1, MPI_INT, rank + 1, DEFAULT_TAG, MPI_COMM_WORLD, &request);
}
// receiving the residue from the previous process
int other_residue = 0;
if (rank != 0) {
MPI_Recv(&other_residue, 1, MPI_INT, rank - 1, DEFAULT_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if (other_residue != 0)
// search for a split match
find_end(other_residue, pattern, private_text, matches, match_number);
}
}
void calculate_absolute_indices(int match_number, int *matches) {
// transformation of match indices from relative to absolute position.
int shift = rank * (private_text_len - remain); // the rest is zero for all but the last process
apply_shift(shift, matches, match_number);
}
void collect_results(int *match_number, int *matches) {
if (rank == MASTER) {
// allocation for the array containing the number of matches of each process
match_numbers = (int *) malloc(sizeof(int) * size);
}
// collection of the number of matches from each process
MPI_Gather(match_number, 1, MPI_INT, match_numbers, 1, MPI_INT, MASTER, MPI_COMM_WORLD);
if (rank == MASTER) {
// preparation of the data structures needed to receive match indices from all processes
total_match_number = sum_array(match_numbers, size);
total_matches = (int *) malloc(sizeof(int) * total_match_number);
displacements = (int *) malloc(sizeof(int) * size);
displacements[0] = 0;
for (int i = 0; i < size - 1; ++i) {
displacements[i + 1] = displacements[i] + match_numbers[i];
}
}
// collection of match indices from each process
// gatherv is necessary because each process will have a different number of matches
MPI_Gatherv(
matches,
*match_number,
MPI_INT,
total_matches,
match_numbers,
displacements,
MPI_INT, MASTER,
MPI_COMM_WORLD
);
if (rank == MASTER) {
free(match_numbers);
free(displacements);
}
}