Shipilov_Nikita_lab_2
This commit is contained in:
99
shipilov_nikita_lab_2/MPIMatrix.java
Normal file
99
shipilov_nikita_lab_2/MPIMatrix.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
shipilov_nikita_lab_2/diagram.png
Normal file
BIN
shipilov_nikita_lab_2/diagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
2
shipilov_nikita_lab_2/machines
Normal file
2
shipilov_nikita_lab_2/machines
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
CT128
|
||||||
|
CT129
|
||||||
125
shipilov_nikita_lab_2/readme.md
Normal file
125
shipilov_nikita_lab_2/readme.md
Normal 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 позволяет значительно ускорить обработку больших массивов данных, особенно при распределении вычислений между несколькими узлами. Однако эффективность зависит от баланса вычислений и передачи данных. В данной работе удалось добиться почти линейного ускорения по сравнению с последовательным исполнением.
|
||||||
Reference in New Issue
Block a user