МИНОБРНАУКИ РФ Федеральное государственное бюджетное образовательное учреждение высшего образования «Тульский государственный университет» Институт прикладной математики и компьютерных наук Кафедра вычислительной техники Отчёт по лабораторной работе №9 «Коллективные обмены в MPI» по дисциплине «Параллельное программирование» Вариант 2 Выполнил Ст. гр. 220682 Проверил Асс. Шмелев Г. С._____ Думчев Е. В.____ Тула 2021 ЗАДАНИЕ НА РАБОТУ Написать параллельную программу для вычисления максимального и минимального значений среди элементов матрицы A – 400 x 300, заполненной случайными числами. Определите зависимость коэффициента ускорения от числа процессоров. ПРОГРАММНАЯ РЕАЛИЗАЦИЯ #include "matrix.hpp" #include <mpi.h> #include <iostream> #include <random> #include <chrono> #define rows 400 #define cols 300 class Timer { private: using clock_t = std::chrono::high_resolution_clock; using second_t = std::chrono::duration<double, std::ratio<1> >; std::chrono::time_point<clock_t> m_beg; public: Timer() {} void start() { m_beg = clock_t::now(); } void reset() { m_beg = clock_t::now(); } double elapsed() const { return std::chrono::duration_cast<second_t>(clock_t::now() - m_beg).count(); } }; class Random { public: Random() { std::random_device device; random_generator_.seed(device()); } double returnRandom(double max) { std::uniform_real_distribution<double> range(0.0, max); return range(random_generator_); } 2 private: std::mt19937 random_generator_; }; int main(int argc, char** argv) { Random rnd; simple_matrix::matrix matrix{ rows, cols }; int rank, size; MPI_Status status; MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &rank); // определение ранга процесса MPI_Comm_size(MPI_COMM_WORLD, &size); // определение размера области взаимодействия if (rank == 0) { for (auto i = 0; i < rows; ++i) for (auto j = 0; j < cols; ++j) matrix.set(i, j, rnd.returnRandom(100)); } if (rank == 0) { Timer t; t.start(); auto minmax = std::minmax_element(matrix.begin(), matrix.end()); std::cout << "min = " << *minmax.first << "; max = " << *minmax.second << "; time = " << t.elapsed() << std::endl; } int numberInThread = ((rows * cols) % size == 0 ? rows * cols / size : rows * cols / size + 1); double* partOfMatrix = new double[numberInThread]; Timer t; if (rank == 0) t.start(); MPI_Scatter(matrix.inner_matrix(), numberInThread, MPI_DOUBLE, partOfMatrix, numberInThread, MPI_DOUBLE, 0, MPI_COMM_WORLD); double res[2]; res[0] = *(std::min_element(partOfMatrix, partOfMatrix + numberInThread)); res[1] = *(std::max_element(partOfMatrix, partOfMatrix + numberInThread)); delete[] partOfMatrix; double* sub_res = nullptr; if (rank == 0) sub_res = new double[size * 2]; MPI_Gather(res, 2, MPI_DOUBLE, sub_res, 2, MPI_DOUBLE, 0, MPI_COMM_WORLD); if (rank == 0) { auto minmax = std::minmax_element(sub_res, sub_res + size * 2); std::cout << "min = " << *minmax.first << "; max = " << *minmax.second << "; time = " << t.elapsed() << "; size = " << size << std::endl; delete[] sub_res; } MPI_Finalize(); return 0; } 3 ТЕСТИРОВАНИЕ В верхней строке вывода представлено время нахождения минимальных и максимальных элементов в однопоточном режиме. В нижней строке – в многопоточном. На рисунках 1-4 представлены рельтаты выполнения программы для 1, 2, 4 и 6 потоков соответственно. Рисунок 1 – Результат работы для 1 потока Рисунок 2 – Результат работы для 2 потоков Рисунок 3 – Результат работы для 4 потоков Рисунок 4 – Результат работы для 4 потоков В результате получим следующий график зависимости времени выполнения от количества потоков (рисунок 5). На него также были добавлены параметры времени выполнения для 12 и 36 потоков. Проще всего данную зависимость можно описать при помощи гиперболической регресии при аппроксимации функции. 𝑦 = 0.0007 + 4 0.0009 𝑥 Рисунок 5 – Зависимость времени выполнения от количества потоков 5