Shipilov_Nikita_lab_2

This commit is contained in:
2025-03-21 18:40:34 +04:00
parent c3d5ac3ba2
commit b0acc56e51
4 changed files with 226 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
import mpi.*;
public class MPIMatrix {
public static void main(String[] args) {
MPI.Init(args);
int rank = MPI.COMM_WORLD.Rank();
int size = MPI.COMM_WORLD.Size();
if (size != 2) {
if (rank == 0) {
System.out.println("This program requires 2 processes.");
}
MPI.Finalize();
return;
}
int n = 1000;
double[][] matrix = null;
double[] localMaxArr = new double[1];
double[] globalMaxArr = new double[1];
double startTime = System.nanoTime();
int rowsPerProcess = n / 2;
double[][] localMatrix = new double[rowsPerProcess][n];
if (rank == 0) {
matrix = new double[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
matrix[i][j] = Math.random() * 100;
}
}
for (int i = 0; i < rowsPerProcess; i++) {
System.arraycopy(matrix[i], 0, localMatrix[i], 0, n);
}
double[] sendBuffer = new double[rowsPerProcess * n];
for (int i = 0; i < rowsPerProcess; i++) {
System.arraycopy(matrix[i + rowsPerProcess], 0, sendBuffer, i * n, n);
}
MPI.COMM_WORLD.Send(sendBuffer, 0, sendBuffer.length, MPI.DOUBLE, 1, 0);
} else {
double[] recvBuffer = new double[rowsPerProcess * n];
MPI.COMM_WORLD.Recv(recvBuffer, 0, recvBuffer.length, MPI.DOUBLE, 0, 0);
for (int i = 0; i < rowsPerProcess; i++) {
System.arraycopy(recvBuffer, i * n, localMatrix[i], 0, n);
}
}
double localMax = 0;
for (int i = 0; i < rowsPerProcess; i++) {
for (int j = 0; j < n; j++) {
if (localMatrix[i][j] > localMax) {
localMax = localMatrix[i][j];
}
}
}
localMaxArr[0] = localMax;
MPI.COMM_WORLD.Reduce(localMaxArr, 0, globalMaxArr, 0, 1, MPI.DOUBLE, MPI.MAX, 0);
double globalMax = globalMaxArr[0];
double[] globalMaxBroadcast = new double[1];
if (rank == 0) {
globalMaxBroadcast[0] = globalMax;
}
MPI.COMM_WORLD.Bcast(globalMaxBroadcast, 0, 1, MPI.DOUBLE, 0);
globalMax = globalMaxBroadcast[0];
for (int i = 0; i < rowsPerProcess; i++) {
for (int j = 0; j < n; j++) {
localMatrix[i][j] /= globalMax;
}
}
if (rank == 0) {
for (int i = 0; i < rowsPerProcess; i++) {
System.arraycopy(localMatrix[i], 0, matrix[i], 0, n);
}
double[] recvBuffer = new double[rowsPerProcess * n];
MPI.COMM_WORLD.Recv(recvBuffer, 0, recvBuffer.length, MPI.DOUBLE, 1, 1);
for (int i = 0; i < rowsPerProcess; i++) {
System.arraycopy(recvBuffer, i * n, matrix[i + rowsPerProcess], 0, n);
}
double endTime = System.nanoTime();
System.out.printf("Process %d finished at %.1f ms\n", rank, (endTime - startTime) / 1_000_000.0);
} else {
double[] sendBuffer = new double[rowsPerProcess * n];
for (int i = 0; i < rowsPerProcess; i++) {
System.arraycopy(localMatrix[i], 0, sendBuffer, i * n, n);
}
MPI.COMM_WORLD.Send(sendBuffer, 0, sendBuffer.length, MPI.DOUBLE, 0, 1);
double endTime = System.nanoTime();
System.out.printf("Process %d finished at %.1f ms\n", rank, (endTime - startTime) / 1_000_000.0);
}
MPI.Finalize();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@@ -0,0 +1,2 @@
CT128
CT129

View File

@@ -0,0 +1,125 @@
# Лабораторная работа №2
Разработка параллельного MPI приложения на языке Java.
### Необходимо:
- Разработать параллельный вариант алгоритма с применением MPI и
замерить время его работы.
<i>В рамках работы программы должно быть две копии приложения, которые соединяются друг с другом по сети. Сообщения о статусе соединения (например, что соединение установлено) должны выводиться в консоль.</i>
<strong>Вариант задания 1: Разделить элементы матрицы на наибольший элемент.</strong>
### Как запустить лабораторную работу:
`javac -cp $MPJ_HOME/lib/mpj.jar MPIMatrix.java` компилирует исходный код (делаем на обоих контейнерах)
`mpjrun.sh -np 2 -dev niodev -machinesfile machines MPIMatrix` команда запускает скомпилированный класс (делаем на контейнере CT128)
### Какие технологии использовали:
- Java - язык программирования.
- MPJ Express - библиотека для реализации параллельных вычислений.
- MPI - интерфейс для передачи сообщений между процессами.
### Как работает программа:
1. Инициализация MPI:
- MPI.Init(args); - инициализация среды выполнения MPI.
- MPI.COMM_WORLD.Rank(); - определение ранга текущего процесса.
- MPI.COMM_WORLD.Size(); - получение общего количества процессов.
2. Генерация матрицы:
- Процесс с rank == 0 создает матрицу n x n, заполняя её случайными значениями от 0 до 100.
- Затем первая половина матрицы остается у процесса 0, а вторая половина отправляется процессу 1 с помощью MPI.Send().
- Процесс 1 принимает данные через MPI.Recv().
3. Поиск максимального элемента:
- Каждый процесс находит локальный максимум в своей части матрицы.
- С помощью MPI.Reduce() вычисляется глобальный максимум и передается процессу 0.
- Затем MPI.Bcast() рассылает его всем процессам.
4. Нормализация матрицы:
- Каждый элемент матрицы делится на найденный глобальный максимум.
5. Сбор данных обратно:
- Процесс 1 отправляет свою нормализованную часть обратно процессу 0.
- Процесс 0 собирает итоговую матрицу и измеряет время выполнения.
### (Размер матрицы 1000х1000)
```bash
Starting process <0> on <CT128>
Starting process <1> on <CT129>
Maximum: 99.99984736376186
Process 1 finished at 170.9 ms
Process 0 finished at 179.2 ms
Stopping Process <0> on <CT128>
Stopping Process <1> on <CT129>
```
### (Размер матрицы 2000х2000)
```bash
Starting process <1> on <CT129>
Starting process <0> on <CT128>
Maximum: 99.99998909285488
Process 1 finished at 347.8 ms
Process 0 finished at 359.3 ms
Stopping Process <0> on <CT128>
Stopping Process <1> on <CT129>
```
### (Размер матрицы 3000x3000)
```bash
Starting process <0> on <CT128>
Starting process <1> on <CT129>
Maximum: 99.99999045962504
Process 1 finished at 753.4 ms
Process 0 finished at 762.8 ms
Stopping Process <0> on <CT128>
Stopping Process <1> on <CT129>
```
### (Размер матрицы 4000x4000)
```bash
Starting process <1> on <CT129>
Starting process <0> on <CT128>
Maximum: 99.99998218458676
Process 1 finished at 1376.1 ms
Process 0 finished at 1398.0 ms
Stopping Process <0> on <CT128>
Stopping Process <1> on <CT129>
```
<img src="./diagram.png">
### Выводы по временным замерам:
- Время выполнения растет примерно квадратично с увеличением размера матрицы.
- Разница во времени между процессами 0 и 1 минимальна, что говорит о равномерном распределении нагрузки.
- Задержка в работе процесса 0 связана с дополнительными затратами на генерацию матрицы и сбор результатов.
- MPI позволяет эффективно разделить вычисления, но обмен данными (Send/Recv) вносит небольшие накладные расходы.
### Вывод:
MPI позволяет значительно ускорить обработку больших массивов данных, особенно при распределении вычислений между несколькими узлами. Однако эффективность зависит от баланса вычислений и передачи данных. В данной работе удалось добиться почти линейного ускорения по сравнению с последовательным исполнением.