— метод решения линейной системы (обращения матрицы), с которым вы работали в предыдущем семестре, необходимо адаптировать для исполнения в системах с распределённой памятью с использованием стандарта MPI (о нём — чуть позже).
Требования по ускорению такие же, как и для версии на Pthreads.
Добавляется дополнительное требование на пересылки данных между процессами: не более O(n) пересылок, объём каждой — не более O(n). Про пересылки — тоже чуть позже.
Матрица должна быть распределена между процессами. Если процессов больше одного, ни один процесс не должен выделять память под всю матрицу (или под всю обратную). Использование памяти для P процессов должно быть \(n^2/P + O(n)\) для решения линейной системы и \(2n^2/P + O(n)\) для обращения матрицы.
— реализация двух методов и графического интерфейса к ним (на основе заготовки).

— реализация двух методов (или одного — метода конечных элементов) и графического интерфейса к ним (на основе той же заготовки).

— по тому же принципу, что и в предыдущем семестре.
Современные суперкомпьютеры выглядят приблизительно так:

На фотографии на предыдущем слайде — IBM Blue Gene/P. Он составлен из 72 стоек. В каждой стойке — 16 блейд-серверов, на каждом сервере — несколько процессоров, у каждого из которых — 8 или больше ядер.
Ядра одного процессора имеют быстрый доступ к одному блоку памяти.
Несколько процессоров образуют NUMA-узел — в несколько раз более медленный доступ к участкам памяти, которые принадлежат другим процессорам, но с точки зрения программиста это можно назвать общей памятью (могут работать, например, программы использующие pthreads).
NUMA-узлы связаны интерконнектом. Интерконнект можно считать высокоскоростной сетью — но прямого доступа к памяти соседнего узла интерконнект не предоставляет.
На машинах с распределённой памятью части программы, работающие на разных узлах, передают данные с использованием обмена сообщениями.
На настоящее время стандартом для разработки программ для машин с распределённой памятью является MPI, дословно — «интерфейс передачи сообщений».
pthread_create создаёт несколько потоков с заданными аргументами и управляет их выполнением.Для работы с MPI во все файлы с исходным кодом, в которых используются функции или типы данных MPI, должен быть включён заголовочный файл mpi.h:
#include <mpi.h>Для компиляции используются обёртки над gcc и g++ — mpicc и mpicxx соответственно. Вместо ld можно использовать mpicc. Командная строка для компиляции отличается от той, которую вы использовали ранее, только тем, что вместо gcc используется mpicc и т.п., все ключи сохраняют своё значение.
gcc -g -lm
mpicc -g -lm myprog.c -o myprog
gcc -O3 myprog.c
mpicc -O3 myprog.cЗапуск осуществляется с использованием команды mpirun:
mpirun -np количество_процессов имя_программы аргументы_программынапример:
mpirun -np 4 ./a.out --formula 2 -n 2000Аргументы --formula 2 и -n 2000 передаются в вашу программу (./a.out), аргумент -np 4 не передаётся.
В начале программы, работающей с MPI, необходимо инициализировать библиотеку MPI с помощью функции MPI_Init; перед завершением — вызвать функцию завершения MPI_Finalize.
int MPI_Init(int *argc, char*** argv);
int MPI_Finalize();Аргументы argc и argv функции MPI_Init должны быть указателями на соответствующие аргументы функции main, см. пример далее. Функция MPI_Finalize не содержит аргументов.
Количество запущенных процессов не должно передаваться в программу в качестве отдельного аргумента командной строки, но определяется с использованием функций MPI_Comm_size. Номер, который автоматически присваивается процессу, может быть получен с помощью функции MPI_Comm_rank. Пример: при запуске p процессов, в каждом из результат выполнения MPI_Comm_size равен p, а результат выполнения MPI_Comm_rank — числам от 0 до p-1. Нулевой процесс обычно для простоты считают «главным» и выполняют из него весь ввод-вывод (при разработке допускается использовать отладочный printf-вывод во всех процессах).
int MPI_Comm_rank(MPI_Comm comm, int *rank);
int MPI_Comm_size(MPI_Comm comm, int *total_procs);Далее под «номером процесса» будем понимать число, которое возвращает в переменной rank вызов функции MPI_Comm_rank.
#include <mpi.h>
#include <stdio.h>
int main(int argc, char **argv) {
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
printf("Process #%d of %d\n", rank, size);
MPI_Finalize();
return 0;
}