MPI-программа работает очень медленно, в чем может быть причина?

Пытаюсь запустить программу, реализующую параллельное выполнение алгоритма Флойда, но почему-то если задаю количество вершин больше чем 300, то программа начинает выполняться очень медленно или не выполняться вовсе. С чем это связано и как это исправить?

#include <algorithm>
#include <fstream>
#include <iostream>
 
#include "mpi.h"
 
#define ROOT_PROC 0
 
using namespace std;
 
void printMatrix(int *matrix, int numberOfVert) {
  for (int i = 0; i < numberOfVert; i++) {
    for (int j = 0; j < numberOfVert; j++) {
      cout << matrix[i * numberOfVert + j] << " ";
    }
    cout << endl;
  }
}
 
int main(int argc, char **argv) {
  srand(time(NULL));
  MPI_Init(&argc, &argv);
 
  int rank, size;
  double t, Time = 0.0;
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
 
  int numberOfVert;
  MPI_Request request;
  MPI_Status status;
 
  Time = MPI_Wtime();
  if (rank == ROOT_PROC) {
    numberOfVert = 1000;
    int *matrix;
 
    matrix = new int[numberOfVert * numberOfVert];
    for (int i = 0; i < numberOfVert; i++) {
      for (int j = 0; j < numberOfVert; j++) {
        matrix[i * numberOfVert + j] = rand() % 100;
      }
    }
    // cout << "Root process. Number of vertex sent to other processes" << endl;
    //  Раздать процессам количество вершин
    MPI_Bcast(&numberOfVert, 1, MPI_INT, ROOT_PROC, MPI_COMM_WORLD);
 
    // cout << "Root process. Print first matrix:" << endl;
    // printMatrix(matrix, numberOfVert);
 
    // Раздать каждому процессу нужно количество строк матрицы
 
    // Вычислить по сколько строк отдать каждому процессу
    int workSize = size - 1; //(руту не отдаем)
    int *rowCounts = (int *)malloc(sizeof(int) * workSize);
 
    for (int i = 0; i < workSize - 1; i++) {
      rowCounts[i] = numberOfVert / workSize;
    }
    // Если поровну делится то последнему столько же
    if (numberOfVert % workSize == 0) {
      rowCounts[workSize - 1] = numberOfVert / workSize;
    }
    // Если не поровну, то в последний скидываем остатки
    else {
      rowCounts[workSize - 1] =
          numberOfVert - ((numberOfVert / workSize) * (workSize - 1));
    }
 
    // cout << "Root process. Row counts sent to other processes" << endl;
    //  Сказать каждому процессу сколько ему ждать строк
    for (int i = 1; i < size; i++) {
      MPI_Send(&rowCounts[i - 1], 1, MPI_INT, i, 0, MPI_COMM_WORLD);
    }
 
    // cout << "Root process. Main loop start" << endl;
    //  Основной цикл алгоритма Флойда
    for (int k = 0; k < numberOfVert; k++) {
      // Раздаем k-ую строку всем процессам(кроме рута)
      for (int p = 1; p < size; p++) {
        MPI_Isend(&matrix[k * numberOfVert], numberOfVert, MPI_INT, p, 0,
                  MPI_COMM_WORLD, &request);
      }
 
      // Отдать каждому процессу его строки матрицы
      int num = 0;                         // Номер строки
      for (int i = 0; i < workSize; i++) { // Бежим по массиву с кол-вом строк
        for (int j = 0; j < rowCounts[i];
             j++) { // Отдаем нужное количество строк
          MPI_Isend(&matrix[num * numberOfVert], numberOfVert, MPI_INT, i + 1,
                    0, MPI_COMM_WORLD, &request);
          num++;
        }
      }
 
      // Получаем от процессов строки, измененные на этой итерации
      num = 0;                             // Номер строки
      for (int i = 0; i < workSize; i++) { // Бежим по массиву с кол-вом строк
        for (int j = 0; j < rowCounts[i];
             j++) { // Принимаем нужное количество строк
          MPI_Recv(&matrix[num * numberOfVert], numberOfVert, MPI_INT, i + 1, 0,
                   MPI_COMM_WORLD, &status);
          num++;
        }
      }
    }
 
    // cout << "Root process. Print final matrix:" << endl;
    // printMatrix(matrix, numberOfVert);
 
    free(matrix);
  } else {
    // Получить количество вершин
    MPI_Bcast(&numberOfVert, 1, MPI_INT, ROOT_PROC, MPI_COMM_WORLD);
 
    // Получить количество строк, которые нужно будет изменить
    int rowCount;
    MPI_Recv(&rowCount, 1, MPI_INT, ROOT_PROC, 0, MPI_COMM_WORLD, &status);
    // cout << rank << " : " << rowCount << endl;
 
    // Выделить память
    int *kRow = (int *)malloc(sizeof(int) * numberOfVert);
    int *rows = (int *)malloc(sizeof(int) * (rowCount * numberOfVert));
 
    // Основной цикл алгоритма Флойда
    for (int k = 0; k < numberOfVert; k++) {
      // Получить k-ю строку
      MPI_Recv(kRow, numberOfVert, MPI_INT, ROOT_PROC, 0, MPI_COMM_WORLD,
               &status);
 
      // Получить свои строки из матрицы
      for (int i = 0; i < rowCount; i++) {
        MPI_Recv(&rows[i * numberOfVert], numberOfVert, MPI_INT, ROOT_PROC, 0,
                 MPI_COMM_WORLD, &status);
      }
 
      // Изменить нужные строки в матрице(параллельная работа)
      for (int i = 0; i < rowCount; i++) {
        for (int j = 0; j < numberOfVert; j++) {
          rows[i * numberOfVert + j] = min(
              rows[i * numberOfVert + j], rows[i * numberOfVert + k] + kRow[j]);
        }
      }
 
      // Отправить изменения руту
      for (int i = 0; i < rowCount; i++) {
        MPI_Send(&rows[i * numberOfVert], numberOfVert, MPI_INT, ROOT_PROC, 0,
                 MPI_COMM_WORLD);
      }
    }
    MPI_Reduce(&t, &Time, 1, MPI_DOUBLE, MPI_MAX, ROOT_PROC, MPI_COMM_WORLD);
    free(kRow);
    free(rows);
  }
 
  if (rank == ROOT_PROC) {
    Time = MPI_Wtime() - Time;
    std::cout << "Время выполнения параллельной версии программы: " << Time
              << std::endl;
  }
  MPI_Finalize();
  return 0;
}

Ответы (0 шт):