KMP-MPI/main.c

223 lines
6.5 KiB
C
Raw Normal View History

2021-03-15 20:04:23 +00:00
#include <stdio.h>
#include <string.h>
#include "kmp.h"
#include "util.h"
2021-03-18 16:47:32 +00:00
#include <mpi.h>
#include <malloc.h>
2021-03-15 20:04:23 +00:00
2021-03-18 16:47:32 +00:00
#define MASTER 0
#define DEFAULT_TAG 17
void find_end(int, char *, char *, int **, int *);
void apply_shift(int, int *, int);
int sum_array(int *, int);
2021-03-15 20:04:23 +00:00
2021-03-21 11:33:22 +00:00
void initialize();
2021-03-21 13:06:28 +00:00
void distribute_text();
2021-03-21 11:33:22 +00:00
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;
2021-03-21 13:06:28 +00:00
char *private_text;
2021-03-21 11:33:22 +00:00
2021-03-15 20:04:23 +00:00
int main() {
2021-03-19 17:05:38 +00:00
int *match_numbers;
2021-03-19 17:50:59 +00:00
int *total_matches;
int total_match_number;
2021-03-18 16:47:32 +00:00
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
2021-03-21 11:33:22 +00:00
if (rank == MASTER)
initialize();
2021-03-18 16:47:32 +00:00
2021-03-21 13:06:28 +00:00
distribute_text();
2021-03-18 16:47:32 +00:00
2021-03-21 13:01:03 +00:00
// sending the remain to the last trial
// this is necessary for the calculation of the offset
2021-03-19 17:50:59 +00:00
if (rank == MASTER)
MPI_Send(&remain, 1, MPI_INT, size - 1, DEFAULT_TAG, MPI_COMM_WORLD);
2021-03-21 13:01:03 +00:00
else if (rank == size - 1)
2021-03-19 17:50:59 +00:00
MPI_Recv(&remain, 1, MPI_INT, MASTER, DEFAULT_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
2021-03-18 16:47:32 +00:00
printf("%d -> input: %s\n", rank, private_text);
2021-03-21 11:33:22 +00:00
printf("%d -> text len: %d\n", rank, private_text_len);
2021-03-18 16:47:32 +00:00
2021-03-21 13:01:03 +00:00
// distribution of the length of the pattern to each process
2021-03-18 16:47:32 +00:00
MPI_Bcast(&pattern_len, 1, MPI_INT, MASTER, MPI_COMM_WORLD);
2021-03-21 13:01:03 +00:00
// allocation of space for the pattern
// the master has already done so previously
2021-03-18 16:47:32 +00:00
if (rank != MASTER) {
pattern = (char *) malloc(sizeof(char) * (pattern_len + 1));
}
2021-03-21 13:01:03 +00:00
// distribution of the pattern to each process
2021-03-18 16:47:32 +00:00
MPI_Bcast(pattern, pattern_len + 1, MPI_CHAR, MASTER, MPI_COMM_WORLD);
2021-03-15 20:04:23 +00:00
2021-03-21 13:01:03 +00:00
// create and build lps array
2021-03-15 20:04:23 +00:00
int lps[pattern_len];
2021-03-18 16:47:32 +00:00
create_lps(pattern, pattern_len, lps);
int match_number = 0, residue;
2021-03-21 13:01:03 +00:00
// search for matches
2021-03-18 16:47:32 +00:00
int *matches = search_pattern(private_text, pattern, lps, &match_number, &residue);
2021-03-21 13:01:03 +00:00
// send the residue to the next process
2021-03-18 16:47:32 +00:00
if (rank + 1 != size) {
MPI_Send(&residue, 1, MPI_INT, rank + 1, DEFAULT_TAG, MPI_COMM_WORLD);
}
2021-03-21 13:01:03 +00:00
// receiving the residue from the previous process
2021-03-18 16:47:32 +00:00
if (rank != 0) {
MPI_Recv(&residue, 1, MPI_INT, rank - 1, DEFAULT_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
if (residue != 0)
2021-03-21 13:01:03 +00:00
// search for a split match
2021-03-18 16:47:32 +00:00
find_end(residue, pattern, private_text, &matches, &match_number);
}
2021-03-21 13:01:03 +00:00
// 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
2021-03-18 16:47:32 +00:00
apply_shift(shift, matches, match_number);
printf("%d -> result number: %d\n", rank, match_number);
2021-03-15 20:04:23 +00:00
2021-03-18 16:47:32 +00:00
if (rank == MASTER) {
2021-03-21 13:01:03 +00:00
// allocation for the array containing the number of matches of each process
2021-03-19 17:05:38 +00:00
match_numbers = (int *) malloc(sizeof(int) * size);
}
2021-03-18 16:47:32 +00:00
2021-03-21 13:01:03 +00:00
// collection of the number of matches from each process
2021-03-19 17:05:38 +00:00
MPI_Gather(&match_number, 1, MPI_INT, match_numbers, 1, MPI_INT, MASTER, MPI_COMM_WORLD);
2021-03-18 16:47:32 +00:00
2021-03-19 17:05:38 +00:00
if (rank == MASTER) {
2021-03-21 13:01:03 +00:00
// preparation of the data structures needed to receive match indices from all processes
2021-03-19 17:50:59 +00:00
total_match_number = sum_array(match_numbers, size);
total_matches = (int *) malloc(sizeof(int) * total_match_number);
2021-03-21 13:01:03 +00:00
2021-03-19 17:50:59 +00:00
displacements[0] = 0;
for (int i = 0; i < size - 1; ++i) {
displacements[i + 1] = displacements[i] + match_numbers[i];
2021-03-18 16:47:32 +00:00
}
}
2021-03-21 13:01:03 +00:00
// 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
);
2021-03-19 17:50:59 +00:00
2021-03-18 16:47:32 +00:00
MPI_Finalize();
if (rank == MASTER) {
2021-03-19 17:50:59 +00:00
printf("total matches: %d\n", total_match_number);
2021-03-18 16:47:32 +00:00
printf("matches index: ");
2021-03-19 17:50:59 +00:00
print_array(total_matches, total_match_number);
2021-03-18 16:47:32 +00:00
}
}
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);
2021-03-19 16:56:57 +00:00
// TODO: match splitted on 3+ node
2021-03-18 16:47:32 +00:00
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;
}
2021-03-21 11:33:22 +00:00
void initialize() {
2021-03-21 13:01:03 +00:00
text = "testo di esempio mamma altra mamma esempio prova mammamma esempio mamma";//read_file("data/text.txt", &text_len);
2021-03-21 11:33:22 +00:00
pattern = "mamma";//read_file("data/pattern.txt", &pattern_len);
text_len = strlen(text);
pattern_len = strlen(pattern);
printf("text: %s\n", text);
printf("pattern: %s\n", pattern);
private_text_len = text_len / size;
remain = text_len % size;
if (pattern_len > private_text_len)
MPI_Abort(MPI_COMM_WORLD, 1);
text_piece = (int *) malloc(sizeof(int) * size);
displacements = (int *) malloc(sizeof(int) * size);
displacements[0] = 0;
for (int i = 0; i < size - 1; ++i) {
text_piece[i] = private_text_len;
displacements[i + 1] = displacements[i] + private_text_len;
}
text_piece[size - 1] = private_text_len + remain;
}
2021-03-21 13:06:28 +00:00
void distribute_text() {
// distribution of the length of the text portion to each process
MPI_Scatter(text_piece, 1, MPI_INT, &private_text_len, 1, MPI_INT, MASTER, MPI_COMM_WORLD);
// allocation of space for text
private_text = (char *) malloc(sizeof(char) * (private_text_len + 1));
// distribution of the text portion to each process
// scatterv is necessary because the last process receives a larger portion of text in case it is not perfectly divisible.
MPI_Scatterv(
text,
text_piece,
displacements,
MPI_CHAR,
private_text,
private_text_len,
MPI_CHAR, MASTER,
MPI_COMM_WORLD
);
private_text[private_text_len] = '\0';
}
2021-03-18 16:47:32 +00:00
void apply_shift(int shift, int *array, int size) {
for (int i = 0; i < size; ++i) {
array[i] += shift;
}
}
2021-03-15 20:04:23 +00:00
2021-03-18 16:47:32 +00:00
int sum_array(int *array, int size) {
int sum = 0;
for (int i = 0; i < size; ++i) {
sum += array[i];
}
2021-03-15 20:04:23 +00:00
2021-03-18 16:47:32 +00:00
return sum;
2021-03-15 20:04:23 +00:00
}
2021-03-19 16:56:57 +00:00